Firebase云消息传递通知未发送iOS有效内容格式

时间:2016-06-18 09:05:14

标签: ios swift firebase-cloud-messaging firebase-notifications

昨晚我在我的应用程序中使用FCM测试推送通知并且它已经崩溃(几天前工作了)。我使用firebase控制台中的通知菜单测试它。

我进一步调查通知有效负载格式已更改,并且不包含类似Apple Documentation中的iOS格式。

我重新检查我的APNs证书并且开发版已经不见了,我尝试重新上传证书并且它出现类似like this one的错误。

我向firebase团队提交了一份反馈,并表示这是他们最终的问题。 (注意:我还在上面的链接中发布了firebase团队的回复)。我的Dev APNs证书又回来了,但格式仍然相同。

这是我获得的有效载荷(来自Swift Print功能)

{
    "collapse_key" = "com.xxx.xxx";
    from = xxx;
    notification =     {
        badge = 3;
        body = "Firebase console";
        e = 1;
        title = Test;
    };
}

此有效负载使iOS无法显示推送通知。

基于this FCM documentation for iOS

以下代码会在通知到来时使应用程序崩溃

func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject],
                 fetchCompletionHandler completionHandler: (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.
  print("Message ID: \(userInfo["gcm.message_id"]!)")

  // Print full message.
  print("%@", userInfo)
}
  • 我已经尝试重新上传我的Dev APNs证书但仍然是错误
  • 我还提交了其他反馈,但Firebase小组尚未回复

我错过了什么吗?

修改

就像我上面所说的那样,它在几天前就可以工作了,当this issue出现时就会崩溃。

具体来说,这一行将使应用程序崩溃,我怀疑它是因为有效载荷格式发生了变化(缺少aps有效载荷)。

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

删除它(并在上面生成)时代码运行良好,但我仍然没有获得aps有效负载格式,因此当应用程序在后台时,通知将永远不会弹出。此外,当前景中的应用程序时,我的通知处理程序将无法正常工作。

编辑2

我已在AppDelegate中注册通知

let setting = UIUserNotificationSettings(forTypes: [.Sound, .Alert, .Badge] , categories: nil)
    application.registerUserNotificationSettings(setting)
    application.registerForRemoteNotifications()

我已经意识到这一点,并且已经启用了推送通知和远程通知后台模式。

Capabilities

编辑2016年6月28日

我再次尝试从firebase控制台推送通知,但仍然得到了与此相同的有效负载格式

%@ [notification: {
    badge = 2;
    body = "Test Message";
    e = 1;
    sound = default;
    sound2 = default;
    title = Test;
}, collapse_key: com.xxx, from: 717xxxxxx]

我的FCM Firebase控制台设置如下所示

Firebase Console Setting

2016年7月8日编辑

这是我的AppDelegate代码

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate, GIDSignInDelegate {

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

        // Firebase 
        let setting = UIUserNotificationSettings(forTypes: [.Sound, .Alert, .Badge] , categories: nil)
        application.registerUserNotificationSettings(setting)
        application.registerForRemoteNotifications()

        FIRApp.configure()

        print(FIRInstanceID.instanceID().token())

        FIRAnalytics.logEventWithName(kFIREventAppOpen, parameters: nil)

        NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(tokenRefreshNotificaiton), name: kFIRInstanceIDTokenRefreshNotification, object: nil)

        return true
    }

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

    func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject]) {
        // 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.
//        print("Message ID: \(userInfo["gcm.message_id"]!)")

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

        var body = ""
        var title = "20Fit"

        guard let aps = userInfo["aps"] as? [String : AnyObject] else {
            print("Error parsing aps")
            return
        }

        if let alert = aps["alert"] as? String {
            body = alert
        } else if let alert = aps["alert"] as? [String : String] {
            body = alert["body"]!
            title = alert["title"]!
        }

        let banner = Banner(title: title, subtitle: body, image: nil, backgroundColor: UIColor.blackColor(), didTapBlock: nil)
        banner.show(duration: 5.0)
    }

    func application(application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: NSData) {
           FIRInstanceID.instanceID().setAPNSToken(deviceToken, type: .Sandbox)
    }

    func tokenRefreshNotificaiton(notification: NSNotification) {
        let refreshedToken = FIRInstanceID.instanceID().token()!
        print("InstanceID token: \(refreshedToken)")

        sendTokenToServer()

        // Connect to FCM since connection may have failed when attempted before having a token.
        connectToFcm()
    }

    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 throttle down OpenGL ES frame rates. Games should use this method to pause the game.
    }

    func applicationDidEnterBackground(application: UIApplication) {
        // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
        // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
        FIRMessaging.messaging().disconnect()
        print("Disconnected from FCM")
    }

    func applicationWillEnterForeground(application: UIApplication) {
        // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
    }

    func applicationDidBecomeActive(application: UIApplication) {
        connectToFcm()
        // 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) {
        // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
        FIRAnalytics.logEventWithName("app_terminated", parameters: nil)
    }


}

