推送通知在Firebase 4.0中无效

Eri*_*rth 11 push-notification ios firebase swift3 firebase-cloud-messaging

我今天更新了我的pod到新的Firebase 4.0.我完成了建议的更改并从Github示例中获取了代码.我会说实话,我不知所措,我拿着FCM令牌并从firebase控制台发送消息,我什么也得不到.

我刷新,它说消息已发送,但我检查控制台和设备,没有任何东西.我错过了什么?

这是我的appdelegate:

//
//  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]
}
Run Code Online (Sandbox Code Playgroud)

这是日志:

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...
Run Code Online (Sandbox Code Playgroud)

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

深入潜入故障和最后的终极事件......跟随这个线程: https ://github.com/firebase/quickstart-ios/issues/290

特别感谢的RIZ他的时间搞清楚这个问题!

Riz*_*tar 17

Firebase Cloud Messaging在iOS上正确设置非常复杂,因为您必须确保您的APN配置正常工作,然后在其上添加FCM.

APN设置

APNs身份验证密钥对苹果来说也很不错,因为它们不会过期,适用于沙箱和生产环境,并且相同的密钥(作为.p8文件)可用于向该Apple Developer帐户下的所有应用程序发送推送通知.

它还为潜在的失败引入了一个新领域:拼写错误.您可以输入随机包ID,只要在Xcode中配置了正确的"团队",您的应用就会很高兴获得APNs设备令牌.

通过APN向该设备令牌发送通知(我使用此脚本通过HTTP/2 +身份验证密钥发送测试通知)将产生DeviceTokenNotForTopic错误,这样可以帮助您找出问题所在.

清单

  • 确保您的应用包ID与您要发送的包ID相匹配
  • 确保您有一个权利文件,至少aps-environment设置了一个密钥development(在Xcode中,这是在发布版本中自动更新的)
  • 如果在Firebase等其他SDK中使用"自动"配置(即调配),请确保您获得了APNs令牌application:didRegisterForRemoteNotificationsWithDeviceToken:.这至少证实你的APN设置没问题(但你可能还有错字)

FCM设置

确保GoogleService-Info.plist您使用的文件BUNDLE_ID与plist中的密钥相同.我见过开发人员认为,因为APNs Keys应该可以在所有应用程序GoogleService-Info.plist中正常工作,所以应用程序的情况也是如此,但事实并非如此.

测试

我还建议使用终端的FCM HTTP API发送测试通知,以帮助调试问题.与Firebase Notifications Console不同,它会为您提供遇到的任何原始错误.这是一个例子:

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"
  ]
}'
Run Code Online (Sandbox Code Playgroud)

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

当我使用FCM SDK时,我使用Paw向我的应用程序发送测试通知.