Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Firebase Cloud Messaging iOS: No background push notification

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

like image 750
Daniel George Avatar asked Jul 19 '16 05:07

Daniel George


People also ask

Does FCM work in iOS?

FCM Background notifications works in Android; not in iOS.

Is Firebase Cloud Messaging push notifications?

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.


2 Answers

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.

like image 56
Daniel George Avatar answered Oct 20 '22 04:10

Daniel George


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

    1. swipe notification away -> PN will be NOT processed by the app

    2. open the app via the launcher icon directly -> PN will be NOT processed by the app

    3. 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!

like image 37
Manuel Schmitzberger Avatar answered Oct 20 '22 05:10

Manuel Schmitzberger