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
FCM Background notifications works in Android; not in iOS.
Firebase Cloud Messaging (FCM) provides a reliable and battery-efficient connection between your server and devices that allows you to deliver and receive messages and notifications on iOS, Android, and the web at no cost.
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.
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:
In this case the app always processes the PN
2) the app is in background:
In this case the app always processes the PN
3) the app is killed/closed:
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!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With