以下是我的应用的完整日志

2016-07-08 19:26:48.022 20FIT Member[2525:1122556] WARNING: Firebase Analytics App Delegate Proxy is disabled. To log deep link campaigns manually, call the methods in FIRAnalytics+AppDelegate.h.
2016-07-08 19:26:48.273 20FIT Member[2525:1122556] Configuring the default app.
2016-07-08 19:26:48.318 20FIT Member[2525:] <FIRAnalytics/DEBUG> Debug mode is on
2016-07-08 19:26:48.338 20FIT Member[2525:] <FIRAnalytics/INFO> Firebase Analytics v.3200000 started
2016-07-08 19:26:48.338 20FIT Member[2525:] <FIRAnalytics/INFO> To enable debug logging set the following application argument: -FIRAnalyticsDebugEnabled (see google link)
2016-07-08 19:26:48.343: <FIRInstanceID/WARNING> Failed to fetch APNS token Error Domain=com.firebase.iid Code=1001 "(null)"
2016-07-08 19:26:48.350: <FIRMessaging/INFO> FIRMessaging library version 1.1.0
2016-07-08 19:26:48.339 20FIT Member[2525:] <FIRAnalytics/DEBUG> Debug logging enabled
2016-07-08 19:26:48.365 20FIT Member[2525:] <FIRAnalytics/DEBUG> Uploading data. Host: https://play.googleapis.com/log
2016-07-08 19:26:48.366 20FIT Member[2525:] <FIRAnalytics/DEBUG> Firebase Analytics is monitoring the network status
Optional("cXwsIWfiJas:APA91bGjUnL-oztH9LntO4EaKdJxPQN_-Za5ydC-hPR-_HPZXNm4m_mzqSztvbBG7HczNN5Jr7Btr8h4ETF5FyOOUn8Ombk4c3RoTL6GDFrh6BnG0ECs_r_Hqx1dnVHeJVwLQo4JInn2")
2016-07-08 19:26:48.406 20FIT Member[2525:] <FIRAnalytics/DEBUG> Successfully parsed a configuration. Version: 1464617411301000
2016-07-08 19:26:48.429 20FIT Member[2525:] <FIRAnalytics/DEBUG> Firebase Analytics is ready to receive events
2016-07-08 19:26:48.432 20FIT Member[2525:] <FIRAnalytics/DEBUG> No network. Upload task will not be scheduled
2016-07-08 19:26:48.434 20FIT Member[2525:] <FIRAnalytics/DEBUG> Cancelling background upload task.
2016-07-08 19:26:48.437 20FIT Member[2525:] <FIRAnalytics/DEBUG> Scheduling user engagement timer
2016-07-08 19:26:48.438 20FIT Member[2525:] <FIRAnalytics/DEBUG> Timer scheduled to fire in approx. (s): 3600
2016-07-08 19:26:48.441 20FIT Member[2525:] <FIRAnalytics/INFO> Firebase Analytics enabled
2016-07-08 19:26:48.445 20FIT Member[2525:] <FIRAnalytics/DEBUG> Logging event: origin, name, params: app, app_open, {
        "_o" = app;
    }
2016-07-08 19:26:48.477 20FIT Member[2525:] <FIRAnalytics/DEBUG> Scheduling user engagement timer
2016-07-08 19:26:48.478 20FIT Member[2525:] <FIRAnalytics/DEBUG> Canceling active timer
2016-07-08 19:26:48.479 20FIT Member[2525:] <FIRAnalytics/DEBUG> Timer scheduled to fire in approx. (s): 3600
2016-07-08 19:26:48.562 20FIT Member[2525:] <FIRAnalytics/DEBUG> Network status has changed. code, status: 2, Connected
2016-07-08 19:26:48.566 20FIT Member[2525:] <FIRAnalytics/DEBUG> Network status has changed. code, status: 2, Connected
2016-07-08 19:26:48.618 20FIT Member[2525:] <FIRAnalytics/DEBUG> Event logged. Event name, event params: app_open, {
        "_o" = app;
    }
