iOS推送通知:当应用程序在后台运行时,如何检测用户是否轻按了通知?


116

关于此主题有很多stackoverflow线程,但是我仍然没有找到一个好的解决方案。

如果该应用程序不在后台,则可以签launchOptions[UIApplicationLaunchOptionsRemoteNotificationKey]application:didFinishLaunchingWithOptions:呼叫以查看是否已从通知中打开该应用程序。

如果应用程序在后台运行,则所有帖子都建议使用application:didReceiveRemoteNotification:并检查应用程序状态。但是,正如我进行的实验(以及该API的名称所暗示的那样),该方法在收到通知时被调用,而不是被窃听。

因此,问题是,如果启动了应用程序,然后又将其后台运行,并且您知道收到了通知application:didReceiveNotification(此时application:didFinishLaunchWithOptions:将不会触发),那么您如何知道用户是否通过轻按通知或仅轻按应用程序图标?因为如果用户点击通知,则期望打开该通知中提到的页面。否则不应该。

我可以使用handleActionWithIdentifier自定义操作通知,但是只有在点击自定义操作按钮时才会触发,而不是在用户点击通知主体时触发。

谢谢。

编辑:

在阅读下面的一个答案之后,我想通过这种方式可以澄清我的问题:

我们如何区分这两种情况:

(A)1.app进入后台;2.收到通知;3.用户点击通知;4.应用进入前台

(B)1.app进入后台;2.收到通知;3.用户忽略该通知,稍后点击应用程序图标;4.应用进入前台

application:didReceiveRemoteNotification:在两种情况下都在步骤2中触发了因为。

或者,应该application:didReceiveRemoteNotification:仅在步骤3中为(A)触发,但是我以某种方式配置了我的应用程序错误,因此我在步骤2中看到了它?


对您的有效负载使用自定义词典值,并采取相应的措施。很简单
2015年

@soulshined有效负载中的字典可以代表用户是否点击了通知,对吗?例如,您的朋友A发布了文章B,您可以在有效负载中说出{user:A,article:B},而应用程序在后台,您会得到didReceiveRemoteNotification。您如何知道应用恢复运行的时间,是否应该显示文章?
鲍磊

2
@soulshined我确实阅读了文档,并且确实对didReceiveRemoteNotification做了什么进行了自我教育。你真的读过我的问题吗?根据Apple的官方文档didReceiveRemoteNotification“告诉代表正在运行的应用程序收到远程通知”。我在问什么是告诉用户是否轻按通知的好方法。您所指的SO链接适用于从头开始启动应用程序的情况,我问的是应用程序在后台运行的情况。
鲍磊


1
@soulshined好吧,也许我没有说清楚。我的意思是,如果该应用程序完全退出,而不是在后台退出,则yesFinishLaunching将被调用。但是,如果您启动应用程序,然后使该应用程序后台运行,现在会收到一条通知,并且用户点击该通知,现在将不再调用didFinishLaunching。而是将调用applicationWillEnterForeground和applicationDidBecomeActive。您如何分辨该应用进入前台,因为用户点击了通知或应用图标?
鲍磊

Answers:


102

好吧,我终于想通了。

在目标设置➝功能选项卡➝后台模式中,如果选中“远程通知”,application:didReceiveRemoteNotification:则在通知到达时(只要应用程序在后台)就会被触发,在这种情况下,无法判断是否用户将点击通知。

如果您取消选中该框,application:didReceiveRemoteNotification:则只有在您点击通知时才会被触发。

选中此框将更改应用程序委托方法之一的行为,这有点奇怪。如果选中该框会更好,Apple使用两种不同的委托方法进行通知接收和通知点击。我认为大多数开发人员总是想知道是否使用了通知。

希望这对遇到此问题的其他人有所帮助。苹果在这里也没有清楚地记录下来所以花了我一段时间才弄清楚。

在此处输入图片说明


6
我已将后台模式完全设置为“关闭”,但在后台模式下应用程序收到通知时仍会收到通知。
Gottfried

5
大!这对我有帮助。可惜我需要关闭远程通知。我想在推送通知到达时预取数据并检测用户点击。我找不到实现此目的的方法。
Peter Fennema

1
我将“后台”模式设置为“开”模式,并启用了远程通知。仍然无法检测到通知事件。
kalim sayyad 2015年

1
我有一个同样的问题,后台模式设置为“ ON”并启用了远程通知,但是当通知以后台模式到达应用程序时,仍未收到通知
Swapnil Dhotre

@Bao-我认为这会导致Appstore遭到拒绝,因为此选项主要用于在后台下载与通知相关的内容。因此,如果您不下载任何内容,Apple可能会拒绝您的应用程序。developer.apple.com/library/ios/documentation/iPhone/Conceptual/...
NIKS

69

