【问题标题】:didReceiveRemoteNotification not working in the backgrounddidReceiveRemoteNotification 在后台不起作用
【发布时间】:2015-10-05 16:11:03
【问题描述】:

我正在开发一个包含大量遗留代码的大型应用程序。 目前 - 有一个实现:

- (void) application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo

问题在于,它仅在应用程序处于前台或用户在应用程序处于后台时点击通知时才会调用。 我尝试实现:

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

但应用程序的行为相同。 在任何情况下 - 当应用程序在后台时不会调用此方法。 可能是什么问题?

【问题讨论】:

  • app在后台时不会调用该方法是正常的。系统将通过提示视图或横幅的方式通知您。
  • 您设备的 iOS 版本是多少?至少是7个?因为fetchCompletionHandler: 需要最低 iOS 7。

标签: ios xcode push-notification xcode6 apple-push-notifications


【解决方案1】:

实现didReceiveRemoteNotificationdidReceiveRemoteNotification:fetchCompletionHandler是正确的方式,但还需要做到以下几点:

请务必注册远程通知,请参阅documentation here

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{    
    [[UIApplication sharedApplication] registerForRemoteNotificationTypes:(UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound)];

    return YES;
}

还要确保编辑 Info.plist 并选中“启用后台模式”和“远程通知”复选框:

此外,您需要将"content-available":1 添加到您的推送通知负载中,否则应用程序在后台不会被唤醒(请参阅documentation here 更新):

对于触发下载操作的推送通知, 通知的有效负载必须包含内容可用密钥及其 值设置为 1。当该键存在时,系统会唤醒应用程序 后台(或将其启动到后台)并调用应用程序 代表的 应用程序:didReceiveRemoteNotification:fetchCompletionHandler: 方法。您对该方法的实现应该下载 相关内容并将其集成到您的应用中

所以payload至少应该是这样的:

{
    aps = {
        "content-available" : 1,
        sound : ""
    };
}

【讨论】:

  • 我已经在调用 registerForRemoteNotificationTypes 并且启用了远程通知
  • @godmoney 查看我的更新答案,您需要将"content-available":"1" 添加到您的通知负载中...
  • @BarisAkar 太好了。我不知道content-available 有效载荷。 +1
  • 我已启用远程通知的后台模式,并且有效负载应包含 content-available:1 键值对但不调用我的后台方法
  • iOS 14 也出现了同样的问题。didReceiveRemoteNotification 方法在应用程序处于后台时永远不会被调用(不是强制关闭)。对此有何建议?我遵循了确切的程序并在 aps 中添加了 "content-available" : 1。 didReceiveRemoteNotification 只会在前台调用。
【解决方案2】:
  1. 在应用委托中注册推送通知。
  2. 在应用功能中添加后台模式。
  3. 在发送推送通知时添加“content-available”=“1”(如果您使用 firebase,在从服务器端发送推送通知时将“content-available”=“1”替换为“content_available”=“true” )。

