Android Push Notifications with Google Cloud Messaging

We’re all familiar with the notifications that we receive from various apps on Android (even other platforms like iOS) that keeps us informed about relevant and timely events that occur in the pertaining app. Like new chat messages from WhatsApp or Emails from Gmail or a new friend request on Facebook. They’re like alerts for any important events occuring inside the app when the user hasn’t or is not using it which is sort of obvious as one won’t keep an app open and stare at it for good.

So how is it achieved? Google provides a service called Google Cloud Messaging (GCM) using which we can send data to our users’ Android devices from our servers and even receive messages from the devices to our servers over the same connection. It handles queueing of messages and delivers to the target Android app on the device based on something called a registration ID. So using GCM, we can keep on sending data to our application on our user’s devices instead of making frequent requests to our servers at regular intervals that could be complicated to implement and even drain the battery big time if not properly executed. On receiving the data, your application can build notifications and how up in the status bar using the Notification Builder class.

What's the one thing every developer wants? More screens! Enhance your coding experience with an external monitor to increase screen real estate.

If you actually go through all the sections under the exhaustive GCM guide, you’ll actually learn everything you need to know and it is something I’d highly recommend. There’s no point rehashing their content as their version is already simple to consume, comprehensive and will keep on accomodating updates. So it should be the go-to place.

The idea behind this article is to concisely point out the important steps involved in implementing Push Notifications.

1. Getting Started (Initial Setup Steps)

The entire setting up process is already mentioned in the documentation. I’ll point out the important steps here.

Download and Setup Google Play services SDK

In order to use the GCM APIs which is a part of the Google Play services APIs, you’ll need to setup the Google Play services SDK as the first step.

Along with the SDK we will also need the Google Play Services APK. There’s a good amount of information available in the play store description, Google Play services introduction and also wikipedia but the general idea is in order to update Google Apps and access Google APIs like the GCM API in our case, we need the Google Play services app along with the SDK (client library that connects to the app).

Always check the device for a compatible Google Play services APK before accessing various features in the Google Play services.

Most probably you might not have the APK in your emulator (or Genymotion), so check out these stackoverflow links for further information on installation:

Create a Google API Project

In the Google Developers Console you’ll need to create a Google API project from where you’ll get various keys like the project number (SENDER_ID) and API Key required to send data through it.

Enable the GCM Service

You’ll have to enable the Google Cloud Messaging for Android service in order to start making use of your newly created app next.

Obtain Your API Key

API Key will be required for sending data, so you’ll have to obtain it.

2. Implementing GCM Client

A Google Cloud Messaging (GCM) Client is basically a GCM-enabled app that runs on an Android device. So this step is basically about how you have to write code in your android application so that it can act as a GCM client to which your servers can send messages through GCM and you can even send back messages on the same connection. Everything is covered in the Implementing GCM Client documentation which you should definitely read entirely. We’ll just sum up the steps involved in this section.

Edit Your Application Manifest

Once you’re done with all the initial setup that we discussed a while back, you’ll need to add certain details to the application’s manifest file as mentioned here. You can simply copy paste the code that you see in that section and make appropriate changes like replacing the sample package name (com.example.gcm) with your own.

For the record, there are certain things that I noticed like you can simply get rid of this snippet and your message broadcast events will get received just fine:

<permission android:name="com.example.gcm.permission.C2D_MESSAGE"
    android:protectionLevel="signature" />
<uses-permission android:name="com.example.gcm.permission.C2D_MESSAGE" />

Also the <category> tag mentioned inside the <receiver> tag seems unimportant as removing that doesn’t break the flow of broadcast reception:

<category android:name="com.example.gcm" />

That said, you can just keep those tags in the manifest file for the sake of adhering to the docs/standards I guess.

Writing Your Application

Rest of the details regarding how to register your android app for GCM and then start receiving and sending messages (even build notifications to show in status bar) lies in the Writing Your Application section. I’ll just try to explain the basic flow here.

Register for GCM

So obviously the Android app first checks for the Google Play services APK and as soon as that evaluates to true it registers for GCM using the GCM APIs by sending the SENDER_ID (project number that you get while creating the app in developers console). On registering you get a REGISTRATION_ID that you can cache using SharedPreferences for future use. You should also send it to your servers over HTTP where you store it and map against your user/member records so that you can use it later for the purpose of sending messages to apps/devices.

