Firebase Push Notification Implementation in Android and App Server

Introduction

I am going to introduce FCM (Firebase Cloud Messaging) implementation in Android app as well as in server side. FCM is a new, improved version of the Google Cloud Messaging (GCM). It has all the features of GCM as well as some additional features.

Android side Implementation (Part 1 – Registration of app)

1 . Add Firebase to your Android project

  1. Add the Android project to Firebase console. If you already have existing Google project associated with your mobile app, click Import Google Project else Create New Project.
  2. Click Add Firebase to your Android app and follow the setup process.
  3. At the end, you will download google-services.json file. You can download this file again at any time.
  4. Move the google_services.json file you just downloaded into your Android app module root directory.

move google_services.json

2. Add Firebase SDK in Android Project in Android Studio

  1. Add rules to your root – level build.gradle file to include the google – services plugins.
  2. Then, in your app-level gradle file (app/build.gradle), add apply plugin line at the bottom of the file to enable the Gradle plugin:

gradle file

In Android Studio, add the FCM dependency to your app-level build.gradle file:       

dependencies 
{
  compile fileTree(dir: 'libs', include: ['*.jar'])
  testCompile 'junit:junit:4.12'
  compile 'com.android.support:appcompat-v7:24.2.0'
  compile  ‘com.google.firebase:firebase-messaging:10.0.1’
}

3 . Android code setup for device registration

  1. Create a service that extends FirebaseInstanceIdService to handle the creation, rotation, and updating of registration tokens. This is required for sending to specific devices or for creating device groups.
  2. Add service declaration in app Manifest file.
<service
 android:name=".MyFirebaseInstanceIDService">
  <intent-filter>
       <action android:name="com.google.firebase.INSTANCE_ID_EVENT"/>
  </intent-filter>
</service>

 Get the device registration token

  1. If the device doesn’t have a compatible version of Google Play services, your app can call GoogleApiAvailability.makeGooglePlayServicesAvailable() to allow users to download Google Play services from the Play Store.
  2. onTokenRefresh() callback fires whenever a new token is generated. On calling getToken() of FirebaseInstanceId you will get a currently available registration token. You can send this to your server.
@Override
public void onTokenRefresh() 
{

  // Get updated InstanceID token.

    String refreshedToken = FirebaseInstanceId.getInstance().getToken();
    Log.w(TAG, "Refreshed token: " + refreshedToken);

  // If you want to send messages to this application instance or
  // Instance ID token to your app server.

   sendRegistrationToServer(refreshedToken);
  }

Server side Implementation

Infrastructure and Flow of Messages

There are 2 Entities involved here – FCM Server and Application Server

FCM Server

FCM connection servers are provided by Google. These servers take messages from an app server and send them to a client app running on a device. Google provides connection servers for HTTP and XMPP.

Application server 

App server sends data to a client app via the chosen FCM connection server, using the appropriate XMPP or HTTP protocol.

Message Flow from Application server to Application on mobile device via FCM Servers

firebase-cloud-messaging

Send messages to specific device

Implementation of HTTP connection                         

  1. First issue a HTTP GET request to receive user device REGISTRATION TOKEN along with User_Id to differentiate particular user among all users.
  2. To send a notification message , issue a HTTP POST request. This will hit the FCM server url.  https://fcm.googleapis.com/fcm/send
  3. This request consist two parts : HTTP header and body:

HTTP header

Header must contain following header:
(i) Authorization: key= YOUR_SERVER_KEY

(You may use your legacy server key.   To get this Click Firebase Console —> Project Name —-> Cloud Messaging Tab (you will get your server key) )

screenshot-16

(ii) Content-Type: application/json for JSON; application/x-www-form-urlencoded;charset=UTF-8 for plain text. 

If Content-Type is omitted, the format is assumed to be plain text.

HTTP Body

  • To send message to specific devices , set “to”  key to the registration to token for the specific app instance.

HTTP POST Request (final structure)

https://fcm.googleapis.com/fcm/send
Content-Type:application/json
Authorization:key=AZVHGDG-7726:FE663RFT44R4

{ 
"data": 
  {
  "score": "r5t5t",
   "time": "15:26"
  },
"to" : "fhtryvu78647f457f356c65v75uvb76b87bu87.."
}

Send messages to device groups

