【问题标题】:Detect if application: didReceiveRemoteNotification: fetchCompletionHandler: was called by tapping on a notification in Notification Center检测应用程序:didReceiveRemoteNotification:fetchCompletionHandler:是否通过点击通知中心的通知被调用
【发布时间】:2014-06-03 19:16:07
【问题描述】:
application: didReceiveRemoteNotification: fetchCompletionHandler:

不同于

application: didReceiveRemoteNotification:

怎么样?来自文档:

与 application:didReceiveRemoteNotification: 方法不同,它是 仅在您的应用程序运行时调用,系统调用此方法 无论您的应用程序的状态如何。如果您的应用程序被暂停 运行时,系统唤醒或启动您的应用程序并将其放入 调用方法前的后台运行状态。 如果用户打开 您的应用程序从系统显示的警报中,系统调用此方法 以便您知道用户选择了哪个通知。

我的挣扎是:我想知道该方法是由用户从通知中心点击系统显示的警报还是从唤醒设备的静默推送通知调用的。目前,据我所知,没有明显的区分方法。

- (BOOL)application: didFinishLaunchingWithOptions:

在上述方法中跟踪 launchOptions 不是解决方案,因为它仅在应用程序暂停/未在后台运行时调用。如果它在后台运行,则不会被调用。