The REGISTRATION_ID is used to send messages by the servers to the apps so that GCM knows which apps on which devices to send the messages to while the SENDER_ID is used to send messages to the server (when using XMPP).

So how is a message handled when it is received by the Android device’s Google Play services APK from GCM ? So GCM sends the message to the correct app/device based on the REGISTRATION_ID specified by the sender. Then the Google Play services APK based on the SENDER_ID (or maybe the REGISTRATION_ID) sends a broadcast to our app with the com.google.android.c2dm.intent.RECEIVE intent. Now I’m not sure how the Play services app figures out which app to send the message broadcast to as it’s proprietary code but I’m just assuming that they maintain a mapping of SENDER_ID (or REGISTRATION_ID) to package name and use the package name in Intent.setPackage() but there’s no good way of knowing the exact implementation.

The entire code for registration purpose is right there in the documentation that you can copy-paste (modify a bit) and start using.

Writing the BroadcastReceiver

Now that you know that a broadcast is sent, you know we need to have this receiver tag in our XML manifest as mentioned in the previous section of editing your manifest file:

<receiver
    android:name=".GcmBroadcastReceiver"
    android:permission="com.google.android.c2dm.permission.SEND" >
    <intent-filter>
        <action android:name="com.google.android.c2dm.intent.RECEIVE" />
        <action android:name="com.google.android.c2dm.intent.REGISTRATION" />
        
        <category android:name="com.example.gcm" />
    </intent-filter>
</receiver>

If you don’t know much about Broadcast Receivers then read some of my previous articles first:

So once the broadcast event is received, it triggers GcmBroadcastReceiver (you need to create that class in your app). Ofcourse you could name it anything like MyReceiver too. Also important to note that it is constrained by the com.google.android.c2dm.permission.SEND permission. More on permissions in my broadcast receivers article (also linked above).

Based on the docs, the broadcast receiver should be a WakefulBroadcastReceiver. A WakefulBroadcastReceiver is a helper BroadcastReceiver that can receive a device wakeup event and then pass on the work to a Service ensuring that the device (CPUs) doesn’t go back to sleep while the Service is executing. It creates and manages a partial wake lock for your app. The service is started using startWakefulService() which is similar to startService() except that it holds/grabs a wake lock when the service starts, i.e., won’t let the device sleep until the wake lock is released. To release the wake lock, completeWakefulIntent() is called which accepts the same intent passed to startWakefulService() as an argument.

This is how the receiver will sort of look like (taken from the docs):

public class GcmBroadcastReceiver extends WakefulBroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        // Explicitly specify that GcmIntentService will handle the intent.
        ComponentName comp = new ComponentName(context.getPackageName(),
                MyService.class.getName());
        // Start the service, keeping the device awake while it is launching.
        startWakefulService(context, (intent.setComponent(comp)));
        // http://developer.android.com/reference/android/content/BroadcastReceiver.html#setResultCode(int)
        setResultCode(Activity.RESULT_OK);
    }

}

The Service (typically IntentService) code is also right there which shows up the data received in a notification using the Notification Builder class although you could do just anything with the data.

public class GcmIntentService extends IntentService {
    public static final int NOTIFICATION_ID = 1;
    private static final String TAG = "GcmIntentService";
    private NotificationManager mNotificationManager;
    NotificationCompat.Builder builder;

    public GcmIntentService() {
        super("GcmIntentService");
    }

    @Override
    protected void onHandleIntent(Intent intent) {
        Bundle extras = intent.getExtras();
        GoogleCloudMessaging gcm = GoogleCloudMessaging.getInstance(this);

        String messageType = gcm.getMessageType(intent);

        if (!extras.isEmpty()) {

            if (GoogleCloudMessaging.
                    MESSAGE_TYPE_SEND_ERROR.equals(messageType)) {
                sendNotification("Send error: " + extras.toString());
            } else if (GoogleCloudMessaging.
                    MESSAGE_TYPE_DELETED.equals(messageType)) {
                sendNotification("Deleted messages on server: " +
                        extras.toString());
            } else if (GoogleCloudMessaging.
                    MESSAGE_TYPE_MESSAGE.equals(messageType)) {
                Log.i(TAG, "Completed work @ " + SystemClock.elapsedRealtime());

                sendNotification(extras.toString());

                Log.i(TAG, "Received: " + extras.toString());
            }
        }
        // Release the wake lock provided by the WakefulBroadcastReceiver.
        GcmBroadcastReceiver.completeWakefulIntent(intent);
    }