Basically Group refers as a set of different devices. All devices in a group share a notification key, which is the token that FCM uses to send messages to all devices in that group.

The limit on data payload is 2KB when sending to iOS devices, and 4KB for other platforms. The maximum number of members allowed for a notification_key is 20.

1. Manage device groups

  • First get all registration tokens which you want to add in a group.
  • Create a Notification_key , which indicate the device group. You can generate this notification_key on App server as well as on your Android client app.
  • You can remove, create, and update devices in a particular group.

2. Create device groups

  • To create a device group, send a POST request that provides a name for the group, and a list of registration tokens for the devices. FCM returns a new notification_key that represents the device group.
  • Send a request like  https://android.googleapis.com/gcm/notification

HTTP POST Request

https://android.googleapis.com/gcm/notification
Content-Type:application/json
Authorization:key=API_KEY
project_id:SENDER_ID
{
   "operation": "create",
   "notification_key_name": "appUser-Chris",
   "registration_ids": ["4", "8", "15", "16", "23", "42"]
}
  • The notification_key_name and notification_key are unique to a group of registration tokens.It is important that notification_key_name is unique per client app if you have multiple client apps for the same sender ID.

Response Format

A successful request returns a notification_key like the following:

{

  "notification_key": "HFDSGFJHGR...735735FGFHGFJGKHGGGG"

}
  • Save the notification_key and the corresponding notification_key_name to use in subsequent operations.

3. Sending downstream messages to device groups

  • Sending messages to a device group is very similar to sending messages to an individual device. Set the to parameter “to” the unique notification key for the device group.

 HTTP POST Request

https://fcm.googleapis.com/fcm/send
Content-Type:application/json
Authorization:key=AIzaSyZ-1u...0GBYzPu7Udno5aA
{
 "to": "aUniqueKey",
 "data":
 {
   "hello": "This is a test message for Firebase Cloud Messaging Device Group Message!",
 }
}

Android side Implementation (Part 2 – Receiving Push Notification)

A service that extends FirebaseMessagingService. This is required if you want to do any message handling beyond receiving notifications on apps in the background ,to receive notifications in foregrounded apps, to receive data payload, to send upstream messages, and so on, you must extend this service.

Add the following code to your app’s manifest:

<service
      android:name=".MyFirebaseMessagingService">
    <intent-filter>
          <action android:name="com.google.firebase.MESSAGING_EVENT"/>
    </intent-filter>
</service>

Code Sample for receiving notification and generate local notification:

public class MyFirebaseMessagingService extends FirebaseMessagingService

{

private static final String TAG = "MyFirebaseMsgService";

 @Override
  public void onMessageReceived(RemoteMessage remoteMessage)
         {
             super.onMessageReceived(remoteMessage);

           // TODO(developer): Handle FCM messages here.
           // Not getting messages here? See why this may be: https://goo.gl/39bRNJ

          Log.d(TAG, "From: " + remoteMessage.getFrom());

          // Check if message contains a data payload.

          if (remoteMessage.getData().size() > 0) {
            Log.d(TAG, "Message data payload: " + remoteMessage.getData());

          }


    // Check if message contains a notification payload.

      if (remoteMessage.getNotification() != null) 
      {
        Log.d(TAG, "Message Notification Body: " + remoteMessage.getNotification().getBody());
       sendNotification(remoteMessage.getNotification().getBody());

       }

      // Also if you intend on generating your own notifications as a result of a received         FCM
     // message, here is where that should be initiated. See sendNotification method below.
      }

     // [END receive_message]


  /**

   * Create and show a simple notification containing the received FCM message.

   *

   * @param messageBody FCM message body received.

   */


  private void sendNotification(String messageBody) {

      Intent intent = new Intent(this, MainActivity.class);

      intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);

      PendingIntent pendingIntent = PendingIntent.getActivity(this, 0 /* Request code */, intent,

              PendingIntent.FLAG_ONE_SHOT);



      Uri defaultSoundUri= RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);

      NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this)

              .setSmallIcon(R.drawable.ic_launcher)

              .setContentTitle("FCM Message")

              .setContentText(messageBody)

              .setAutoCancel(true)

              .setSound(defaultSoundUri)

              .setContentIntent(pendingIntent);

    NotificationManager notificationManager =

              (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);

    notificationManager.notify(0 /* ID of notification */, notificationBuilder.build());

  }

 

Leave a Reply