【问题标题】:Push Notifications not working in Firebase 4.0推送通知在 Firebase 4.0 中不起作用
【发布时间】:2017-11-01 19:29:02
【问题描述】:

我今天将我的 pod 更新到了新的 Firebase 4.0。我浏览了建议的更改并从 Github 示例中获取了代码。老实说,我很茫然,我拿了 FCM 令牌并从 firebase 控制台发送了一条消息,但我什么也没得到。

我刷新,它说消息已发送,但我检查了控制台和设备,但那里什么也没有。我错过了什么?

这是我的应用程序代理:

//
//  Created by Erik Grosskurth on 4/24/17.
//

import UIKit
import FirebaseAnalytics
import FirebaseInstanceID
import FirebaseMessaging
import UserNotifications
import SystemConfiguration
import MobileCoreServices
import Quickblox
import QuickbloxWebRTC


let kQBApplicationID:UInt = 3545252534
let kQBAuthKey = "udfgsegsetrgsextr"
let kQBAuthSecret = "setbsetbsetbsetrbset"
let kQBAccountKey = "sbrtsbrtbsrtbsrtbrt"

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?
    let gcmMessageIDKey = "gcm.message_id"

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {

        // [START register_for_notifications]

        FirebaseApp.configure()

        Messaging.messaging().delegate = self

        if #available(iOS 10.0, *) {
            // For iOS 10 display notification (sent via APNS)
            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()

        if (Messaging.messaging().fcmToken != nil) {
            DataModel.sharedInstance.sessionInfo.FirebaseAccessToken = Messaging.messaging().fcmToken!
            print("FCM token: \(DataModel.sharedInstance.sessionInfo.FirebaseAccessToken)")
        }else {
            print("token was nil")
        }

        // [END register_for_notifications]

        //Quickblox config
        QBSettings.setApplicationID(kQBApplicationID)
        QBSettings.setAuthKey(kQBAuthKey)
        QBSettings.setAuthSecret(kQBAuthSecret)
        QBSettings.setAccountKey(kQBAccountKey)

        // Set settings for zone
        QBSettings.setApiEndpoint("https://api.quickblox.com", chatEndpoint: "chat.quickblox.com", forServiceZone: .production)
        // Activate zone
        QBSettings.setServiceZone(.production)

        QBSettings.setKeepAliveInterval(30)
        QBSettings.setAutoReconnectEnabled(true)
        QBRTCConfig.setStatsReportTimeInterval(1)
        QBRTCConfig.setDialingTimeInterval(5)
        QBRTCConfig.setAnswerTimeInterval(60)

        return true
    }

    // [START receive_message]
    func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any]) {

        Messaging.messaging().appDidReceiveMessage(userInfo)

        if let messageID = userInfo[gcmMessageIDKey] {
            print("Message ID: \(messageID)")
        }

        print(userInfo)

    }

    func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {

        Messaging.messaging().appDidReceiveMessage(userInfo)

        if let messageID = userInfo[gcmMessageIDKey] {
            print("Message ID: \(messageID)")
        }

        print(userInfo)

        completionHandler(UIBackgroundFetchResult.newData)

    }


    // when APNs has assigned the device a unique token
    func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {

        print("didRegisterForRemoteNotificationsWithDeviceToken()")

        Messaging.messaging().apnsToken = deviceToken

        //Messaging.messaging().setAPNSToken(deviceToken, type: MessagingAPNSTokenType.sandbox)
        //Messaging.messaging().setAPNSToken(deviceToken, type: MessagingAPNSTokenType.prod)
        //Messaging.messaging().setAPNSToken(deviceToken, type: MessagingAPNSTokenType.unknown)

        let deviceTokenString = deviceToken.reduce("", {$0 + String(format: "%02X", $1)})
        DataModel.sharedInstance.sessionInfo.APNSAccessToken = deviceTokenString
        print("APNS Access Token: \(deviceTokenString)")

    }


    // [END receive_message]
    func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
        print("Unable to register for remote notifications: \(error.localizedDescription)")
    }


    func applicationWillResignActive(_ application: UIApplication) {
        // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
        // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
    }

    func applicationDidEnterBackground(_ application: UIApplication) {
        QBChat.instance().disconnect { (error) in
            if error != nil {
                print("error: \(String(describing: error))")
            } else {
                print("success for applicationDidEnterBackground")
            }
        }
    }

    func applicationWillEnterForeground(_ application: UIApplication) {
        let qbUser = QBUUser()
        qbUser.id = DataModel.sharedInstance.qbLoginParams.id
        qbUser.password = DataModel.sharedInstance.sessionInfo.QBPassword
        QBChat.instance().connect(with: qbUser) { (error) in
            if error != nil {
                print("error: \(String(describing: error))")
            } else {
                print("success for applicationWillEnterForeground")
            }
        }
    }

    func applicationDidBecomeActive(_ application: UIApplication) {
        // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
    }

    func applicationWillTerminate(_ application: UIApplication) {
        QBChat.instance().disconnect { (error) in
            if error != nil {
                print("error: \(String(describing: error))")
            } else {
                print("success for applicationWillTerminate")
            }
        }
    }

    // LOCK IN PORTRAIT MODE
    func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
        return UIInterfaceOrientationMask(rawValue: UIInterfaceOrientationMask.portrait.rawValue)
    }

}

