Firebase云消息推送iOS:没有后台推送通知

17

通过方法混淆,我成功地使用更新的Firebase云消息传递,在我的应用委托中的didReceiveRemoteNotification方法中接收有效负载,当我的应用程序处于前台时。然而,尽管API响应消息已成功发送(见下文),但我在后台运行应用程序时没有接收到任何类型的有效负载并且didReceiveRemoteNotification未被调用。
以下是我向FCM API发送触发推送通知的请求:https://fcm.googleapis.com/fcm/send

{
"to": "{valid-registration-token}",
"priority":"high", //others suggested setting priority to high would fix, but did not
  "notification":{
      "body":"Body3",
      "title":"test"  
 } 
}
< p >< br >来自 FCM 的响应

{
      "multicast_id": 6616533575211076304,
      "success": 1,
      "failure": 0,
      "canonical_ids": 0,
      "results": [
        {
          "message_id": "0:1468906545447775%a4aa0efda4aa0efd"
        }
      ]
    }

这是我的appDelegate代码

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {

        Fabric.with([Crashlytics.self])
        FIRApp.configure()

        NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(self.tokenRefreshNotification),
                                                         name: kFIRInstanceIDTokenRefreshNotification, object: nil)
        return true
    }



    func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject], fetchCompletionHandler completionHandler: (UIBackgroundFetchResult) -> Void) {
        // Let FCM know about the message for analytics etc.
        FIRMessaging.messaging().appDidReceiveMessage(userInfo)

        // Print full message.
        print("%@", userInfo)

        // handle your message

//        let localNotification = UILocalNotification()
//        localNotification.fireDate = NSDate()
//        let notification = userInfo["notification"]!
//        localNotification.alertBody = notification["body"] as? String
//        localNotification.alertTitle = notification["title"] as? String
//        localNotification.timeZone = NSTimeZone()
//        application.scheduleLocalNotification(localNotification)

    }

    func tokenRefreshNotification(notification: NSNotification) {
        let refreshedToken = FIRInstanceID.instanceID().token()!
        print("InstanceID token: \(refreshedToken)")
        LoginVC.registerForPushNotifications()
        connectToFcm()
    }


    //foreground messages
    func applicationDidBecomeActive(application: UIApplication) {
        connectToFcm()
    }

    // [START disconnect_from_fcm]
    func applicationDidEnterBackground(application: UIApplication) {
        FIRMessaging.messaging().disconnect()
        print("Disconnected from FCM.")
    }


    func connectToFcm() {
        FIRMessaging.messaging().connectWithCompletion { (error) in
            if (error != nil) {
                print("Unable to connect with FCM. \(error)")
            } else {
                print("Connected to FCM.")
            }
        }
    }

}

我在我的应用程序的后续流程中调用此代码以请求权限

static func registerForPushNotifications() {
    let settings: UIUserNotificationSettings =
                UIUserNotificationSettings(forTypes: [.Alert, .Badge, .Sound], categories: nil)
            UIApplication.sharedApplication().registerUserNotificationSettings(settings)
            UIApplication.sharedApplication().registerForRemoteNotifications()
}

既然我能在应用程序前台收到通知,我就假设这可以消除我未上传apns证书或注册令牌不正确的所有担忧。如果不是这种情况,请评论并让我重新研究。我可能忽略了一些简单的东西,但是如何在应用程序处于后台时获取通知呢?谢谢。