我一直在寻找与您相同的东西,但实际上找到了不需要取消远程通知的解决方案。

要检查用户是否点击了该应用程序,或者应用程序处于后台或处于活动状态,您只需要检查应用程序中的状态即可

-(void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler{

    if(application.applicationState == UIApplicationStateActive) {

        //app is currently active, can update badges count here

    }else if(application.applicationState == UIApplicationStateBackground){

        //app is in background, if content-available key of your notification is set to 1, poll to your backend to retrieve data and update your interface here

    }else if(application.applicationState == UIApplicationStateInactive){

        //app is transitioning from background to foreground (user taps notification), do what you need when user taps here

    }

有关更多信息,请检查:

UIKit框架参考> UIApplication类参考> UIApplicationState


10
当应用程序在屏幕上时,如果用户与通知中心(从顶部滑动)或控制中心(从底部滑动)互动,则该应用程序处于UIApplicationStateInactive状态怎么办?显然,无法确定APNS是在非活动状态下接收还是用户实际点击了它。
科斯蒂亚·金

1
@KostiaKim你是对的,但是那是一个超级优势的案例...除此之外,就将前景中的应用程序之间分开...用户点击...背景中的应用程序而言,这个答案是最有效的
Honey

谢谢,这种揭开了一切的神秘面纱。请记住,为了在应用程序在后台运行时调用委托方法,推送通知必须包含content-available键,但是如官方文档中所述通知必须是静默的(即不包括声音或徽章)。
尼克

1
@KostiaKim我实际上能够解决这样的问题,即不知道控制中心是否已打开,或者用户是否通过添加一个在中设置为true且在中设置为func applicationDidEnterBackground(_ application: UIApplication)false 的布尔值来实际窃听通知,func applicationDidBecomeActive(_ application: UIApplication)这使我可以显示in app应用由于控制中心或通知列表而处于非活动状态时发出通知
DatForis

3
这让我感到困惑,为什么Apple不会显示其他事件,或者只是在元数据中添加一个标志以指示用户实际上与通知进行了交互。对于影响用户对应用程序行为的期望的关键信息,不得不“推断”用户是否基于有关应用程序状态的环境信息采取了行动。也许唯一要做的就是创建一个自定义操作以使用该信息打开应用程序?
艾伦·尼恩惠斯

20

根据 iOS / XCode:如何知道该应用程序是通过单击通知或跳板应用程序图标启动的? 您必须像下面这样在didReceiveLocalNotification中检查应用程序状态:

if ([UIApplication sharedApplication].applicationState == UIApplicationStateInactive)
{
    // user has tapped notification
}
else
{
    // user opened app from app icon
}

尽管这对我而言并不完全有意义,但它似乎有效。


1
在这种情况下将无法正常工作。我以前尝试过。选中该复选框(有关详细信息,请参见我接受的答案)后,通知到达时,即使用户没有点击通知(通知刚刚到达),也会输入带有注释的行“ //用户已点击通知” )。
鲍磊

3
我不同意。我在后台功能中签入了“远程通知”,它的工作方式与我的回答中所述相同。我也检查了“背景提取”。也许这会导致变化?
Werner Kratochwil 2015年

您能+1我的答案吗?;-)我仍然需要一些投票才能更多地参与stackoverflow。非常感谢
Werner Kratochwil 2015年

是的,这是解决方案。tnx。
阿夫申

请注意,如果在用户位于其他屏幕上时发送通知(例如,如果他们拉下状态栏然后从您的应用程序接收通知),这将是误报。
凯文·库珀

16

如果有人希望在Swift 3.0中

switch application.applicationState {
    case .active:
        //app is currently active, can update badges count here
        break
    case .inactive:
        //app is transitioning from background to foreground (user taps notification), do what you need when user taps here
        break
    case .background:
        //app is in background, if content-available key of your notification is set to 1, poll to your backend to retrieve data and update your interface here
        break
    default:
        break
    }

快速4

switch UIApplication.shared.applicationState {
case .active:
    //app is currently active, can update badges count here
    break
case .inactive:
    //app is transitioning from background to foreground (user taps notification), do what you need when user taps here
    break
case .background:
    //app is in background, if content-available key of your notification is set to 1, poll to your backend to retrieve data and update your interface here
    break
default:
    break
}

我们应该在哪个触发器上添加此代码,didReceiveRemoteNotification或didFinishLaunchingWithOptions?
Dashrath


@Hamid sh,我在所有状态下都收到推送通知,即当应用程序处于前景,背景,关闭(终止)时..!但是我的问题是,当应用程序处于后台状态并关闭(终止)状态时,如何增加徽章计数?请详细告诉我我该怎么做...。我的应用程序徽章计数仅在应用程序处于Forground状态时才增加.....?如果可能的话,请简单告诉我.....!
Kiran jadhav'7

8

如果您选中了“背景模式”>“远程通知” ==是,则点击通知事件将到达:

-(void)userNotificationCenter:(UNUserNotificationCenter *)center **didReceiveNotificationResponse**:(UNNotificationResponse *)response withCompletionHandler:(void(^)())completionHandler.

它帮助了我。请享受 :)


