IOS data notifications with FCM

IOS data notifications with FCM

I am using FCM (firebase cloud messaging) to send "custom" data notifications to an IOS app. From what I understand, we use notification messages when you want FCM to handle displaying a notification on your app's behalf. And we use data messages when you just want to process the messages only in your app. It's by design. 
Problem I am facing is that that Device/InstandID token is unique to installed app and not the user logged in the app. So to solve this, I am sending intended user tag in the data so it becomes a data message. Since the app handles the data notifications, the didReceiveRemoteNotification() callback is only fired when the app is opened and the notification is only shown than and not instantly when it's sent.
My question is that can I send a custom data notification message and make it appear instantly even when the app is closed. 
This is the payload I am sending to FCM:
{
    registeration_ids : [, ],
    data : {
        title   : message_title,
        body    : message_body, 
        intended_user : message_user
    }
}

In android FirebaseMessagingService.onMessageReceived() is invoked even if the app is in the background but in ios didReceiveRemoteNotification() is only invoked when the application is launched so no background messages will appear if you send a data message.

Solutions/Answers:

Solution 1:

Try to set content_available to true.

From the fcm documentation :

Note: If you want to send messages consisting of only custom key-values to an iOS device when the app is in the background, set custom key-value pairs in the data key and set content_available to true.

{
    registeration_ids : [<id_1>, <id_2>],
    content_available: true,

    data : {
        title   : message_title,
        body    : message_body, 
        intended_user : message_user
    }
}

Solution 2:

From what I understand so far, there is no way of solving this issue properly on the ios side. It works perfectly on the android side because the application is awoken in all states (foreground, background & closed).

You have two kinds of messages you can send:

A notification-message which is displayed and handled by the operating system directly.

A data-message which is handled by the application.

If you add a custom tag, it now becomes a data-message and would have to be handled by the application. You can add a content_available tag in data-message to let the application know about the message but the problem is that the data-message is only delivered to the application in ios if the application is in the foregrounded (opened) or in the background (minimised). The data-message will not be delivered to the application if the user has “force-closed” the application (even with the background notifications enabled).

Solution is to handle the intended user on the server side and solve the multiple-users to one-device-token problem by maintaining the a one to one device-token to user relationship.

Solution 3:

I noticed that notification will arrive when app is force-closed in case that notification priority is set to high.

{  "notification": {
    "body" : "This week’s edition is now available.",
    "title": "Portugal vs. Denmark",
    "text": "5 to 1",
    "content_available": 1
  },
  "data" : {
    "volume" : "3.21.15",
    "contents" : "http://www.news-magazine.com/world-week/21659772"
  },
  "to" : "fqUk65A1kTE:APA91bG5...", // or set topic like "/topics/test"
  "priority" : "high"
}

For iOS client apps, normal and high priority are analogous to APNs priority levels 5 and 10.

From the iOS documentation it is possible that notification with default priority are not delivered.

apns-priority: 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.

Update 1:

The above notification is sent through FCM api and it was received while app was killed.
After I tap the notification on device this is what appears in device log after the app has started:

...didReceiveRemoteNotification: [gcm.message_id: 0:1468481012881485%e1d60a46e1d60a46, volume: 3.21.15, aps: {
        alert =     {
            body = "This week\U2019s edition is now available.";
            title = "Portugal vs. Denmark";
        };
    }, contents: http://www.news-magazine.com/world-week/21659772][;

Notice that data part is also contained in received message.

Update 2:

Multiple users on single device or one user with many devices.

On your server side you must assure that one unique fcm_id can be assigned only to one user. This means that one device is assigned to one user, so only one user will be notified per device.

Also, one user can have multiple fcm_ids, so it means user can have more devices and be signed in.

When the user_2 log in to same device of user_1, fcm_id must be detached from the user_1 and attached to user_2. Within this way, only currently logged in user will receive the message.

Solution 4:

Poor Documentation from Firebase!

For ios, Data messages can’t be received when app is killed. But this is not mentioned anywhere in their documentation. So I contacted Firebase and this is what they said.

“Though there is a content_available parameter, data messages cannot be received when the app is killed. It can only be received on background and in foreground. If you wish to receive data messages when the app is killed, you need to send it along a display messages “.

So its better to use APNS for ios rather if you ever thought of using same payload for android and Ios in FCM.

Solution 5:

The key problem is sending message to specific user group for the latest identity logged in.

Actually you can use topic messaging to solve the problem. Suppose you have 3 user tags/groups A,B and C. When FCM is initialized, register to 1 topic for All users to ensure that you can send a message to all user tags.

For specific user tags, subscribe to A if user signed in as A. After the user signed out and signed in as B, check if the user has subscribed to A/C or not. If yes, unsubscribe from A/C and then subscribe to B. This can then avoid handling tags involved in data section.

References

Related:  No static method zzUr() in Firebase when I try to use Analytics with Notifications