APNs证书更改后,FCM无法发送推送通知

16

在我某个证书过期之前,我没有遇到从 FCM 发送推送通知到我的 iOS 应用程序的任何问题。更换证书后,FCM 不再传递消息。我阅读了这篇文章 (https://firebase.googleblog.com/2017/01/debugging-firebase-cloud-messaging-on.html),并按照以下验证步骤进行了尝试,但现在却束手无策...

  • 注释掉任何 connectToFCM 函数
  • 下载 Pusher 并成功使用 APNs 证书向设备发送通知
  • 成功地通过 curl 调用 FCM (下面是响应)
    • {"multicast_id":7774794018682407760,"success":1,"failure":0,"canonical_ids":0,"results":[{"message_id":"0:1493321644068397%b76e8527b76e8527"}]}
  • 尝试重新创建开发和生产证书
  • 尝试带密码和不带密码从钥匙串中导出它们

有没有谁对这个极其令人沮丧的事情有经验,并且有关于如何继续的建议?

值得注意的是,我无法移除 APNs 证书,虽然我看到了这个选项,但它是灰色的,我无法选择它。


你把新证书上传到 Firebase 了吗? - washloops
是的,我已经上传了多个版本,试图让它工作。 - Jake Lisby
解决方案:我重新安装了应用程序,然后它就可以工作了。 - TIMEX
3个回答

3

这有助于理解流程。

enter image description here
图片来自Firebase博客

你已经测试了APN发送到应用程序。因此证书没有问题。

从你提供的博客中可以看出,通过进行curl调用获得成功响应仅意味着消息被FCM接收。这并不意味着该消息已经传递到APNs。

使用Firebase通知面板直接发送一条消息,以查看FCM是否与APNs通信。

如果这个方法有效,则存在消息格式的问题。

如果失败,请确保:

  1. 将消息优先级设置为high,以便立即发送。

  2. "content_available": true

  3. 卸载并重新安装应用程序

  4. 检查服务器代码。


2
请在您的项目设置中更新APNs证书(生产和开发),路径为YourProjectSetting=>cloudmessaging=>iOS应用程序配置。Firebase Cloud Messaging可以使用APNs身份验证密钥或APNs证书与APNs连接。

注意: 确认您的项目凭据(SenderID、Legacy server key、Server key)。

HTTP POST请求:用于发送通知。

https://fcm.googleapis.com/fcm/send
Content-Type:application/json
Authorization:key=AIzaSyZ-1u......7Udno5aA
{
    "registration_ids": ["regId1","regId2"],
    "data": {
        "title": "App Name",
        "message": "Hello this is for testing",
        "body": "Hello this is for testing"

    },
    "content-available": true,
    "priority": "high",
    "notification": {
        "title": "App Name",
        "message": "Hello this is for testing",
        "body": "Hello this is for testing"
    }
}

请在你的AppDelegate.swift文件中添加以下代码。
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
            self.fcmInitialSetup(application)
            return true
        }
        func fcmInitialSetup(_ application: UIApplication){

            // [START register_for_notifications]
            if #available(iOS 10.0, *) {
                let uns: UIUserNotificationSettings = UIUserNotificationSettings(types: [.alert, .badge, .sound], categories: nil)
                application.registerUserNotificationSettings(uns)
                application.registerForRemoteNotifications()

            } else {
                let settings: UIUserNotificationSettings =
                    UIUserNotificationSettings(types: [.alert, .badge, .sound], categories: nil)
                application.registerUserNotificationSettings(settings)
            }

            application.registerForRemoteNotifications()

            // [END register_for_notifications]

            FIRApp.configure()

            // Add observer for InstanceID token refresh callback.
            NotificationCenter.default.addObserver(self, selector: #selector(self.tokenRefreshNotification), name: NSNotification.Name.firInstanceIDTokenRefresh, object: nil)

            if let token = FIRInstanceID.instanceID().token() {
                sendTokenToServer(token)
            }
        }

        func sendTokenToServer(_ currentToken: String) {
            print("sendTokenToServer() Token: \(currentToken)")
            // Send token to server ONLY IF NECESSARY

            print("InstanceID token: \(currentToken)")
            self.token = currentToken
            UserDefaults.standard.set(self.token, forKey: "token")
            UserDefaults.standard.synchronize()
            if self.token != nil{
                let userInfo = ["token": self.token]
                NotificationCenter.default.post(
                    name: Notification.Name(rawValue: self.rkey), object: nil, userInfo: userInfo)
            }
        }


        // NOTE: Need to use this when swizzling is disabled
        func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
            let tokenChars = (deviceToken as NSData).bytes.bindMemory(to: CChar.self, capacity: deviceToken.count)
            var tokenString = ""

            for i in 0..<deviceToken.count {
                tokenString += String(format: "%02.2hhx", arguments: [tokenChars[i]])
            }

            FIRInstanceID.instanceID().setAPNSToken(deviceToken, type: FIRInstanceIDAPNSTokenType.unknown)
            print("Device Token:", tokenString)
            print("FIRInstanceID.instanceID().token() Token:", FIRInstanceID.instanceID().token())
            if let tokenData = FIRInstanceID.instanceID().token(){
                UserDefaults.standard.set(tokenData, forKey: "token")
                UserDefaults.standard.synchronize()
                let userInfo = ["token": tokenData]
            }
        }

        func tokenRefreshNotification(_ notification: Notification) {
            // NOTE: It can be nil here
            //        print("Token:\(FIRInstanceID.instanceID().token()!)")
            if let refreshedToken = FIRInstanceID.instanceID().token() {
                print("InstanceID token: \(refreshedToken)")
                UserDefaults.standard.set(refreshedToken, forKey: "token")
                UserDefaults.standard.synchronize()
                print("update now \(self.token)")
                if self.token != nil{
                    let userInfo = ["token": self.token]
                    NotificationCenter.default.post(
                        name: Notification.Name(rawValue: self.rkey), object: nil, userInfo: userInfo)
                }

            }

            // Connect to FCM since connection may have failed when attempted before having a token.
            connectToFcm()
        }
        // [END refresh_token]
        func connectToFcm() {
            FIRMessaging.messaging().connect { (error) in
                if (error != nil) {
                    print("Unable to connect with FCM. \(error)")
                } else {
                    print("Connected to FCM.")
                }
            }
        }

        func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any]) {
            print(userInfo)
        }

        func application(_ application: UIApplication, open url: URL, sourceApplication: String?, annotation: Any) -> Bool {
            print("Within open URL")
            return true
        }


        // [START receive_apns_token_error]
        func application( _ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError
            error: Error ) {
            print("Registration for remote notification failed with error: \(error.localizedDescription)")
            // [END receive_apns_token_error]
            let userInfo = ["error": error.localizedDescription]
            NotificationCenter.default.post(
                name: Notification.Name(rawValue: rkey), object: nil, userInfo: userInfo)
        }

        func registrationHandler(_ token: String!, error: NSError!) {
            if (token != nil) {
                self.token = token!
                print("Registration Token: \(self.token)")
                UserDefaults.standard.set(self.token, forKey: "token")
                UserDefaults.standard.synchronize()
                let userInfo = ["token": self.token]
                NotificationCenter.default.post(
                    name: Notification.Name(rawValue: self.rkey), object: nil, userInfo: userInfo)
            } else {
                print("Registration to GCM failed with error: \(error.localizedDescription)")
                let userInfo = ["error": error.localizedDescription]
                NotificationCenter.default.post(
                    name: Notification.Name(rawValue: self.rkey), object: nil, userInfo: userInfo)
            }
        }

        func registerForPushNotifications(_ application: UIApplication) {
            let notificationSettings = UIUserNotificationSettings(
                types: [.badge, .sound, .alert], categories: nil)
            application.registerUserNotificationSettings(notificationSettings)
        }

        func application(_ application: UIApplication, didRegister notificationSettings: UIUserNotificationSettings) {
            if notificationSettings.types != UIUserNotificationType() {
                application.registerForRemoteNotifications()
            }
        }

        // [START receive_message]
        func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any],
                         fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
            // If you are receiving a notification message while your app is in the background,
            // this callback will not be fired till the user taps on the notification launching the application.
            // TODO: Handle data of notification

            // Print message ID. add Toast
            print(userInfo);

            print(application.keyWindow?.visibleViewController() ?? "")

            print("Message ID: \(userInfo["gcm.message_id"]!)")


            // Print full message.
            print("%@", userInfo)
        }
        // [END receive_message]



        func applicationDidBecomeActive(_ application: UIApplication) {
            connectToFcm()
        }

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

        func application(_ application: UIApplication, performFetchWithCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {

        }

        // [END disconnect_from_fcm]


// [START ios_10_message_handling]
@available(iOS 10, *)
extension AppDelegate : UNUserNotificationCenterDelegate {

    // Receive displayed notifications for iOS 10 devices.
    func userNotificationCenter(_ center: UNUserNotificationCenter,
                                willPresent notification: UNNotification,
                                                        withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
        let userInfo = notification.request.content.userInfo
        // Print message ID.
        print("Message ID: \(userInfo["gcm.message_id"]!)")
        // Print message ID. add Toast

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

extension AppDelegate : FIRMessagingDelegate {
    // Receive data message on iOS 10 devices.
    func applicationReceivedRemoteMessage(_ remoteMessage: FIRMessagingRemoteMessage) {
        print("%@", remoteMessage.appData)
    }
}

// [END ios_10_message_handling]

参考资料: https://firebase.google.com/docs/cloud-messaging/ios/device-group 希望这可以帮到你。

1

不必为每个应用程序创建APNS证书,您可以创建一个APNs密钥并将其用于所有应用程序。

APNs 使用Apple推送通知服务来处理通知请求。一个密钥用于您的所有应用程序。有关更多信息,请参阅本地和远程通知编程指南。

即使FCM也支持此功能。现在您可以避免为每个应用程序创建APNS证书的麻烦。


请参考此链接:https://firebase.google.com/docs/cloud-messaging/ios/certs - KavyaKavita

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