【讨论】:

    【解决方案3】:

    我遇到了同样的问题。出现通知横幅,但未调用 -application:didReceiveRemoteNotification:fetchCompletionHandler: 方法。对我来说有效的解决方案是添加 - application:didReceiveRemoteNotification: 方法的实现并将调用转发到 -application:didReceiveRemoteNotification:fetchCompletionHandler::

    func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject]) {
    
        self.application(application, didReceiveRemoteNotification: userInfo) { (UIBackgroundFetchResult) in
    
        }
    }
    

    【讨论】:

    • 嗨,ZaEem,你找到解决办法了吗
    • 当app为后台时,只发送远程推送通知此方法称为func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject])
    • @UsmanNisar 我已经为我的问题添加了解决方法,它对我来说工作正常。它不适合你吗?
    【解决方案4】:

    我正在创建一个 iOS 项目,该项目将使用 Firebase 云消息传递 (FCM) 将自定义数据元素通过 Firebase/APNS 通知从公司服务器发送到 iOS 设备。

    我首先要了解的是,与 Android 不同,没有类似类型的“服务”能够捕获和保存我发送的信息,无论应用程序是否在前台(活动),背景(仍在内存中)或未激活(不在内存中)。因此,我必须使用通知消息而不是像我为 Android 设计的数据消息。

    经过大量阅读以了解 Apple APNS 以及 iOS 应用程序和 APNS 服务器之间的 Firebase 接口,查看了关于 stackoverflow 和其他网络资源的无数帖子,我终于弄清楚了如何让它满足我的要求。

    当从服务器(或 Firebase 控制台,因为 FCM 默认为 Notification NOT Data 消息)发送 Firebase 云消息传递 (FCM) 通知消息时,它会通过 APNS 传递并在 iOS 设备上作为通知呈现。当用户点击通知横幅时,iOS 会执行以下操作:如果应用程序未运行/加载 iOS 启动应用程序,如果应用程序已加载/运行但在后台 iOS 将应用程序带到前台或者如果应用程序是在前台(所有三种情况),然后通过 func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: (UIBackgroundFetchResult) -> Void) {} 传递消息内容。

    可以肯定的是,您必须启用后台模式并检查远程通知,您不必在有效负载中包含 {"content-available" : 1}。

    1) 完成 APNS 和 Firebase 设置,非常简单,生成和注册证书等。

    2)在appDelegate,didFinishLaunchingWithOptions中,添加:

            Messaging.messaging().delegate = self as? MessagingDelegate
    
            if #available(iOS 10.0, *) {
    
                UNUserNotificationCenter.current().delegate = self
    
                let authOptions: UNAuthorizationOptions = [.alert, .badge, .sound]
    
                UNUserNotificationCenter.current().requestAuthorization(
                    options: authOptions,
                    completionHandler: {_, _ in })
            }
            else {
    
                let settings: UIUserNotificationSettings =
                    UIUserNotificationSettings(types: [.alert, .badge, .sound], categories: nil)
    
                application.registerUserNotificationSettings(settings)
            }
    
            application.registerForRemoteNotifications()
    
    

    3) 然后将这些回调函数添加到appDelegate:

        func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: (UIBackgroundFetchResult) -> Void) {
    
            // Print message ID.
            if let messageID = userInfo["gcm.message_id"] {
    
                print("\n*** application - didReceiveRemoteNotification - fetchCompletionHandler - Message ID: \(messageID)")
            }
    
            // Print full message.
            print("\n*** application - didReceiveRemoteNotification - full message - fetchCompletionHandler, userInfo: \(userInfo)")
    
            myNotificationService?.processMessage(title: userInfo["Title"] as! String
                , text: userInfo["Text"] as! String, completion: { (success) in
    
                    if success {
                        completionHandler(.newData)
                    }
                    else {
                        completionHandler(.noData)
                    }
            })
        }
    
        func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
    
            completionHandler([.alert, .badge, .sound])
        }
    

    很有帮助:

    https://developer.apple.com/library/archive/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/CreatingtheNotificationPayload.html

    https://firebase.googleblog.com/2017/01/debugging-firebase-cloud-messaging-on.html

    【讨论】:

      【解决方案5】:

      我的设备状态不佳。尽管我已经完成了此处提到的所有先决条件,但我必须重新启动设备才能使其正常工作。

      【讨论】:

        【解决方案6】:

        我正在使用iOS 14,我从接受的answer 做了所有事情,但什么也没做。我需要来自didReceiveRemoteNotificationuserInfo,但即使我按下实际通知,它也永远不会从背景 中调用。我必须使用下面的方法,在该方法中我使用UIApplication.shared.applicationState 来检查后台状态。我从那里得到userInfo

        // called when notification is tapped
        func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
        
            let userInfo = response.notification.request.content.userInfo
        
            if let dict = userInfo as? [String: Any] {
        
                let state = UIApplication.shared.applicationState
                if state == .inactive || state == .background {
                        
                        print("app is in BACKGROUND - userInfo: ", dict) // do something with dict when app is in the background and user taps the notification
                        
                } else {
                        
                        print("app is in FOREGROUND - userInfo: ", dict) // do something with dict when app is in the foreground and user taps the notification
                }
            }
        
            completionHandler()
        }
        

        假设您已正确设置所有其他内容,当您在应用处于背景时点击通知时,您将获得带有userInfo 的正确打印语句。

        【讨论】:

          【解决方案7】:

          我通过在 appDelegate 中添加两种方法来解决此问题,一种用于点击,另一种用于前台:

          func application(_ application: UIApplication,
                           didReceiveRemoteNotification userInfo: [AnyHashable: Any],
                           fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult)
                           -> Void) {
              print(">>>NOTIF RECEIVED: ACTION:\(userInfo["action"] ?? "nil") DATA: \(userInfo["data"] ?? "nil")<<<")
              completionHandler(UIBackgroundFetchResult.newData)
          }
              
          func userNotificationCenter(_ center: UNUserNotificationCenter,
                                      didReceive response: UNNotificationResponse,
                                      withCompletionHandler completionHandler: @escaping () -> Void) {
              let userInfo = response.notification.request.content.userInfo
              print(">>>TAP NOTIF RECEIVED: ACTION:\(userInfo["action"] ?? "nil") DATA: \(userInfo["data"] ?? "nil")<<<")
              completionHandler()
          }
          

          重要的先决条件:

          • yourTarget/Signing&amp;Capabilities 中添加background modes 并检查remote notifications

          • 在 appDelegate/didfinishLaunchingWithOptions 中检查之前是否完成了初始化,如下所示:

              FirebaseApp.configure()
            
              UNUserNotificationCenter.current().delegate = self
              Messaging.messaging().delegate = self
              let authOptions: UNAuthorizationOptions = [.alert, .badge, .sound]
              UNUserNotificationCenter.current().requestAuthorization(
                  options: authOptions,
                  completionHandler: { _, _ in }
              )
            
              application.registerForRemoteNotifications()
            

          【讨论】:

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