FCM后台通知无法在iOS中使用

我在iOS上遇到FCM通知问题。

当我的应用程序处于前台( appdelegate中的appdelegate被触发)时,我收到了成功的通知,但是当应用程序处于后台(我没有在iOS的通知托盘中看到任何内容)时,我没有收到通知。

所以我觉得问题是FCM发出的信息格式。 我的服务器发送给FCM的json格式如下:

 { "data":{ "title":"mytitle", "body":"mybody", "url":"myurl" }, "notification":{ "title":"mytitle", "body":"mybody" }, "to":"/topics/topic" } 

正如你所看到的,在我的json中有两个块:一个通知块(在后台接收通知)和一个数据块(在前台接收通知)。

我不明白为什么后台通知没有收到。 我怀疑是关于块的顺序(如果我把“数据”块放在“通知”块之前,是一个问题?)。

编辑:关于这个问题的更多信息。

这是我的appdelegate.swift:

 @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate { var window: UIWindow? // Application started func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject : AnyObject]?) -> Bool { let pushNotificationSettings: UIUserNotificationSettings = UIUserNotificationSettings(forTypes: [.Alert, .Badge, .Sound], categories: nil) application.registerUserNotificationSettings(pushNotificationSettings) application.registerForRemoteNotifications() FIRApp.configure() NSNotificationCenter.defaultCenter().addObserver(self, selector: "tokenRefreshNotification:", name: kFIRInstanceIDTokenRefreshNotification, object: nil) return true } // Handle refresh notification token func tokenRefreshNotification(notification: NSNotification) { let refreshedToken = FIRInstanceID.instanceID().token() print("InstanceID token: \(refreshedToken)") // Connect to FCM since connection may have failed when attempted before having a token. if (refreshedToken != nil) { connectToFcm() FIRMessaging.messaging().subscribeToTopic("/topics/topic") } } // Connect to FCM func connectToFcm() { FIRMessaging.messaging().connectWithCompletion { (error) in if (error != nil) { print("Unable to connect with FCM. \(error)") } else { print("Connected to FCM.") } } } // Handle notification when the application is in foreground 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) } // Application will enter in background 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. } // Application entered in background func applicationDidEnterBackground(application: UIApplication) { FIRMessaging.messaging().disconnect() print("Disconnected from FCM.") } // Application will enter in foreground 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. } // Application entered in foreground func applicationDidBecomeActive(application: UIApplication) { connectToFcm() application.applicationIconBadgeNumber = 0; } // Application will terminate func applicationWillTerminate(application: UIApplication) { // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. } } 

我可以在前台接收消息的唯一方法是禁用方法debugging,在我的info.plist中将FirebaseAppDelegateProxyEnabled设置为NO。

在这种情况下,FCM文档说我必须在我的appdelegate.swift中实现两个方法:

  - FIRMessaging.messaging().appDidReceiveMessage(userInfo) in didReceiveRemoteNotification callback - FIRInstanceID.instanceID().setAPNSToken(deviceToken, type: FIRInstanceIDAPNSTokenType.Sandbox) in didRegisterForRemoteNotificationsWithDeviceToken callback 

但是,如果我实现这些function,即使应用程序在前台,消息也会停止。

我知道这很奇怪

编辑2:

当应用程序在后台时,通知没有收到,但是当我打开我的应用程序时,立即收到相同的通知(方法didReceiveRemoteNotification被激发)。

假设你已经正确地设置了一切,那么将消息的prioritynormalhigh应该立即显示。 这是由于iOS绑定通知并处理它们的方式。 您可以在这里阅读关于FCM通知的优先级 。 请注意,除非有好的情况,否则你不应该使用high生产率,因为它有电池的损失。

这里是苹果的文档的参考

通知的优先级。 指定下列值之一:

10 – 立即发送推送消息。 具有此优先级的通知必须在目标设备上触发警报,声音或徽章。 将此优先级用于仅包含可用内容密钥的推送通知是错误的。

5-发送推送消息的时间考虑到设备的功耗考虑因素。 具有这个优先级的通知可以被分组并且以突发传递。 他们被扼杀,并在某些情况下不交付。 如果您省略此标头,则APNs服务器将优先级设置为10。

您需要将content_available属性设置为true,如下所示:

 { "data":{ "title":"mytitle", "body":"mybody", "url":"myurl" }, "notification":{ "title":"mytitle", "body":"mybody", "content_available": true }, "to":"/topics/topic" } 

本节中有一个蓝色的注释框,其中声明了这一点: https : //firebase.google.com/docs/cloud-messaging/concept-options#notifications

您可能需要添加推送通知权利。 通过转到您的目标设置,然后单击“function”并打开“推送通知”。

目标能力

优先级和content_available(如其他答案中所述)是确保您收到通知的关键要素。 testing显示有趣的结果,所以我想在这里分享。

testing结果:Swift 3,Xcode 8,iOS 10

优先级=“高”=>“立即”(在明显的networking延迟内)接收消息。

优先级=“正常”=>各种结果(通常很快,但明显比“高”慢)

通知中的content_available = true(没有负载消息)

  • 前景=按预期收到的数据
  • 背景=按预期收到的数据(打开应用程序时)

content_available = true在顶层(无有效消息)

  • 前景=按预期收到的数据
  • 背景=按预期收到的数据(打开应用程序时)

content_available = true(包含消息{title / body})

  • 前景=收到的数据TWICE
  • 背景= TWICE收到的数据(打开应用程序时)

content_available = true在顶层(带有负载信息)

  • 前景=收到的数据TWICE
  • 背景= TWICE收到的数据(打开应用程序时)

结论:

  1. 虽然优先级是未收到消息的可能原因,但最重要的因素是您必须具有“content_available”或有效负载消息。
  2. content_available必须用于仅有数据的有效载荷(没有它,不会发送任何消息)。
  3. content_available不应该用于包含消息的有效载荷,因为它会导致从FCM发送双重消息。
  4. 在顶层或通知中使用content_available时没有区别。

编辑:额外的testing结果: – 如果你有一个味精的标题,你必须有一个味精的身体,或者你没有得到一个警报。

奇怪的是,你会得到振动,徽章和声音,但警报框将不会显示,除非你有一个身体以及标题。

我有这个问题,与content_available属性设置。 解决的办法是从iOS设备上删除并重新安装应用程序。