我看到Apple添加了此功能,但无法弄清楚如何以这种方式获取通知的自定义有效负载。
sudo

当应用程序处于后台状态并变为活动状态时,以及应用程序从
终止

@NikhilMuskur仅当启用“远程通知”是吗?
佐拉尔

@Zorayr是的,没错
Nikhil Muskur

8

我也遇到了这个问题-但是在带有新UserNotificationsFramework的iOS 11上。

对我来说就像这样:

  • 新产品发布: application:didFinishLaunchingWithOptions:
  • 从终止状态接收: application(_:didReceiveRemoteNotification:fetchCompletionHandler:)
  • 在前台收到: userNotificationCenter(_:willPresent:withCompletionHandler:)
  • 在后台收到: userNotificationCenter:didReceiveNotificationResponse:withCompletionHandler:

这是在iOS 11 +中实现的方法
OhadM

just‍♂️
Zorayr

4

就我而言,关闭后台模式没有任何区别。但是,当应用程序被挂起并且用户点击了通知时,我可以通过以下回调方法处理这种情况:

func userNotificationCenter(_ center: UNUserNotificationCenter,
                            didReceive response: UNNotificationResponse,
                            withCompletionHandler completionHandler: @escaping () -> Void) {

}

这是苹果公司所说的官方方式。根据Apple的文档,只要用户与推送通知UI进行交互,就会调用该文件。如果应用程序不在后台,它将在后台模式下启动应用程序并调用此方法。
瑞安

3

对于iOS 10及更高版本,请将其放在AppDelegate中,以了解是否已轻按通知(即使应用已关闭或打开也可以使用)

func userNotificationCenter(_ center: UNUserNotificationCenter,
                                didReceive response: UNNotificationResponse,
                                withCompletionHandler completionHandler: @escaping () -> Void) {
print("notification tapped here")
}

1
这是iOS 10+的正确答案。此处的另一个线程提供了完整说明:stackoverflow.com/a/41783666/1761357
dead_can_dance

2

PushNotificationManager类内部有两个用于处理PushNotification处理的Funcs :

class PushNotificationManager: NSObject, MessagingDelegate, UNUserNotificationCenterDelegate{

}

当通知到达时,我测试了第一个触发器

@available(iOS 10.0, *)
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {

    completionHandler(UNNotificationPresentationOptions.alert)

    //OnReceive Notification
    let userInfo = notification.request.content.userInfo
    for key in userInfo.keys {
         Constants.setPrint("\(key): \(userInfo[key])")
    }

    completionHandler([])

}

和第二个当点击通知:

@available(iOS 10.0, *)
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {

    //OnTap Notification
    let userInfo = response.notification.request.content.userInfo
    for key in userInfo.keys {
        Constants.setPrint("\(key): \(userInfo[key])")
    }

    completionHandler()
}

我还在远程通知的打开和关闭状态下对其进行了测试(在后台模式下)


1

SWIFT 5.1

UIApplication.State 不适用于我,因为一旦我在应用中读取了指纹(显示了模态),通知也会在上方栏中引发,用户必须单击它。

我已经建立

public static var isNotificationFromApp: Bool = false

AppDelegate,我true在开始时设置它,viewController然后在通知中storyboard/ viewController我只是检查一下:)

希望可以派上用场


-7

您可以配置推送通知的有效负载以调用应用程序委托的 application:didReceiveRemoteNotification:fetchCompletionHandler:为在后台运行应用程序时方法。您可以在此处设置一些标志,以便用户下次启动应用程序时可以执行操作。

从Apple的文档中,您应该使用此方法下载与推送通知关联的新内容。另外,要使此方法起作用,您必须启用“从后台模式进行远程通知”,并且您的推送通知有效负载必须包含content-available其值设置为1的密钥。有关更多信息,请参阅此处的使用推送通知从Apple doc启动下载部分。

另一种方法是在推送通知有效负载中记录徽章。因此,下次启动应用程序时,您可以检查应用程序徽章计数。如果大于零,请执行操作,并从服务器清零/清除徽章计数。

希望对您有帮助。


@bhusan您是否已阅读我的问题的详细信息?我看到通知刚到时(在用户点击通知之前),didReceiveRemoteNotification被调用。我想确定用户是否点击了它。
鲍磊

您没有回答OP的问题。他不只是想知道已有通知。他想知道用户是否通过点击该远程通知打开了该应用程序。
乔C
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.