    private void sendNotification(String msg) {
        mNotificationManager = (NotificationManager)
                this.getSystemService(Context.NOTIFICATION_SERVICE);

        PendingIntent contentIntent = PendingIntent.getActivity(this, 0,
                new Intent(this, MainActivity.class), 0);

        NotificationCompat.Builder mBuilder =
                new NotificationCompat.Builder(this)
                        .setSmallIcon(R.drawable.checkmark)
                        .setContentTitle("GCM Notification")
                        .setStyle(new NotificationCompat.BigTextStyle()
                                .bigText(msg))
                        .setContentText(msg);

        mBuilder.setContentIntent(contentIntent);
        mNotificationManager.notify(NOTIFICATION_ID, mBuilder.build());
    }
}

3. Implementing GCM Server

You’ve seen what all are required on the client-side to grab the messages coming from GCM and manipulate them. But the messages have to come from somewhere, which is going to be your server (3rd party application server) that’ll send messages to the GCM connection servers. So basically 2 components are involved on the server-side: Google’s GCM Connection Servers that receives messages from the 3rd party server and sends it to the Android app (client-side) and the 3rd party application server itself that sends messages to the devices via GCM connection servers. This third party server is generally yours where you maintain a record of all the registration IDs and other app data. You could either build your servers or use some PaaS models such as Parse.

Make sure you go through the documentation of Implementing GCM Server with CCS (XMPP) as well as HTTP. Basically the difference is GCM HTTP supports only downstream messages, i.e., cloud-to-device whereas CCS (XMPP) supports both downstream (cloud-to-device) and upstream (device-to-cloud) (imagine a chat messaging system where messages go both upstream and downstream).

In GCM HTTP’s approach, 3rd-party servers send JSON or plain text messages as HTTP POST requests to GCM servers and wait for a response, hence this mechanism and synchronous and blocking. On the other hand, CCS (XMPP) connects to Google infrastructure using a persistent XMPP connection to send/receive JSON (encapsulated in XMPP) messages to/from all their devices asynchronously.

Make sure to go through these documentation links for further information like the request and response JSON parameters, setting up XMPP on your 3rd party servers, etc.:

For testing purposes, here’s a simple bash script that I wrote to quickly test HTTP POST requests that’d send messages to my android device/app.

#!/bin/bash

api_key="API_KEY"

reg_id="REGISTRATION_ID"

curl --header "Authorization: key=$api_key" --header Content-Type:"application/json" https://android.googleapis.com/gcm/send  -d "{\"registration_ids\":[\"$reg_id\"],\"data\":{\"name\":\"Rishabh Android Push Notificaiton\"}}"

User Notification Keys

A single user might have the same app installed on multiple devices. So in order to solve the problem of sending a single message to all those multiple instances of an app running on multiple devices owned by the same user, we can map all the registration IDs (represents a particular Android app running on a particular device) to a single notification key that’ll be generated by GCM.

You should go through the entire documentation of User Notifications to learn how to generate a notification key either on your 3rd party server or on the client (Android app) and then add/remove registration keys to them. Finally you’ll learn how to send messages to a particular notification key which is similar to how you send to registration IDs.

Here’s an example cURL request that generates a notification key for a particular registration ID:

#!/bin/bash

api_key="API_KEY"

reg_id="REGISTRATION_ID"

project_id="SENDER_ID" # The project number

curl --header "Authorization: key=$api_key" --header Content-Type:"application/json" --header "project_id:$project_id" https://android.googleapis.com/gcm/notification  -d "{\"registration_ids\":[\"$reg_id\"],\"operation\":\"create\",\"notification_key_name\":\"unique_username_id\"}"

It should give you an output like this:

{"notification_key":"NOTIFICATION_KEY"}

Advanced Topics

There are some important information on Advanced Topics covered in the documentation that you must read.

Summary

The motive behind this article was to sum up the flow and mostly link to the documentation URLs as they have all the information required and will obviously update with changes.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download

Author: Rishabh

Rishabh is a full stack web and mobile developer from India. Follow me on Twitter.

One thought on “Android Push Notifications with Google Cloud Messaging”

Leave a Reply

Your email address will not be published. Required fields are marked *