651.288.7000 info@intertech.com

Push Notifications Tutorial for Android using Google Cloud Messaging (GCM)

by | Oct 14, 2015

push-notification-seriesThis post is part of a series written by our developers that documents their journey in a cross-platform mobile app development project. They set out to improve an internal process, create educational content for the developer community, and explore new craft beers and a vintage arcade. Sound interesting? Read more about this series and their efforts in our introductory series post.

It is common for mobile applications to act as a client in client/server systems.  In that scenario, it is often useful to notify the client of certain events (such as when a new message has been received on the server), and it is convenient to have a way for the server to communicate this information to the client without requiring the client to request it.  This type of communication is called a push notification.  This push notifications tutorial describes how to configure an Android application to receive push notifications via Google Cloud Messaging (GCM), in conjunction with an application server (see blog post on writing server application).

This push notifications tutorial assumes that Android Studio is used as the IDE, with a target device running Android 4.0.4 or higher.

Google Cloud Messaging (GCM)

GCM is a service provided by Google that helps developers implement push notifications in their applications.  By using GCM, developers are not required to implement their own method for sending data from their server to the client applications.

GCM Overview
Your App server -> GCM -> device running your client application

Both the app server and Android client need to register with GCM and provide information to uniquely identify and authorize them.  Your Android app will need a Sender ID, and your server will need an API key, both of which can be obtained using the Google Developers Console.

Configuring the Project in Google Developers Console

If you haven’t already, create a project in the Google Developers Console.  The project number is the sender ID that you will use to register in your client application.

gdc_project01

To get an API key, select APIs under APIs & Auth, and find Google Cloud Messaging for Android:

gdc_project02

Follow the link for Google Cloud Messaging for Android, and click Enable API:

gdc_project03

Once enabled, select Credentials under APIs & Auth, click Create New Key, and select Server Key:

gdc_project04

The following screen will allow you to create the key, which should then be displayed on the Credentials page.  Use this key in your server application to communicate with GCM.  For more information, see blog post for implementing push notifications on an application server.

Configuring your Android Application

The next step is to configure your application.  This involves these steps:

  • Import configuration file (which contains the sender ID)
  • Add Google Play Services
  • Update Manifest

Import Configuration File

As an alternative to hard coding the sender ID (project number) in your application, you can use Google Developers Console to generate a configuration file, and use the Google Services plugin for Gradle to get that information into your project.  To do so, follow these steps:

  1. Use this link to generate and download the configuration file.  Place the file in your app folder in Android Studio (the same folder that contains your app specific build.gradle file)
  2. Add the Google Services plugin to your project level build.gradle file:
    classpath ‘com.google.gms:google-services:1.3.0-beta1’
  3. Apply the plugin by adding this line to your app specific build.gradle file:
    apply plugin: ‘com.google.gms.google-services’

Instead of the above steps, you could simply hard code the sender ID into your source code when you register the device with GCM.  This is simpler, however if your application uses other Google services, importing the configuration file may be a benefit in the long run.

Add Google Play Services

GCM requires Google Play Services, so make sure that you have the Google Play services SDK installed.  In Android Studio, open the SDK manager (Tools -> Android -> SDK Manager).  Under SDK Tools, look for Google Play services, and install if necessary.

With the SDK Tools installed, you can add a dependency to your project, for example:
compile ‘com.google.android.gms:play-services-gcm:7.5.0’

Update Manifest

Next step is to update your application’s manifest.  Your application will need certain permissions:

  • android.permission.INTERNET
  • android.permission.WAKE_LOCK
  • com.google.android.c2dm.permission.RECEIVE
  • applicationPackage + .permission.C2D_MESSAGE

The last permission may look a little funny.  This is a special permission that is specific to your app, which you define in your manifest.  If your package name is com.something.app, you would define this permission as follows:

<permission android:name="com.something.app.permission.C2D_MESSAGE" android:protectionLevel="signature" />

Then declare that you use this permission like this:

<uses-permission android:name="com.something.app.permission.C2D_MESSAGE" />

Next, you’ll need to declare a receiver and two services:

  • A GcmReceiver, with permission com.google.android.c2dm.permission.SEND.  You do not need to write and code for this, it is provided by Google
  • A Service that extends GcmListenerService.  This is a class that you write that will override onMessageReceived, which handles incoming messages
  • A Service that extends InstanceIDListenerService.  This is a class that you write that will override onTokenRefresh, which is called when your device’s GCM registration needs to renewed

The relevant portions of the manifest would look something like this:

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
<permission android:name="com.something.app.permission.C2D_MESSAGE" android:protectionLevel="signature" />
<uses-permission android:name="com.something.app.permission.C2D_MESSAGE" />

<receiver
    android:name="com.google.android.gms.gcm.GcmReceiver" android:exported="true"
    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.something.app" />
    </intent-filter>