// [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

        // With swizzling disabled you must let Messaging know about the message, for Analytics
        Messaging.messaging().appDidReceiveMessage(userInfo)
        // Print message ID.
        if let messageID = userInfo[gcmMessageIDKey] {
            print("Message ID: \(messageID)")
        }

        // Print full message.
        print(userInfo)

        // Change this to your preferred presentation option
        completionHandler([])
    }

    func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
        let userInfo = response.notification.request.content.userInfo
        // Print message ID.
        if let messageID = userInfo[gcmMessageIDKey] {
            print("Message ID: \(messageID)")
        }

        // Print full message.
        print(userInfo)

        completionHandler()
    }
}
// [END ios_10_message_handling]

extension AppDelegate : MessagingDelegate {
    // [START refresh_token]
    func messaging(_ messaging: Messaging, didRefreshRegistrationToken fcmToken: String) {
        DataModel.sharedInstance.sessionInfo.FirebaseAccessToken = fcmToken
        print("Firebase registration token: \(fcmToken)")
    }
    // [END refresh_token]
    // [START ios_10_data_message]
    // Receive data messages on iOS 10+ directly from FCM (bypassing APNs) when the app is in the foreground.
    // To enable direct data messages, you can set Messaging.messaging().shouldEstablishDirectChannel to true.
    func messaging(_ messaging: Messaging, didReceive remoteMessage: MessagingRemoteMessage) {
        print("Received data message: \(remoteMessage.appData)")
    }
    // [END ios_10_data_message]
}

这里是日志:

2017-05-31 16:49:56.937067-0400 Telemed[1843:937699] [Firebase/Analytics][I-ACS003016] Firebase Analytics App Delegate Proxy is disabled. To log deep link campaigns manually, call the methods in FIRAnalytics+AppDelegate.h.
2017-05-31 16:49:56.937 Telemed[1843] <Warning> [Firebase/Analytics][I-ACS003016] Firebase Analytics App Delegate Proxy is disabled. To log deep link campaigns manually, call the methods in FIRAnalytics+AppDelegate.h.
2017-05-31 16:49:57.023568-0400 Telemed[1843:937706] [Firebase/Analytics][I-ACS005000] The AdSupport Framework is not currently linked. Some features will not function properly. Learn more at 
2017-05-31 16:49:57.023 Telemed[1843] <Warning> [Firebase/Analytics][I-ACS005000] The AdSupport Framework is not currently linked. Some features will not function properly. Learn more at 
2017-05-31 16:49:57.028454-0400 Telemed[1843:937697] [Firebase/Analytics][I-ACS023007] Firebase Analytics v.4000000 started
2017-05-31 16:49:57.028 Telemed[1843] <Notice> [Firebase/Analytics][I-ACS023007] Firebase Analytics v.4000000 started
2017-05-31 16:49:57.029042-0400 Telemed[1843:937697] [Firebase/Analytics][I-ACS023008] To enable debug logging set the following application argument: -FIRAnalyticsDebugEnabled (see )
2017-05-31 16:49:57.029 Telemed[1843] <Notice> [Firebase/Analytics][I-ACS023008] To enable debug logging set the following application argument: -FIRAnalyticsDebugEnabled (see )
FCM token: myTokenIsHere
2017-05-31 16:49:57.101756-0400 Telemed[1843:937699] [Firebase/Analytics][I-ACS032003] iAd framework is not linked. Search Ad Attribution Reporter is disabled.
2017-05-31 16:49:57.102 Telemed[1843] <Warning> [Firebase/Analytics][I-ACS032003] iAd framework is not linked. Search Ad Attribution Reporter is disabled.
2017-05-31 16:49:57.103700-0400 Telemed[1843:937697] [Firebase/Analytics][I-ACS023012] Firebase Analytics enabled
2017-05-31 16:49:57.103 Telemed[1843] <Notice> [Firebase/Analytics][I-ACS023012] Firebase Analytics enabled
Destroyed Session but Saved Login
2017-05-31 16:49:57.158678-0400 Telemed[1843:937637] [MC] System group container for systemgroup.com.apple.configurationprofiles path is /private/var/containers/Shared/SystemGroup/systemgroup.com.apple.configurationprofiles
2017-05-31 16:49:57.159102-0400 Telemed[1843:937637] [MC] Reading from public effective user settings.
didRegisterForRemoteNotificationsWithDeviceToken()
APNS Access Token: 091F01B...

