FCM background notifications not working in iOS
我在iOS上的FCM通知有问题。
当我的应用程序位于前台(触发了
因此,我认为问题在于FCM发送的消息格式。
我的服务器发送到FCM的json格式如下:
1 2 3 4 5 6 7 8 9 10 11 12 | { "data":{ "title":"mytitle", "body":"mybody", "url":"myurl" }, "notification":{ "title":"mytitle", "body":"mybody" }, "to":"/topics/topic" } |
如您所见,我的json中有两个块:一个通知块(用于在后台接收通知)和一个数据块(用于在前台接收通知)。
我不明白为什么没有收到后台通知。
我对块的顺序感到怀疑(如果将"数据"块放在"通知"块之前是个问题吗?)。
编辑:
有关该问题的更多信息。
这是我的appdelegate.swift:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 | @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:. } } |
我可以在前台接收消息的唯一方法是禁用方法切换,将info.plist中的FirebaseAppDelegateProxyEnabled设置为NO。
在这种情况下,FCM文档说我必须在我的appdelegate.swift中实现两个方法:
1 2 | - FIRMessaging.messaging().appDidReceiveMessage(userInfo) in didReceiveRemoteNotification callback - FIRInstanceID.instanceID().setAPNSToken(deviceToken, type: FIRInstanceIDAPNSTokenType.Sandbox) in didRegisterForRemoteNotificationsWithDeviceToken callback |
但是,如果我实现了这些功能,即使应用程序处于前台,消息也会停止到达。
我知道这很奇怪。
编辑2:
当应用程序在后台运行时,不会收到通知,但是当我打开应用程序时,会立即收到相同的通知(触发了didReceiveRemoteNotification方法)。
假设您已经正确设置了所有内容,那么将消息的
这是Apple文档的参考
The priority of the notification. Specify one of the following values:
10–Send the push message immediately. Notifications with this priority
must trigger an alert, sound, or badge on the target device. It is an
error to use this priority for a push notification that contains only
the content-available key.5—Send the push message at a time that takes into account power
considerations for the device. Notifications with this priority might
be grouped and delivered in bursts. They are throttled, and in some
cases are not delivered. If you omit this header, the APNs server sets
the priority to 10.
您需要像这样将
1 2 3 4 5 6 7 8 9 10 11 12 13 | { "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
优先级和content_available(如其他答案所述)是确保您收到通知的关键要素。测试显示出有趣的结果,所以我想在这里分享。
测试结果:Swift 3,Xcode 8,iOS 10
优先级="高" =>"立即"(在明显的网络延迟内)接收消息。
优先级="正常" =>各种结果(通常较快,但明显比"较高"慢)
通知中的content_available = true(无有效载荷消息)
- 前景=预期收到的数据
- 背景=预期收到的数据(打开应用程序时)
content_available =顶层为true(无有效负载消息)
- 前景=预期收到的数据
- 背景=预期收到的数据(打开应用程序时)
通知中的content_available = true(带有消息{title / body})
- 前景=收到数据TWICE
- 背景=两次收到数据(打开应用程序时)
content_available =顶层为true(带有有效负载消息)
- 前景=收到数据TWICE
- 背景=两次收到数据(打开应用程序时)
结论:
编辑:其他测试结果:
-如果您有味精标题,则必须有味精正文,否则就不会收到警告。
奇怪的是,您将获得振动,徽章和声音,但是除非您有身体和标题,否则警告框不会显示。
您可能需要添加推送通知权利。为此,请转到目标设置,然后单击"功能"并打开"推送通知"。
-对于FCM,当应用程序在后台或前台且OS <10时 application(_:didReceiveRemoteNotification :)方法将触发。
-当应用程序为前台且OS => 10时
userNotificationCenter:willPresentNotification:withCompletionHandler:方法将触发。
-发送不带通知组件的数据消息时:
application(_:didReceiveRemoteNotification :)方法将触发。
-发送带有通知组件的数据消息时:
userNotificationCenter:willPresentNotification:withCompletionHandler:方法将触发。
当您使用直接FCM频道消息时,您不会在后台收到通知
这是Firebase文档的一段:
With the direct channel enabled, the FCM backend uses a reliable message queue to keep track of pending messages when the app is in the background or closed. When the app goes to the foreground and the connection is re-established, the channel will automatically send pending messages to the client until it gets an acknowledgement from the client.
您可以使用FCM APNs界面在前台和后台接收通知
我遇到了