Push notifications using Firebase Cloud Messaging

18 / Aug / 2016 by Apurv Pandey 1 comments

Assuming that you are familiar with Google Cloud Messaging, the new word for you in the title “FirebaseCloudMessaging” is Firebase.

In case you don’t know about Firebase, let me give you a brief idea about it. Firebase is a cloud service provider, provided by Google, which provides Mobile backend as a service (MBaaS), also known as “backend as a service” (BaaS). Using Firebase, you can quickly sync up your data and make it available it on your app, which is being used by multiple users.

Now, since it is being used by multiple users, how does Firebase individualizes multiple users? Here comes the role of “authentication” (mechanism of providing identification to each user) by Fireabase. Since authentication plays a vital role while sending push notifications, let me brief you about it as well.

What is authentication and role of FireBase in it?

Generally applications need to know the identity of their user. Being aware of user’s identity allows android apps to provide them a customized experience and grant them permissions for accessing their data. This process of proving a user’s identity is called authentication. Firebase provides a full set of authentication options.

When a user authenticates to a Firebase app :

  • Information about the user is returned in callbacks on the client device. Using this we can customize our app’s user experience, according to specific user.
  • This user information returned contains a uid (a unique ID), which is distinct across all providers, and it never changes for a specific authenticated user.
  • Now, in our app’s security & Firebase rules, value for the authToken becomes defined. Its value will be null for unauthenticated users. However, for authenticated users it will an object containing auth.uid (unique for every user) and some other informational data about the user. Using this, we can securely control data access on a per-user basis.

What is FCM?

Firebase Cloud Messaging (FCM) provides cross-platform messaging solution that allows reliable delivery of messages at no cost. Using this we can :

  • Send notification messages (2KB limit) or data messages (4KB limit).
  • Distribute messages to a single device, groups of devices, or to devices subscribed to some topics.
  • Send acknowledgments, chats, and other messages from devices back to the server over FCM’s reliable and battery-efficient connection channel.

Using Notification messages, developers can send users a visible display message with some predefined keys and optional custom key-value pairs (data payloads).

Apart from this, what more Google has to say about FCM?

If you go to URL – https://developers.google.com/cloud-messaging/  to learn about GCM,
the very first lines that will strike you are :

Firebase Cloud Messaging(FCM) is the new version of GCM. It inherits the reliable and scalable GCM infrastructure, plus new features! If you are integrating messaging in a new app, start with FCM. GCM users are strongly recommended to upgrade to FCM, in order to benefit from new FCM features today and in the future.

As you can deduce from this statement, Google is investing strongly in Firebase, to make it one unified mobile platform.

Lets clear few points before proceeding further :

How is FCM similar to GCM?

Both can be used to send messages to multiple platforms – Android, iOS and Chrome, as their core structure is same.

How is FCM different from GCM?

  • Unlike GCM integration, we don’t have to write our own registration or subscription retry logic.
  • We no longer have to explicitly declare “Receiver”.
  • Generation of registration token is handled by the library itself. We don’t have to initiate it explicitly.
  • It provides server-less notifications solution with a web console – Firebase Notifications. This web console will remind you of Parse Push Console (if you have used it).

So is GCM going to be deprecated ?

No. However, some features of GCM are already depreciated. Like – Obtaining Registration Tokens with gcm.register() is deprecated now. So, in coming days some other functions may also get depreciated. However, they will support the current version of GCM Android and iOS SDKs. All new client-side features will be added to FCM SDKs only.

Prerequisites for using FCM

  • Device running on Android 2.3 (Gingerbread) or newer version, along with Google Play services 9.2.1 or newer.
  • Android Studio 1.5 or higher version.
  • An Android Studio project and its package name.

Steps for Integrating Firebase and FCM SDK

  1. Add Firebase to your app

Go to Firebase console and either create a new project or import an existing one. After creating or importing your project, a welcome screen will open; like below.

firebase 10

As I’m into Android, I’ll be adding Firebase to my Android app. However, steps for Android, iOS and Web app are almost same.

Click on Add Firebase to your app.

firebase12

Add package name by copying it from AndroidManifest.xml file and get SHA-1 key by using below command :

$ keytool -exportcert -alias androiddebugkey -keystore ~/.android/debug.keystore -list -v

It may ask for keystore password: Type “android” if using debug.keystore. After entering required information click on Add App. Now it’ll ask you to save downloaded google-services.json file. Save it in the root of app folder of your app. Next, you’ll be asked to add the following dependencies to your gradle file for accessing Firebase SDKs.

