FCM 后台通知在 iOS 中不起作用
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/37899712/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
FCM background notifications not working in iOS
提问by Mark O' Brian
I have a problem with FCM notification on iOS.
我在 iOS 上遇到 FCM 通知问题。
I receive notifications with success when my app is in foreground (the callback didReceiveRemoteNotification
in appdelegate
is fired), but I don't receive notifications when the app is in background (I do not see anything in the notification tray of iOS).
当我的应用程序在前台时(回调didReceiveRemoteNotification
inappdelegate
被触发),我成功收到通知,但当应用程序在后台时我没有收到通知(我在 iOS 的通知托盘中没有看到任何内容)。
So, I think the problem is in the format of the message sent by FCM. The json sent by my server to FCM, is in the following format:
所以,我认为问题出在 FCM 发送的消息格式上。我的服务器发送到 FCM 的 json 格式如下:
{
"data":{
"title":"mytitle",
"body":"mybody",
"url":"myurl"
},
"notification":{
"title":"mytitle",
"body":"mybody"
},
"to":"/topics/topic"
}
As you can see, there are two blocks in my json: one notification block (to receive notifications in background), and one data block (to receive notifications in foreground).
如您所见,我的 json 中有两个块:一个通知块(在后台接收通知)和一个数据块(在前台接收通知)。
I cannot understand why notifications in background are not received. My doubts are about the order of the blocks (is a problem if I put the "data" block before the "notification" block?).
我不明白为什么没有收到后台通知。我的疑问是关于块的顺序(如果我将“数据”块放在“通知”块之前会有问题吗?)。
EDIT:More info about the problem.
编辑:有关该问题的更多信息。
This is my appdelegate.swift:
这是我的 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:.
}
}
The only way I can receive messages in foreground, is by disabling method swizzling, setting FirebaseAppDelegateProxyEnabled to NO in my info.plist.
我可以在前台接收消息的唯一方法是禁用方法 swizzling,在我的 info.plist 中将 FirebaseAppDelegateProxyEnabled 设置为 NO。
In this case, FCM documentation says that I have to implement in my appdelegate.swift two methods:
在这种情况下,FCM 文档说我必须在我的 appdelegate.swift 中实现两个方法:
- FIRMessaging.messaging().appDidReceiveMessage(userInfo) in didReceiveRemoteNotification callback
- FIRInstanceID.instanceID().setAPNSToken(deviceToken, type: FIRInstanceIDAPNSTokenType.Sandbox) in didRegisterForRemoteNotificationsWithDeviceToken callback
But if I implement those functions, messages stops to arrive even when the app is in foreground.
但是如果我实现了这些功能,即使应用程序在前台,消息也会停止到达。
I know this is very strange.
我知道这很奇怪。
EDIT 2:
编辑2:
When the app is in background the notification isn't received, but when i open my app, the same notification is received immediately (method didReceiveRemoteNotification is fired).
当应用程序在后台时,不会收到通知,但是当我打开我的应用程序时,会立即收到相同的通知(方法 didReceiveRemoteNotification 被触发)。
采纳答案by Chris
Assuming you've set up everything correctly, then setting the priority
of the message from normal
to high
should make it appear immediately. This is due to the way iOS bundles notifications and handles them. You can read about the Priority of FCM notifications here. Please note that you shouldn't really use high
in production unless there is a good case for it, as it has a battery penalty.
假设您已正确设置所有内容,则将priority
消息的设置normal
为high
应使其立即出现。这是由于 iOS 捆绑通知和处理它们的方式。您可以在此处阅读FCM 通知的优先级。请注意,high
除非有很好的案例,否则您不应该真正在生产中使用它,因为它有电池损耗。
Here is the reference from Apple's docs
这是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.
通知的优先级。指定以下值之一:
10-立即发送推送消息。具有此优先级的通知必须在目标设备上触发警报、声音或徽章。将此优先级用于仅包含内容可用密钥的推送通知是错误的。
5—在考虑到设备电源的时间发送推送消息。具有此优先级的通知可能会被分组并以突发方式传送。它们受到限制,在某些情况下无法交付。如果省略此标头,APNs 服务器会将优先级设置为 10。
回答by Keith Holliday
You need to set the content_available
property to true like so:
您需要content_available
像这样将属性设置为 true:
{
"data":{
"title":"mytitle",
"body":"mybody",
"url":"myurl"
},
"notification":{
"title":"mytitle",
"body":"mybody",
"content_available": true
},
"to":"/topics/topic"
}
There is a blue note box on in this section that states this: https://firebase.google.com/docs/cloud-messaging/concept-options#notifications
本节中有一个蓝色的注释框,说明了这一点:https: //firebase.google.com/docs/cloud-messaging/concept-options#notifications
回答by CFP Support
Priority and content_available (as mentioned in other answers) are the key elements to make sure you receive the notifications. Tests showed interesting results, so I thought to share them here.
Priority 和 content_available(如其他答案中所述)是确保您收到通知的关键要素。测试显示了有趣的结果,所以我想在这里分享它们。
Test Results: Swift 3, Xcode 8, iOS 10
测试结果:Swift 3、Xcode 8、iOS 10
Priority = "high" => "immediate" (within obvious network delays) reception of message.
优先级 =“高”=>“立即”(在明显的网络延迟内)接收消息。
Priority = "normal" => various results (generally fast, though obviously slower than "high")
Priority = "normal" => 各种结果(一般很快,虽然明显比“high”慢)
content_available = true in the notifications (no payload message)
通知中的 content_available = true(无负载消息)
- Foreground = data received as expected
- Background = data received as expected (when opening the app)
- 前景 = 按预期接收的数据
- 背景 = 按预期接收的数据(打开应用程序时)
content_available = true in the top level (no payload message)
content_available = true 在顶层(无有效负载消息)
- Foreground = data received as expected
- Background = data received as expected (when opening the app)
- 前景 = 按预期接收的数据
- 背景 = 按预期接收的数据(打开应用程序时)
content_available = true in the notifications (with message {title/body})
通知中的 content_available = true(带有消息 {title/body})
- Foreground = data received TWICE
- Background = data received TWICE (when opening the app)
- 前景 = 数据接收两次
- 背景 = 数据接收两次(打开应用程序时)
content_available = true in the top level (with payload message)
content_available = true 在顶层(带有有效负载消息)
- Foreground = data received TWICE
- Background = data received TWICE (when opening the app)
- 前景 = 数据接收两次
- 背景 = 数据接收两次(打开应用程序时)
CONCLUSIONS:
结论:
- While Priority is a possible cause of not receiving messages, the MOST IMPORTANT factor is that you must have either 'content_available' or a payload message.
- content_available MUST be used on data-only payloads (without it, no message is ever sent).
- content_available SHOULD NOT be used on payloads that contain messages as it causes double messages to be sent from FCM.
- No difference found in the use of content_available in the top level or in the notifications.
- 虽然优先级可能是无法接收消息的原因,但最重要的因素是您必须拥有“content_available”或有效负载消息。
- content_available 必须用于纯数据负载(没有它,就不会发送任何消息)。
- content_available 不应用于包含消息的有效负载,因为它会导致从 FCM 发送双重消息。
- 在顶层或通知中使用 content_available 没有发现差异。
EDIT: Additional testing results: - if you have a msg title you MUST have a msg body or you don't get an alert.
编辑:附加测试结果: - 如果您有 msg 标题,则必须有 msg 正文,否则您不会收到警报。
The odd part of this is that you WILL get the vibrate, badge and sound, but the alert box won't show up unless you have a body as well as the title.
奇怪的部分是您将获得振动、徽章和声音,但除非您拥有正文和标题,否则不会显示警报框。
回答by astromme
回答by ireshika piyumalie
-For FCM when application is in background or foreground and OS <10 application(_:didReceiveRemoteNotification:) method will fire.
-对于 FCM,当应用程序处于后台或前台并且 OS <10 应用程序(_:didReceiveRemoteNotification:) 方法将触发时。
-When application is foreground and OS => 10 userNotificationCenter:willPresentNotification:withCompletionHandler: method will fire.
- 当应用程序处于前台且操作系统 => 10 userNotificationCenter:willPresentNotification:withCompletionHandler: 方法将触发。
-When sending data message without notification component: application(_:didReceiveRemoteNotification:) method will fire.
- 当发送没有通知组件的数据消息时:application(_:didReceiveRemoteNotification:) 方法将触发。
-When sending data message with notification component : userNotificationCenter:willPresentNotification:withCompletionHandler: method will fire.
- 使用通知组件发送数据消息时: userNotificationCenter:willPresentNotification:withCompletionHandler: 方法将触发。
回答by hamed moosaei
when you use direct FCM channel messages you can not receive notification in background
当您使用直接 FCM 频道消息时,您无法在后台收到通知
this is a paragraph from Firebase document:
这是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 后端使用可靠的消息队列来跟踪待处理的消息。当应用程序进入前台并重新建立连接时,通道将自动向客户端发送挂起的消息,直到它得到客户端的确认。
you can use FCM APNs interface to receive notifications in both foreground and background
您可以使用 FCM APNs 接口在前台和后台接收通知
回答by azmeuk
I had this issue, with the content_available
property set. The solution was to remove and reinstall the application from the iOS device.
我有这个问题,content_available
属性集。解决方案是从 iOS 设备中删除并重新安装该应用程序。