问题
Using the newer Firebase cloud messaging with method swizzling i am successfully able to receive a payload in the didReceiveRemoteNotification
method in my app delegate when my app is foregrounded. However i do not get any sort of payload and didReceiveRemoteNotification
does not get called when my app is backgrounded, despite the api response that the message is successfully sent (see below)
Here is the request that i send to the FCM api to trigger a push notification https://fcm.googleapis.com/fcm/send
{
"to": "{valid-registration-token}",
"priority":"high", //others suggested setting priority to high would fix, but did not
"notification":{
"body":"Body3",
"title":"test"
}
}
with response from FCM
{
"multicast_id": 6616533575211076304,
"success": 1,
"failure": 0,
"canonical_ids": 0,
"results": [
{
"message_id": "0:1468906545447775%a4aa0efda4aa0efd"
}
]
}
Here is my appDelegate code
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
Fabric.with([Crashlytics.self])
FIRApp.configure()
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(self.tokenRefreshNotification),
name: kFIRInstanceIDTokenRefreshNotification, object: nil)
return true
}
func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject], fetchCompletionHandler completionHandler: (UIBackgroundFetchResult) -> Void) {
// Let FCM know about the message for analytics etc.
FIRMessaging.messaging().appDidReceiveMessage(userInfo)
// Print full message.
print("%@", userInfo)
// handle your message
// let localNotification = UILocalNotification()
// localNotification.fireDate = NSDate()
// let notification = userInfo["notification"]!
// localNotification.alertBody = notification["body"] as? String
// localNotification.alertTitle = notification["title"] as? String
// localNotification.timeZone = NSTimeZone()
// application.scheduleLocalNotification(localNotification)
}
func tokenRefreshNotification(notification: NSNotification) {
let refreshedToken = FIRInstanceID.instanceID().token()!
print("InstanceID token: \(refreshedToken)")
LoginVC.registerForPushNotifications()
connectToFcm()
}
//foreground messages
func applicationDidBecomeActive(application: UIApplication) {
connectToFcm()
}
// [START disconnect_from_fcm]
func applicationDidEnterBackground(application: UIApplication) {
FIRMessaging.messaging().disconnect()
print("Disconnected from FCM.")
}
func connectToFcm() {
FIRMessaging.messaging().connectWithCompletion { (error) in
if (error != nil) {
print("Unable to connect with FCM. \(error)")
} else {
print("Connected to FCM.")
}
}
}
}
I call this code at a later flow in my app to ask for permissions
static func registerForPushNotifications() {
let settings: UIUserNotificationSettings =
UIUserNotificationSettings(forTypes: [.Alert, .Badge, .Sound], categories: nil)
UIApplication.sharedApplication().registerUserNotificationSettings(settings)
UIApplication.sharedApplication().registerForRemoteNotifications()
}
Since i am able to receive notifications while app is foregrounded i assume this would allay all concerns that my apns certificates are not uploaded or that the registration token is incorrect. If that is not the case, please comment and i'll go down that rabbit hole again. There's probably something simple that i am overlooking, but how can i get the notifications to appear while the app is backgrounded? Thanks
回答1:
Apparently, (despite using method swizzling that should be doing it automatically) you must still set the APNS token on the Firebase Instance. Consequently this means you must also implement the didRegisterForRemoteNOtificationsWithDeviceToken
method with something like
func application(application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: NSData) {
// set firebase apns token
FIRInstanceID.instanceID().setAPNSToken(deviceToken, type: FIRInstanceIDAPNSTokenType.Unknown)
}
As an added note. Using "priority":"high"
was useful for testing as it sent the notification right away.
回答2:
Similarily to Daniel George's solution I could fix my problem with:
Messaging.messaging().apnsToken = deviceToken
FirebaseInstanceID 2.0.8, FirebaseMessaging 2.0.8
回答3:
The desired behavior, at least for my app, is for the arrival of a push notification where the content of the PN (Push Notification) should be shown in a desired page in the app.
I've three different app states where a PN can arrive: (of course it depends on your implementation, but you should get an idea how apple processes the PN in these states)
(the behavior is determined by apple!)
1) the app is in foreground:
- PN received
- pops up in the Notification Center (you can either click on it or not - it does not matter)
- badge will be updated
- PN is available in the desired page
In this case the app always processes the PN
2) the app is in background:
- PN received
- pops up in the Notification Center (you can either click on it or not - it does not matter)
- badge will be updated
- PN is available in the desired page
In this case the app always processes the PN
3) the app is killed/closed:
- PN received
- pops up in the Notification Center
now there are three possible ways
swipe notification away -> PN will be NOT processed by the app
open the app via the launcher icon directly -> PN will be NOT processed by the app
click on the notification -> PN will be processed by the app
For this case, if the user does not open the app by tapping the notification, there is no way to get the notification data.
To be independent of the app state, you need to setup a server, where you can request the specific data. E.g. you've a view which shows all notifications, you need an API to request specific data. You shouldn't process the data in the receiving method of the Pushnotification.
I hope that helps someone!
回答4:
Make sure that you have added "content_available" : true in the JSON payload. Otherwise you won't get push notification in the background mode.
"notification" : {
"content_available" : true,
"body" : "this is body",
"title" : "this is title"
}
回答5:
Follows these step after getting successful token from FCM to enable the background payload data fetch using FCM:
open Project Navigator > AppCapabilities > Background Modes > check for remote notifications
In App.delegate define:
func application(_ application: UIApplication,didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) { print("userinfo in background mode on-\(userInfo)") completionHandler(UIBackgroundFetchResult.newData) }
Format your payload correctly according to apple guidelines: enter link description here
Do not forget to add key value pair:
{"content-available":1}
unless you won't able to fetch payload in background.
now try to send the notification again using FCM token. Have a happy coding
回答6:
AFAIK, for ios you wont be able to use FCM for send push notification messages for apps in background or killed state.
Firebase Push Notification
来源:https://stackoverflow.com/questions/38450595/firebase-cloud-messaging-ios-no-background-push-notification