今天我面临着类似的问题:当应用程序在前台时,AppDelegate中的处理程序被调用,但是当应用程序在后台时,没有托盘通知出现。很有趣,看看是否会有任何结果。如果我解决了这个问题,我会让你知道的。 - Kazimieras
你看过 Github 上的这个 问题 吗? - Kazimieras
当您的应用程序在前台时,您可以直接从FCM接收消息,而不是通过APNs(当您的应用程序在后台时使用的内容)。为确保APNs已正确配置,请通过实现didRegisterForRemoteNotificationsWithDeviceToken方法来确认您是否收到了APNs令牌。 - Arthur Thompson
@ArthurThompson 在这个版本的代码之前,我没有使用方法交换技术,并实现了didRegisterForeRemoteNotificationsWIthDeviceToken方法,在那里我能够获得一个令牌。起初我希望我已经完成了,但当这个令牌对于FCM无效时,我不得不重构代码。这回答了你的问题吗? - Daniel George
@Kazimieras 是的,我读完了整个内容。我尝试将优先级设置为高并将 content-available 设置为 true,但没有成功。我还尝试同时使用两者,但其他人说那样不起作用,在我的情况下也是如此。 - Daniel George
似乎APNs沙盒存在一些问题(https://forums.developer.apple.com/thread/52224),但现在已经解决了,您是否仍然遇到此问题? - Arthur Thompson
7个回答

12

显然,尽管使用了应该自动执行的方法交换技术,您仍然必须在Firebase实例上设置APNS令牌。因此,这意味着您还必须使用类似于以下内容的didRegisterForRemoteNotificationsWithDeviceToken方法:

func application(application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: NSData) {


        // set firebase apns token
        FIRInstanceID.instanceID().setAPNSToken(deviceToken, type: FIRInstanceIDAPNSTokenType.Unknown)
}
作为附注,使用"priority":"high"对测试很有用,因为它会立即发送通知。

我刚刚把所有东西都搞定了,然后进行了全新安装,现在FIRInstanceID.instanceID().token对象为nil,我无法使用错误代码501连接到Fcm。有什么想法吗? - Daniel George
对我来说关键是选择“未知”作为类型。之前我尝试过“沙盒”和“开发”,但无论哪种方式都不能正常工作。当进行干净的安装时,令牌对象为nil,但我通过守卫检查解决了这个问题,并且从我所看到的情况来看,令牌刷新通知被触发多次。 - Kazimieras
4
如果应用启用了方法交换,它会自动设置APNs令牌,因此无需实现didRegisterForRemoteNotificationsWithDeviceToken。请注意,尽管翻译的内容需要通俗易懂,但是我不能更改原始意思。 - Arthur Thompson
@ArthurThompson 那么,为什么我即使使用更新的版本,也不得不这样做来解决这个后台通知问题呢?事实上,谷歌关于Firebase的文档中有很多使用过时和不清晰方法的指南。 - llanfair

4
期望的行为,至少对于我的应用程序来说,是在推送通知到达时,在应用程序中显示PN(Push Notification)内容所在的期望页面。
我有三种不同的应用程序状态,其中PN可以到达: (当然这取决于您的实现,但您应该了解苹果如何处理这些状态)
(行为由苹果确定!)
1)应用程序在前台:
- PN已接收 - 弹出在通知中心(您可以单击或不单击 - 没关系) - 徽章将被更新 - PN在期望页面中可用
在这种情况下,应用程序始终处理PN
2)应用程序在后台:
- PN已接收 - 弹出在通知中心(您可以单击或不单击 - 没关系) - 徽章将被更新 - PN在期望页面中可用
在这种情况下,应用程序始终处理PN
3)应用程序被杀死/关闭:
- PN已接收 - 弹出在通知中心 - 现在有三种可能的方式 - 滑动通知 - >应用程序不会处理PN - 直接通过启动器图标打开应用程序 - >应用程序不会处理PN - 单击通知 - >应用程序将处理PN
对于这种情况,如果用户没有通过点击通知来打开应用程序,则无法获取通知数据。
为了独立于应用程序状态,您需要设置一个服务器,可以在其中请求特定数据。例如,您有一个视图显示所有通知,则需要API来请求特定数据。您不应在Pushnotification的接收方法中处理数据。
希望这能帮助某些人!

2

请确保在JSON负载中添加了 "content_available" : true,否则您将无法在后台模式下收到推送通知。

"notification" : {
            "body" : "this is body",
            "title" : "this is title"
}
"content_available" : true

1
与Daniel George的解决方案类似,我也可以通过以下方式解决我的问题:
Messaging.messaging().apnsToken = deviceToken

FirebaseInstanceID 2.0.8,FirebaseMessaging 2.0.8


设备令牌(deviceToken)是什么?我们如何找到它? - C Morell
这里有可用的代码: func application(application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) 您可以在此处找到相关信息:https://firebase.google.com/docs/cloud-messaging/ios/client 这是Firebase用于识别您设备的令牌。 - Colibri

0

我一直在苦苦思索为什么我的iOS14通知无法正常发送。Firebase文档中没有提到这一点。

在2020年12月的iOS14上,我可以确认@Daniel George的解决方案仍然有效,并且修复了我的通知未能正常发送的问题。以下是更新后的语法。

func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) { Messaging.messaging().apnsToken = deviceToken }

iOS14.1、Swift 5.3、Firebase和Firebase Cloud Messaging截至2020年12月18日均已更新。


0
从 FCM 获取成功令牌后,请按照以下步骤启用使用 FCM 的后台有效载荷数据提取:
  1. 打开项目导航器> AppCapabilities > 背景模式 > 检查远程通知

  2. 在App.delegate中定义:

    func application(_ application: UIApplication,didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
    
        print("userinfo in background mode on-\(userInfo)")
    
        completionHandler(UIBackgroundFetchResult.newData)
    }
    
  3. 根据苹果的指南正确格式化您的有效负载: enter link description here

  4. 不要忘记添加键值对: {"content-available":1} 否则您将无法在后台获取有效负载。

现在尝试使用 FCM 令牌再次发送通知。祝您编程愉快


-4
据我所知,对于iOS,您将无法在应用程序处于后台或已关闭状态下使用FCM发送推送通知消息。

Firebase推送通知


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接