Push Notifications Tutorial for Android using Google Cloud Messaging (GCM)
This 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.
To get an API key, select APIs under APIs & Auth, and find Google Cloud Messaging for Android:
Follow the link for Google Cloud Messaging for Android, and click Enable API:
Once enabled, select Credentials under APIs & Auth, click Create New Key, and select Server Key:
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:
- 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)
- Add the Google Services plugin to your project level build.gradle file:
classpath ‘com.google.gms:google-services:1.3.0-beta1’ - 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 permissioncom.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 overrideonMessageReceived
, which handles incoming messages - A Service that extends
InstanceIDListenerService
. This is a class that you write that will overrideonTokenRefresh
, 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]
Do you have a sample working project about this sir? Would you be able to send me a zip copy of it? Thank this is my email altamagna88@gmail.com
Hi Christian, I do not have a sample project, as it is not very
practical in this case. In order for a sample to work, you would need a
project in Google Developers Console, as well as a custom application
server.
sir i didn’t find any blog on related with how to implement on server, this blog is only for app side?
Hi Dustin. Is this tutorial updated according to the latest version of gcm classes and Google Play Services? I am asking this because you wrote this article in October 2015, and as you know Google keeps updating these things, and all previous used classes get deprecated.
Thank you.
Hi Aman. I am currently using Play Services 8.3, and the method described in this post works fine. 8.4 was released in December, but I am not aware of any changes that would make this obsolete.
Hi Dustin,
I can’t able to understand the GCM after reading so many tutorials. Most of the tutorials found complex for me. Finally after reading your blog I got clear understanding of GCM basics and even implemented a sample app. Since I am not well versed with the server side I used this site http://apns-gcm.bryantan.info/ to check the working and it works well. Good Job (y)