Covering up the Skipped Beat in FCM Conceptualization: Distinction between Notification Messages and Data Messages

Anirban Bhattacharjee
7 min readApr 25, 2017

--

As the never ending title suggests, this post is about the fine line of distinction that exists between Notification Messages and Data Messages in Firebase Cloud Messaging (FCM) in Android.

Before commencing straight into the depth, let us get settled by having a brief discussion on FCM, incase you’re scratching your head by looking at the title.

For Android developers, implementing Push Notifications and handling callbacks for the same is no new piece of pie! In almost all the apps that are there in your phone, you must have got a notification appear and sit up in your System Tray. Well, these bunch of things are categorized into two simplest forms, Local Notifications and Remote Push Notifications. This article focusses upon an in-depth concept of the later one. And these Remote Push Notifications are, in short, things that are triggered by an application’s backend and delivered to end user apps by a vendor i.e. FCM or GCM (Google Cloud Messaging, which has become somewhat af an old-school thing since Google IO in May, 2016).

The underlying process is, any backend server, containing a web API Key composes a remote message, or notification data in simple terms, and sends it to a vendor(in our case, it is FCM) to ensure delivery to end point devices. This is done through means of a device token, which is sent by the backend to the particular vendor, which serves for the purpose of identification of device. This is the token generated by any app registered with Firebase. (To initialize Firebase, follow the link). The vendor simply sends the particular remote message to the device having the token provided by the backend to the vendor. This operation is explained for one but generally occurs in bulk.

How I came up with the idea of wasting your precious few minutes with my article?

Well, I was implementing Server Driven Notifications on the client side, i.e. on the Android side. I saw a weird thing coming up. While I was testing things out, there rose something which killed an hour of my time.
I found out a significant difference of the manner in which things were getting handled when I was sending Notifications from the Firebase Console and while I did the same using a REST client (POSTMAN in my case).

I’ll sum up the differences in a synchronous manner. Here we go:

  • When the app was open, the callback was received in the onMessageReceived(RemoteMessage) over-riden method of the class which extends FirebaseMessagingService . The behaviour seemed fine in either of the cases. Also, this is fine as per the documentation provided by Google which states that one has to override the onMessageReceived(RemoteMessage) as callback comes there.
  • In the second scenario, my app was in background. I tried generating the same from both Firebase Console and Postman. In case of Postman, the behaviour was exactly the same as the previous scenario. However, for the Firebase, a random notification was generated which displayed the text and title which I had composed but surprisingly, the onMessageReceived(RemoteMessage) did not get called. (I got to know as I had put logs in the onMessageReceived method!!)
  • Before raising the doubts, I’d like to cover up the last scenario whereby, the app was killed. In that case, the behaviour happened to be exactly same as the second case scenario.

Looking above, the obvious and desperate questions came as in where from does this custom Notification got generated? I was literally confused in awe of the fact that how come I see Notifications somewhat magically or there was some kind of supernatural spell going on in my code!

There had to be an explanation as I was not that dumb to consider everything as magic and letting it go!!!

Jokes apart, after going through their docs thoroughly and after having repetitive arguments with my colleagues, we finally found an explanation, an obvious and a simple one, yet it is still unnoticed to many!

How I deduce that reading this article was/is not at all a waste of time? (In fact, it might save you lump sum amount of time in the near future)

The answer to all the doubts lie in the title of this post. The Cloud Messaging strictly categorizes notifications into two different types, Notification Messages and Data Messages.

Let us at first grasp a brief knowledge about each of the two:

  • Notification Messages: These are the messages sent to the clients for the sole purpose of only generating notifications at the client side. It doesn’t care much about the data which is being sent as a JSON. Here, it is determined that the app doesn’t need to be waken up as the requirement is to just show the user a simple Notification. So, this is handled internally by the Google Cloud Messaging (or Firebase Cloud Messaging) and the notification is simply shown without incurring the overhead of waking up the FirebaseMessagingService and thus in turn, the onMessageReceived(RemoteMessage) method.
    A Notification Message’s JSON payload looks something like this:
{
"to" : "the-respective-device-token-goes-here",
"notification" : {
"body":"It is a notification message",
"title":"MyApp Notification"
}
}