firebase14

Instead of adding complete client SDK, you should add dependencies for the Firebase SDKs you wish to use. Like in our case, its

compile ‘com.google.firebase:firebase-messaging:9.2.1′

Sync your project.
If you are getting a build error complaining about duplicate files you can choose to exclude those files by adding the packagingOptions directive to your build.gradle file, inside the android domain:

packagingOptions{
exclude ‘META-INF/LICENSE’
exclude ‘META-INF/LICENSE-FIREBASE.txt’
exclude ‘META-INF/NOTICE’
exclude ‘LICENSE.txt’
}

Click on finish and you are done. Firebase is added to your app now.

Now let us first understand how Firebase works ?

Client app registration process – 

Client registration process

Send notifications using FCM

Sending notification

Message received in the form of notification

Since, you have understood by now how FCM works, lets begin some coding.

  1. Add internet permission to your manifest file.                                                                                                                <uses-permission android:name=“android.permission.INTERNET” />
  2. Now we need to add a service that extends FirebaseMessagingService. This is the Base class for communicating with Firebase Messaging. This FirebaseMessagingService extends Service class. Class hierarchy followed is :                                        

firebase4

This class provides various functionalities :

  • automatically displaying notifications.
  • message handling beyond receiving notifications on apps in the background.
  • receive notifications in foregrounded apps
  • receiving data payload
  • sending upstream messages
  • receiving errors in case of upstream message failures.

To handle any type of events required by the application, we need to override this base class methods. These methods are invoked on a background thread. To add this service include following to your manifest file :

Firebase 5

3. Now we need to add a service that extends FirebaseInstanceIdService. This is the Base class to handle Firebase Instance ID token refresh events. This FirebaseInstanceIdService extends Service class.

Class hierarchy followed is :

1 java.lang.Object
2 ↳android.content.Context
3 ↳android.content.ContextWrapper
4 ↳android.app.Service

It provides various functionalities :

  • Creation of registration tokens
  • Rotation of registration tokens
  • Update process of registration tokens
  • Sending notification to a single device or group of devices
  • Allows devices to subscribe to various topics with the server subscription management API.

If your app requires Instance ID or uses Instance ID tokens, then we can extend this class and implement onTokenRefresh() to receive token refresh events. To add this service include following to your manifest file :

Firebase 6

Now create the respective service classes in your Android code.

Retrieving & monitoring of device registration token

On initial startup of our app, the FCM SDK will generate a registration token for the client app instance. If we want to target a single device or create device groups, we’ll need this token which can be retrieved from our MyFirebaseInstanceIDService class. This token could be rotated or changed after initial startup. So, I would strongly recommended you to fetch the latest updated registration token using   FirebaseInstanceId.getInstance().getToken() ;   unless you specifically need to retrieve the current token. So to retrieve the token, simply override onTokenRefresh() as  below:

Firebase 7

If the system determines that the token needs to be refreshed, then this callback is called. Once the token is retrieved, you can save it to your server and store it using your required method. This will not be called very frequently. It is needed for key rotation and to handle Instance ID changes; which happens in following cases:

  • When app deletes Instance ID
  • When app is restored on a new device
  • When user re-installs or uninstalls the app
  • When user deletes the app data

If you have specific need to retrieve current token call call FirebaseInstanceID.getToken(). It returns null if the token has not yet been generated.

Once this is set up we are ready to start sending downstream messages with the Firebase
console . (Downstream messages means sending messages from your app server to Firebase Cloud Messaging client apps). However, lets skip that part for now. Let us first understand how to handle received messages on client side, otherwise some users may not receive the notifications we send. This includes any users who have your app in the foreground on the device.

Receiving and handling messages

In order to receive messages, we have to override the onMessageReceived() callback from our FireBaseMessagingService class; keeping in mind the exceptions mentioned below :

  • Notifications delivered when your app is in the background – In this case, notification is delivered to the system tray of the device. A user’s tap on a notification opens the app launcher by default.
  • Messages with notification + data payload - In this case, the notification is delivered to the device’s system tray, and data payload is delivered in the extras of the intent of your launcher Activity.

Firebase 8

This is also called if any notification message is received while user is interacting with the app i.e. app is in the foreground. To fetch notification parameters use getNotification() method.If we need to perform some action based on the message received and access message data, we will have to override this method.

