FCM notifications and collapse_key

steliosf picture steliosf · Jun 14, 2017 · Viewed 20.7k times · Source

I'm sending notifications to users Android devices though the Firebase Notification console and I notice that even if I send 10 different notifications while the user device is offline, once the user goes online she/he will receive all 10.

However in Firebase documentation it is stated that:

FCM allows a maximum of four different collapse keys per device to be used by the app server at any given time. In other words, the FCM connection server can simultaneously store four different collapsible send-to-sync messages per device, each with a different collapse key. If you exceed this number, FCM only keeps four collapse keys, with no guarantees about which ones are kept.

So shouldn't the user receive only 4 notifications? Am I missing something? (I am not extending the FirebaseMessagingService, I leave the notification handling to the SDK)

UPDATE: If you don't specify a collapse key in the Firebase notifications console, it seems that an implicit collapse key is assigned to the notification and that is the package name of the app. I've tested that by checking all key/value pairs of the getIntent().getExtras() key set, once I launch the app by tapping on the notification. And indeed, I am getting a collapse_key key with the value of the package name, even if I haven't specified one.

UPDATE 2: I tried to handle the notifications by extending the FirebaseMessagingService, so that I receive the messages from the notifications console, when the app is in the foreground. I receive the notification message and I manually display a notification to the user. And guess what. Collapse keys work great! I receive a single notification even if I send multiple notifications with the same collapse key. BUT this happens obviously only when the app is in the foreground, because the Firebase SDK doesn't call the onMessageReceived() when the app is in the background, but instead it handles the notification itself. Does that mean that this is a bug of the Firebase SDK? (since the issue happens only when the notification is shown by the SDK)

So question remains, why do I receive all 10 notifications since each notification has the same collapse key? Maybe an FCM bug?

Answer

Bob Snyder picture Bob Snyder · Jun 23, 2017

After reading the post and comments, I'm not completely clear on everything that has been tried, which efforts were successful and which failed. I'll cover a number if items and hope something is helpful.

Your post indicates that for some tests, you specified a collapse key when you composed the message in Firebase console. That is not possible. If you opened Advanced options and entered a key/value pair under Custom data, that will not work. Those values are stored in the message under the data key, not at the top level of the message where collapse_key must appear. Also, Table 1 in the documentation includes a warning that data keys should not be any of the reserved words in the table, specifically citing collapse_key:

The key should not be a reserved word ("from" or any word starting with "google" or "gcm"). Do not use any of the words defined in this table (such as collapse_key).

As noted in the comments to your post, the console automatically assigns a collapse key that is the package name, so user entry of a collapse key is not needed.

That said, my experiences with the console match yours. I create messages by entering only Message text and the device token. I see no collapse processing; each message is received by the device. Based on my experience with the tests described below, this seems to be a problem with the console and not with collapse processing in general. This is odd, because if I send the messages when the app is in the foreground, and onMessageReceived() is invoked, I have debug logging that outputs the collapse key in the message using getCollapseKey(). That output confirms that the key is present and is my app package name.

You indicate that you did some tests sending notifications from a cloud function. I did my own testing with this cloud function and observed the expected message collapse:

exports.test = functions.database.ref('/test').onWrite(event => {
  const token = 'dK1FjGbNr6k:APA91bH7Vz3x...icGO56sJ7rAqOXRI';

  console.log('Sending notification...');

  const payload = {
    notification: {
      title: 'Message',
      body: 'Just one please!'
    }
  };

  const options = {
    collapseKey: 'green'
  };

  return admin.messaging().sendToDevice(token, payload, options).then(response => {
    console.log('Done');
  });
});

I also sent this message using browser app Advanced Rest Client, and also saw correct message collapsing:

{
  "to": "dK1FjGbNr6k:APA91bH7Vz3x...O56sJ7rAqOXRI",
  "collapse_key": "green",
  "notification": {
    "title": "Message",
    "body": "Just one please!"
  }
}

I'll also share that Firebase emits an analytics log message when a notification message is received. This is useful for testing, when you want to get a count of messages received:

D/FA: Logging event (FE): notification_receive(_nr), Bundle[{firebase_event_origin(_o)=fcm, message_device_time(_ndt)=0, message_time(_nmt)=1498227476, message_id(_nmid)=6447126672094369335}]