In the above scenario, a Notification will be shown to the user with body as this It is a notification message and with title as MyApp Notification

  • Data Messages: These are the second kind of remote pushes whereby stress is laid on data specifically. This means that the client ought to examine the data pack before taking any action. So, in this case, in a straightforward manner, FirebaseMessagingServices wakes up and a call is received at the onMessageReceived(RemoteMessage). This is useful in the case where the type is necessary to create an intent with a particular activity and redirecting the user to that particular Activity on click of the same.
    A Data Message’s JSON payload looks simply like this:
{
"to" : "the-respective-device-token-goes-here",
"data" : {
"is_silent":false,
"type":"DataMessage",
"title":"MyApp Data",
"message":"It is a data message ",
"created_at":"2017-04-25T08:04:44.325+00:00"
}
}

Now, every last doubt has become self explanatory. While I was triggering notifications using the REST client, I did not focus on the JSON payload. It had data JSON object in it. But while sending the same through Firebase console, it was rendering it as notification and thus, the behaviour was like that. Once a data is received, FCM doesn’t blindly trigger the FirebaseMessagingService and its callbacks. It carefully monitors the object and if it feels that the app has to process the data, it triggers the callback to the respective method or else, it executes its own chunk of code to simply generate a notification with the desired title and body and thus the purpose is served without incurring the overhead of triggering a call to the onMessageReceived(RemoteMessage) .

There are cases where one needs to pass some data alongside the Notification but the sole purpose is to just generate a Notification. In that particular case, a separate concept has been coined as Hybrid Messages. These are basically Data Messages wrapped inside Notification Messages, meaning the execution procedure would be same as in case of Notification Messages, except for on click of the respective notification, the respective callback will be triggered (in our case, the onMessageReceived(RemoteMessage)) with the data packet.

A Hybrid Message’s JSON payload looks somewhat like this:

{
"to" : "the-respective-device-token-goes-here",
"notification" : {
"body":"It is a notification message",
"title":"MyApp Notification"
},
"data" : {
"is_silent":false,
"type":"DataMessage",
"title":"MyApp Data",
"message":"It is a data message ",
"created_at":"2017-04-25T08:04:44.325+00:00"
}
}

So that was pretty much of it! This is a dead simple concept yet it remains unboxed and dizzy to most of us. Hope you found it useful, if not, please forgive me and I’ll cover it up in my next read!

Note: For those who are not much familiar with generating notifications using Firebase console or a REST client, the following is for you :)

Sending Remote Message Using Firebase Console:

  • Make sure your App is registered as a Firebase Project (if not, create it from Android Studio using Tools -> Firebase -> Set it up by providing the basic details)
  • Open this Link(Firebase Console). Select your project. In the dashboard that opens up, Select Notification under the GROW section in the left hand side Navigation drawer.
  • Click on the button that says NEW MESSAGE
  • You would see something like this. ( Refer to attached picture Fig. 1 below). If you want to test it out, select Single Device and provide the Registration Token of the device.
Fig. 1: Firebase New Message Composing
  • [Any firebase project will have a device token. You can get a callback for the same if you extend the FirebaseInstanceIdService and override the onTokenRefresh() method. The code to get the token of the device is:
String refreshedToken = FirebaseInstanceId.getInstance().getToken();
  • After it is done, compose a message and body and click on send. If you want to have your custom JSON payload, click on the Advanced options and compose the same and send.
  • Once you click on SEND MESSAGE, the message will be sent.

Sending Remote Message using a REST client:

  • Use this URL: https://fcm.googleapis.com/fcm/send
  • Make a POST request. The POST params or the BODY of this request comprises of the JSON payload which you should be sending. There has to be a to field. In that field, paste the respective device token in which you would like to send the notification.
  • In the HEADERS, you would have to specify the following: Content-Type as application/json and Authorization as key=YOUR-APP-SERVER-KEY
    You can find the server key of your project from Firebase Console’s Project Settings. Switch to the Cloud Messaging Tab and Copy the Server Key or the Legacy Server Key.
    Below is an attached screenshot for specifying the header correctly:
Fig. 2: Specifying Headers for initiating request

That’s it. Have a nice day!

--

--

Anirban Bhattacharjee

I don’t know much about myself. And I like it that way. Coding, Cricket and Coffee thrills me and makes a good day better. Love to learn. Enough said :P