didReceiveRemoteNotification无法在后台运行

时间:2015-07-16 09:28:57

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

我正在使用大量遗留代码处理大型应用。 目前 - 有一个实现:

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

问题是只有在应用程序处于前台或用户在应用程序处于后台时点击通知时才会调用它。 我试图实施:

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

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

6 个答案:

答案 0 :(得分:68)

实施didReceiveRemoteNotificationdidReceiveRemoteNotification:fetchCompletionHandler是正确的方法,但您还需要执行以下操作:

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

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

    return YES;
}

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

enter image description here

此外,您需要将"content-available":1添加到推送通知有效内容中,否则如果该应用位于后台,该应用将不会被唤醒(请参阅documentation here):

  

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

所以有效载荷至少应该是这样的:

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

答案 1 :(得分:13)

  1. 在app delegate中注册推送通知。
  2. 在应用功能中添加背景模式。
  3. 添加"内容可用" =" 1"发送推送通知时(如果您正在使用firebase替换"内容可用" =" 1"通过" content_available" =" true"同时从服务器端发送推送通知。)。

答案 2 :(得分:4)

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

func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject]) {

    self.application(application, didReceiveRemoteNotification: userInfo) { (UIBackgroundFetchResult) in

    }
}

答案 3 :(得分:0)

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

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

经过大量阅读以了解Apple APNS和iOS应用程序与APNS服务器之间的Firebase界面,并查看了无数关于stackoverflow和其他Web资源的帖子,我终于找到了如何使它满足我的要求。

从服务器发送Firebase云消息(FCM)通知消息时(或Fbase默认将Notification Not Data消息作为Firebase控制台发送),该消息会通过APNS传递并作为通知显示在iOS设备上。当用户点击通知横幅时,iOS将执行以下操作:如果该应用未运行/加载,则iOS启动该应用,如果该应用已加载/正在运行,但在后台,则iOS将其置于前台,或者如果该应用为在前台(所有三种情况下),然后通过func应用程序(_应用程序:UIApplication,didReceiveRemoteNotification userInfo:[AnyHashable:Any],fetchCompletionHandler completeHandler:(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

答案 4 :(得分:0)

我正在使用 iOS 14 并且从接受的 answer 开始我做了所有但什么都没做。我需要来自 userInfodidReceiveRemoteNotification 但它永远不会从 后台 被调用,即使我按下了实际的通知。我必须使用下面的方法,在该方法中我使用 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 的正确打印语句。

答案 5 :(得分:0)

我的设备状态不佳。虽然我已经完成了这里提到的所有先决条件,但我不得不重新启动设备才能使其工作。