>>>-----> **已解决

为了深入了解故障排除和最后的终极面部...请关注此主题: https://github.com/firebase/quickstart-ios/issues/290

特别感谢 THE RIZ 抽出时间解决问题!!

【问题讨论】:

  • 我假设您已将 APN 密钥上传到 Firebase 控制台并检查了设备上的应用设置以确保通知未被禁用?
  • 是的,但值得仔细检查,因为我在更新之前很久没有这样做了
  • 你不是我见过的(今天?)第一个遇到问题的人。可能想在这个问题上加星:stackoverflow.com/questions/44250823/…
  • LOL 有人只是语法 naziedited 我的问题。谢谢

标签: ios firebase swift3 push-notification firebase-cloud-messaging


【解决方案1】:

在 iOS 上正确设置 Firebase 云消息传递相当复杂,因为您必须确保 APNs 配置正常工作,然后在此基础上添加 FCM。

APNs 设置

Apple 的 APNs 身份验证密钥也非常好,因为它们不会过期,适用于沙盒和生产环境,并且可以使用相同的密钥(作为 .p8 文件)向 发送推送通知该 Apple 开发者帐户下的所有应用程序。

它还引入了一个潜在故障的新区域:typos。你可以输入一个随机的 bundle id,只要在 Xcode 中配置了正确的“团队”,你的应用就会很高兴地获得一个 APNs 设备令牌。

通过 APNs 向该设备令牌发送通知(我使用 this script 通过 HTTP/2 + Auth Keys 发送测试通知)将产生 DeviceTokenNotForTopic 错误,因此这应该可以帮助您找出问题所在。

清单

  • 确保您的应用程序包 ID 与您要发送到的包 ID 匹配
  • 确保您有一个权利文件,其中至少有一个 aps-environment 密钥设置为 development(Xcode 会在发布版本中为您自动更新)
  • 如果在 Firebase 等其他 SDK 中使用“自动”配置(即 swizzling),请确保您在 application:didRegisterForRemoteNotificationsWithDeviceToken: 中获取 APNs 令牌。这至少可以确认您的 APN 设置没有问题(但您仍然可能有错字)

FCM 设置

确保您使用的 GoogleService-Info.plist 文件与 plist 中的 BUNDLE_ID 键用于同一应用程序。我看到开发人员认为,因为 APNs 密钥应该在他们所有的应用程序中都可以正常工作,所以相同的 GoogleService-Info.plist 在应用程序中也可以正常工作,但事实并非如此。

测试

我还建议使用终端中的FCM's HTTP API 向自己发送测试通知,以帮助调试问题。与 Firebase 通知控制台不同,它会为您提供遇到的任何原始错误。这是一个例子:

curl -X "POST" "https://fcm.googleapis.com/fcm/send" \
     -H "Authorization: key=SERVER_KEY" \
     -H "Content-Type: application/json" \
     -d $'{
  "notification": {
    "body": "Testing with direct FCM API",
    "title": "Test Message",
    "badge": "0",
    "sound": "default"
  },
  "registration_ids": [
    "FCM_TOKEN"
  ]
}'

在您的 SERVER_KEY 中填写您的 Firebase 控制台 > 项目设置 > 云消息传递 > 服务器密钥中的值。将 FCM_TOKEN 替换为您的 FCM 令牌。

我在使用 FCM SDK 时使用 Paw 向我的应用发送测试通知。

【讨论】:

  • 知道为什么我会收到错误 "success":0,"failure":1,"canonical_ids":0,"results":[{"error":"InvalidRegistration"}]}
  • 啊,我使用的是 APN 令牌(来自苹果)而不是 firebase 令牌(这是不同的),这就是为什么
  • @aman 你能分享要使用哪个令牌的代码吗?我从过去 4 周开始面临这个问题,但仍然没有解决方案。你能帮忙吗
  • @Abhishek - func request_access_to_send_push_notifications(_ app:UIApplication) { let center = UNUserNotificationCenter.current() center.requestAuthorization(options:[.badge, .alert, .sound]) { (granted, error ) in // 根据授权启用或禁用功能。 } app.registerForRemoteNotifications() }
  • @Abhishek func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { // .. if let me = Auth.auth().currentUser { request_access_to_send_push_notifications(application) } //.. }
【解决方案2】:

我使用 .p8 文件发送通知,但通知未发送;然后我意识到 .p8 文件下没有启用 Apple 推送通知服务 (APN)。

启用后,现在一切似乎都正常了。

【讨论】:

    猜你喜欢
    • 2017-04-29
    • 1970-01-01
    • 2018-12-04
    • 1970-01-01
    • 2019-04-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多