【问题讨论】:

    标签: ios cocoa-touch apple-push-notifications uiapplicationdelegate


    【解决方案1】:

    Apple 文档有点混乱

    application: didReceiveRemoteNotification: fetchCompletionHandler:  
    

    如果您的应用程序支持远程通知后台模式(即您正在执行 BackgroundFetch),则使用。

    application: didReceiveRemoteNotification:  
    

    当操作系统接收到 RemoteNotification 并且应用程序正在运行(在后台/挂起或在前台)时调用。
    您可以检查 UIApplicationState 以查看应用程序是由用户带到前台(点击通知)还是在通知到来时已经在运行。

    - (void) application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {
          UIApplicationState state = [application applicationState];
            // user tapped notification while app was in background
        if (state == UIApplicationStateInactive || state == UIApplicationStateBackground) {
             // go to screen relevant to Notification content
        } else {
             // App is in UIApplicationStateActive (running in foreground)
             // perhaps show an UIAlertView
        }
    }
    

    【讨论】:

    • 我不在乎application: didReceiveRemoteNotification:,而是在乎application: didReceiveRemoteNotification: fetchCompletionHandler:
    • 所以你在做后台抓取?我想我对混乱在哪里感到困惑。 Apple 文档状态(如果您的应用程序支持 remote-notification 后台模式)>无论您的应用程序处于何种状态,系统都会调用此方法。文档还声明 >如果用户从系统显示的警报中打开您的应用程序,系统会再次调用此方法,以便您知道用户选择了哪个通知。我会假设跟踪 UIApplicationState 仍然适用......
    • @hasan83 - 如果我包含 NSString * jsCallBack = [NSString stringWithFormat:@"testfromdelegate()"]; 会发生什么[self.viewController.webView stringByEvaluatingJavaScriptFromString:jsCallBack]; inside if (state == UIApplicationStateInactive || state == UIApplicationStateBackground) { // 转到与通知内容相关的屏幕 } 在这两种情况下,我都希望 JSCallback 会被执行。真的吗?请告诉我。
    • 理论上是这样。但是,如果通知从 InActive 状态启动应用程序(关闭)。这意味着你没有你的参考。到 self.viewController 在您的应用程序委托中初始化。明白了吗?或者我应该解释更多吗?
    • 我不知道这是 iOS 10 的问题还是什么,但 -application: didReceiveRemoteNotification: 从未 被触发,即使应用程序在前台运行(我做过但是,在主屏幕中获取横幅)。我切换到 application: didReceiveRemoteNotification: fetchCompletionHandler: 并且它工作正常......我正在使用基于 CloudKit 订阅的通知。
    【解决方案2】:

    您可以检查UIApplicationapplicationState 以区分静默呼叫和用户正在使用的应用程序进行的呼叫:

    typedef enum : NSInteger {
       UIApplicationStateActive,
       UIApplicationStateInactive,
       UIApplicationStateBackground
    } UIApplicationState;
    

    或者在delegateapplicationDidEnterBackground: 上设置自己的标志。

    【讨论】:

    • 重要一点:Active=收到通知时应用已打开,Inactive=用户点击通知,Background=收到通知时应用正在后台运行(内容可用必须为真;这种情况是实际的后台获取)。请注意,应用程序必须至少在后台运行。如果你强制关闭应用程序,didReceiveRemoteNotification 不会被调用。
    • 当您启用在应用运行时显示通知时,您将无法在 iOS 10+ 中执行此操作。 stackoverflow.com/questions/23168345/…
    【解决方案3】:

    应用程序状态不可靠,因为如果您在应用程序上打开了控制中心或 Apple 的通知中心,应用程序:didReceiveRemoteNotification: fetchCompletionHandler: 将被调用并且应用程序状态将为非活动。

    当应用程序在后台时,我在尝试响应点击通知时遇到了同样的问题,而且似乎没有可靠的方法来单独识别这一点。

    【讨论】:

      【解决方案4】:

      在快速的情况下

      func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject]) {
      
          let state : UIApplicationState = application.applicationState
          if (state == .Inactive || state == .Background) {
              // go to screen relevant to Notification content
          } else {
              // App is in UIApplicationStateActive (running in foreground)
          }
      }
      

      【讨论】:

      • 这不是问题所在。问题是如何识别这个方法是被系统调用的还是被用户点击通知的动作调用的。
      【解决方案5】:

      application: didReceiveRemoteNotification:fetchCompletionHandler:方法被调用时,应用状态是UIApplicationStateInactive如果用户点击警报(在这种情况下你想准备一些UI)并且当应用被静默唤醒时是UIApplicationStateBackground(在这种情况下你只是加载一些数据)。

      【讨论】:

      • 在 iOS 10+ 的情况下,可以在应用打开时显示通知。在这种情况下,系统和用户点击都会调用application:didReceiveRemoteNotification:fetchCompletionHandler:,并且两者都会有application.applicationState == .active,这是一个问题。
      【解决方案6】:

      在 iOS 10.0+ 中可以使用该方法

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

      检测用户何时从通知中心点击系统显示的警报。

      如果你实现了上面的方法

      • - (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult result))completionHandler; 将在收到通知时被调用
      • 用户点击通知时将调用- (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)(void))completionHandler;

      【讨论】:

        【解决方案7】:

        我不确定我是否理解你的问题。

        您想区分静默推送通知后台获取和嘈杂推送通知吗?您可以简单地检查推送通知字典是否包含“内容可用”键:[[userInfo objectForKey:@"aps"] objectForKey:@"content-available"] 如果包含,则应该是静默推送。如果不是,那是正常的推送。

        您想知道当应用程序收到通知并且它处于挂起/未运行状态时是否调用了该后台 fetch 方法?如果是这样,您可以执行以下操作:

        • Download and import LumberJacks into your app. 查看说明并了解如何进行设置,以便将日志保存到磁盘。
        • 将它放在任何你想查看是否/何时调用该方法的方法中:

          • DDLogDebug(@"%@ - %@",NSStringFromSelector(_cmd),NSStringFromClass([self class]));

          这会将类和方法打印到日志文件中。

        • 在向启用了后台提取的应用发送推送通知后检查日志文件,并通过查看日志文件查看是否调用了任何方法。

        如果您已正确设置应用程序以进行后台提取,则即使在应用程序处于后台/未运行状态时,如果您收到推送通知(无论是否静默推送),都会调用方法 application: didReceiveRemoteNotification: fetchCompletionHandler:

        【讨论】:

          【解决方案8】:

          对于 Swift:在 application(_:didFinishLaunchingWithOptions:) 中解析应用程序选项。如果它们存在,您就知道应用是通过它们点击启动的。

            if let remoteNotif = launchOptions?[UIApplicationLaunchOptionsKey.remoteNotification] as? [String: Any] {
                  print("Remote notfi is \(remoteNotif)")
                  if let notification = remoteNotif["aps"] as? [AnyHashable : Any] {
                  /// - parse notification
                }
            }
          

          否则,你可以处理tap in,你就知道应用是open/background/inactiveapplication(_:didReceiveRemoteNotification:fetchCompletionHandler:)

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2014-12-22
            • 2018-01-17
            • 1970-01-01
            • 1970-01-01
            • 2015-11-10
            • 1970-01-01
            • 2018-01-27
            相关资源
            最近更新 更多