How to send a message from the FireBase console?

  1. Install and run the app on the target devices.
  2. Open the Notifications tab of the Firebase console and select New Message.
  3. Enter message text.
  4. Select the message target (devices). The dialog displays further advanced options to filter the target devices by allowing you to choose from App Version, Users in Audience or Device Language.
FireBase console to send messages

FireBase console to send messages

Once you click Send Message button, client devices you targeted, that have the app in the background, will receive notification in the system notifications tray. Whenever the user will tap on the notification, the app launcher will open up your app. If you want to send a message to a particular device: select “Single Device” from options available and insert the token you received.

Various other advanced options are available which you can explore yourself by playing around with them like :

  • the expiration period
  • play a sound when the notification is received
  • Setting custom data with some message
  • setting the notification priority – normal or high

Normal priority – This is the default priority for message delivery. These messages do not open up network connections if your device in is “Doze mode”, and their delivery is delayed to preserve the battery.

High priority – FCM delivers high priority messages immediately, permitting the FCM service to wake a device which is in “doze mode” when possible and open a network connection to your app server. Apps which have features like instant messaging, chat, or voice call alerts, generally need to open a network connection to make sure that FCM delivers the message to the device without any delay. Set messages to high priority only when your message is time-critical and it requires immediate response from the user. However, keep in ind that setting your messages to high priority contributes more to battery consumption compared with normal priority messages.

Limitations of Firebase Notifications :

Handling of messages when app is in the background.

There are two types of messages in FCM :

1. notification messages = display-messages :

These messages are displayed automatically when the app is in background. These are delivered to the notification tray . When the user taps on the notification, it opens up the app launcher, which is default process. This also applies for messages that contain both notification and data payload. However, If the app is already in foreground only then FirebaseMessagingService.onMessageReceived() is called.

2. data messages (custom key-value pairs):

These messages are also automatically displayed when the app is in background and FirebaseMessagingService.onMessageReceived()is not invoked. These are delivered to the notification tray . If the app is already in foreground, only then FirebaseMessagingService.onMessageReceived() is called. In this case, data message are received in onMessageReceived() and client can handle the key-value pairs accordingly.

Firebase team have developed a UI to send data-messages to the devices. However, this data could not be received at your end. Hence, firebase console should not be used for data-messages.

So, if you want to process the messages arrived in the background, you have to send ‘click_action’ with message. click_action is a parameter of the notification payload. However, it is not possible while sending messages from Firebase console, but only via Firebase API. click_action indicates the action associated when the user clicks on the notification. If this is defined, then the activity with a matching intent filter is launched when user clicks the notification.

How to achieve this ?

1. Go to your AndroidManifest.xml. Go to the activity you want to open on
click of notification. Set its intent filter as below –
<intent-filter>
<action android:name=”com.ttnd.fcmtest.OPEN_ACTIVITY_1″ />
<category
android:name=”android.intent.category.DEFAULT” />
</intent-filter>
2. Get a RESTClient – RESTClient
3. Send an HTTP POST Request to the URL mentioned below :
Firebase Cloud Messaging HTTP Protocol
4. Set Headers – Key : Content-Type, Value : application/json
Key : Authorization, Value: key=< your-server-key >

5. Body :

{
“to”: “< registration token>”,
“notification”: {“body”: “Exciting match!”,
“title”: “India vs. Pakistan”,
“click_action”: “com.apurv.fcmtest.OPEN_ACTIVITY_1″
},
“data”: {
“custom_key”: “custom_value”,
“Match”: “IndiaVSPakistan”
}
}

6. Click on Send Button. You’ll receive message with data payload.
You can access this data in the onCreate() of your respective Activity.

Voilà…..you are done!!

Enjoy FCM.

Below are some useful links for various operations :

 

FOUND THIS USEFUL? SHARE IT

comments (1 “Push notifications using Firebase Cloud Messaging”)

  1. DreamAs

    Thanks for this post. It is awesome. This post helps me understand more about firebase messaging.
    I have a question when the app is in the background, we use FirebaseAPI with the body.
    5. Body :

    {
    “to”: “”,
    “notification”: {“body”: “Exciting match!”,
    “title”: “India vs. Pakistan”,
    “click_action”: “com.apurv.fcmtest.OPEN_ACTIVITY_1″
    },
    “data”: {
    “custom_key”: “custom_value”,
    “Match”: “IndiaVSPakistan”
    }
    }
    We send the message to the device that matching registration token.
    How to send the message to all devices?
    Thanks in advance.

    Reply

Leave a comment -