</receiver>
<service
    android:name="com.something.app.MyIntentService" android:exported="false" >
    <intent-filter>
        <action android:name="com.google.android.c2dm.intent.RECEIVE" />
    </intent-filter>
</service>
<service
    android:name=“com.something.app.MyIDListenerService" android:exported="false">
    <intent-filter>
        <action android:name="com.google.android.gms.iid.InstanceID"/>
    </intent-filter>
</service>

Write the Code

We can now begin coding.  The first thing we need to do is register with GCM to get a registration token and provide that to our server.  This token uniquely identifies an Android device, and our server will use it to send messages to that specific device.  The code to register is straightforward:

InstanceID instanceID = InstanceID.getInstance(context);
String token = instanceID.getToken(context.getString(R.string.gcm_defaultSenderId), GoogleCloudMessaging.INSTANCE_ID_SCOPE, null);
//send token to app server
  • Note: gcm_defaultSenderId is not defined in any of our resource files.  This value is in the play-services.json file that was created and downloaded earlier, and is made accessible via the Google Services plugin.  If you chose not to install the configuration file, you can use the hard coded sender ID as the first parameter to getToken

Keep in mind that the above code uses network resources and should not be run on the main thread; you should use your preferred technique for executing background tasks on Android (Service, AsyncTask, etc).

Once you have a token, send it to your application server to complete the registration process.  The client/server communication is specific to your application, and is thus not covered here.

Our Android client is now registered with GCM, and our server can begin sending messages to devices running our client using the provided API key and GCM registration token.  Messages for our Android application are received by the GcmReceiver that we declared in our Manifest.  This class is provided by Google, so we don’t need to write any code for it.  When a message is received from our app server, the GcmReceiver will start our GcmListenerService.  This is were we write code to process the messages.  Here is a basic example that displays the message as a notification:

public class GcmIntentService extends GcmListenerService {
    @Override
    public void onMessageReceived(String from, Bundle data) {
        String message = data.getString("message");
        NotificationManager notificationManager= (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
        NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this)
                .setSmallIcon(R.drawable.ic_launcher)
                .setContentTitle("Test")
                .setContentText(message);
        notificationManager.notify(1, mBuilder.build());
    }
}


In addition to the GcmListenerService, there is another service that we need to implement: InstanceIDListenerService.  If you look back at the manifest, you will see that we declared two permissions for the GcmReceiver: com.google.android.c2dm.intent.RECEIVE and com.google.android.c2dm.intent.REGISTRATION.  Messages that originated from our app server will have the RECEIVE intent and will start our GcmListenerService.  If the message is for REGISTRATION, then the InstanceIDListenerService will be started and the onTokenRefresh() method will be called.  When exactly does this occur?  According to the documentation:

  • Called when the system determines that the tokens need to be refreshed. The application should call getToken() and send the tokens to all application servers.
  • This will not be called very frequently, it is needed for key rotation and to handle special cases.

What we really care about is that when this method is invoked, we need to get a new token from GCM, and send it to our app server:

public class GcmIDListenerService extends InstanceIDListenerService {
    @Override
    public void onTokenRefresh() {
          InstanceID instanceID = InstanceID.getInstance(context);
          String token = instanceID.getToken(context.getString(R.string.gcm_defaultSenderId), GoogleCloudMessaging.INSTANCE_ID_SCOPE, null);
          //send token to app server
    }
}


There is one final issue we need to be concerned with when using Google Play Services: the device may not have Play Services installed/enabled, or the device may not be compatible with Play Services.  GooglePlayServicesUtil provides methods for making that determination and notifying the user.

import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GooglePlayServicesUtil;
...
int resultCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable(context);
if (resultCode != ConnectionResult.SUCCESS) {
    if (GooglePlayServicesUtil.isUserRecoverableError(resultCode)) {
          //Play Services is not installed/enabled 
        GooglePlayServicesUtil.showErrorNotification(resultCode, context);
    } else {
        //This device does not support Play Services
    }
}

If Play Services is not available but can be installed or enabled, the above code will show a notification, which when clicked will prompt the user to download Play Services or enable it in the device’s system settings.  GooglePlayServicesUtil also has a method named getErrorDialog() which will show a dialog instead of a notification.  Which one to use depends on your application.  If Play Services is critical to the functioning of your app, it may be more appropriate to display the dialog.  If it is not essential, then it may be more appropriate to show the notification instead.  Using the notification is often more convenient because it doesn’t require a reference to an Activity, making it easy to call from a background task or service.

Wrap up

Your Android application is now ready to receive push notifications from your server.  For more information, please see our blog on implementing the server application.

Looking for training in mobile development? Check out the mobile development courses that we have available!

Intertech also provides Mobile Development Consulting. From to to Windows phone, we can help you build the app that your company needs.

 

More Push Notification tutorials in this series:

[et_bloom_locked optin_id=optin_4]

DOWNLOAD PDF NOW

[/et_bloom_locked]