2016-07-08 19:26:48.635 20FIT Member[2525:] <FIRAnalytics/DEBUG> Timer scheduled to fire in approx. (s): 3143.319384038448
2016-07-08 19:26:48.636 20FIT Member[2525:] <FIRAnalytics/DEBUG> Upload task scheduled to be executed in approx. (s): 3143.319384038448
2016-07-08 19:26:48.637 20FIT Member[2525:] <FIRAnalytics/DEBUG> Do not schedule an upload task. Task already exists
2016-07-08 19:26:48.710 20FIT Member[2525:] <FIRAnalytics/DEBUG> Received SSL challenge for host. Host: https://play.googleapis.com/log
2016-07-08 19:26:49.408 20FIT Member[2525:] <FIRAnalytics/DEBUG> Uploading data. Host: https://play.googleapis.com/log
Connected to FCM.
2016-07-08 19:26:49.869 20FIT Member[2525:] <FIRAnalytics/DEBUG> Received SSL challenge for host. Host: https://play.googleapis.com/log
2016-07-08 19:26:50.206 20FIT Member[2525:] <FIRAnalytics/DEBUG> Uploading data. Host: https://play.googleapis.com/log
2016-07-08 19:26:50.723 20FIT Member[2525:] <FIRAnalytics/DEBUG> Received SSL challenge for host. Host: https://play.googleapis.com/log
%@ [notification: {
    badge = 2;
    body = "Test Message";
    e = 1;
    sound = default;
    sound2 = default;
    title = Yoiii;
}, collapse_key: com.xxx.xxx, from: 717xxxx]
Error parsing aps

8 个答案:

答案 0 :(得分:4)

我遇到了同样的问题

关于fcm指南的这一部分:https://firebase.google.com/docs/cloud-messaging/ios/client#swizzling_disabled_receive_messages_through_the_messaging_apns_interface

我解决了添加setAPNSToken:type:

的问题
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
{
    [[FIRInstanceID instanceID] setAPNSToken:deviceToken type:FIRInstanceIDAPNSTokenTypeSandbox];
}

之后,fcm开始发送推送,并为iOS正确格式化了有效负载。

生产环境使用FIRInstanceIDAPNSTokenTypeProd

答案 1 :(得分:1)

您正在打印的“有效负载”看起来对我而言。但请注意,这是而不是APN有效负载。它实际上是一个用户信息字典。如果我理解您的问题,您似乎担心"aps"字段丢失。您不会在用户信息词典中看到该字段。

您是在真实设备上还是在模拟器中运行它?请记住,模拟器无法显示远程通知,并且在真实设备上,应用程序需要在后台显示通知。

尝试发送本地通知(安排时间为30秒):

localNotif.fireDate = [[NSDate date] dateByAddingTimeInterval:30];

然后按主页键等待。

答案 2 :(得分:0)

您提供的“有效负载”(大概)是由didReceiveRemoteNotification方法的最后一行生成的,即print("%@", userInfo)

您声称上面的代码会导致应用程序崩溃,这与成功打印到日志的代码相矛盾。

我认为还有其他东西会让您的应用崩溃。你看过系统日志了吗? (如果您使用的是模拟器,请转到Debug&gt; Open System Log。)

我建议运行Firebase演示应用程序(pod try Firebase),以说服自己它正在按预期工作。

答案 3 :(得分:0)

我正在研究为什么你的gcm.message_id为空,给我几天。

如果应用程序在后台时没有收到通知,请确保注册远程通知,如快速入门示例所示(请参阅didFinishLaunchingWithOptions):https://github.com/firebase/quickstart-ios/blob/master/messaging/FCMSwift/AppDelegate.swift

另外,请确保在Xcode中设置了允许处理后台通知的功能。

答案 4 :(得分:0)

这里的问题相同。此外,Firebase消息与关键&#39; aps&#39;在使用控制台发送时似乎没有交付。必须是使用Firebase的一些错误才能更改有效负载格式。

关于在后台模式下获取Firebase通知,在这种情况下,我认为iOS无法识别有效负载格式 - &gt;根本没有通知。要在后台从Firebase读取消息,请在移至后台模式时调用 FIRMessaging.messaging()。disconnect()。然后你应该得到你的消息并通过你自己的句柄处理它(仍然没有系统通知)。

答案 5 :(得分:0)

我浏览了Apple的开发者论坛,似乎didRegisterForRemoteNotificationsWithDeviceToken没有在SandBox模式下工作,只在Production中工作。 didRegisterForRemoteNotificationsWithDeviceToken是我用firebase注册deviceToken的地方。由于没有发生这种情况,Firebase正在使用notification密钥发送有效负载,因为它不知道该设备是Apple。 Apple今天解决了这个问题,现在我可以发送通知了。

答案 6 :(得分:0)

我讨厌同样的问题,我加上'高'优先级,它对我有用!

{
    "collapse_key" :"com.xxx.xxx",
    to: "xxx",
    priority : "high",
    notification :{..}
}

答案 7 :(得分:-2)

切换您的wifi /移动数据将达到目的。