Introduction
Getting users to install your app is only half the battle. Getting them to use it regularly is the other half. It is quite possible that your users completely forget about your app after using it only once or twice. What with all the other new apps competing for their attention.
By using push notifications, you can remind users about your app every now and then, improving the chances of your app staying installed on their devices.
Google Cloud Messaging, GCM for short, is a free service you can use to send push notifications to your users. In this tutorial, you learn how to use it to create an Android app that can receive push notifications, and a simple server-side Python script that can generate and send them.
Why Use Google Cloud Messaging?
For most client-server communications, the client initiates requests to receive data from the server. In other words, the client pulls data from the server. In the case of push notifications, however, it is the server initiating the data transfer.
This is usually accomplished by maintaining a persistent TCP/IP connection—a connection that stays open indefinitely—between the server and the client. That might sound great, but if you have a popular app, maintaining thousands of persistent connections between your server and the devices of your users can be very expensive.
Google Cloud Messaging is a service that solves this problem by acting as an intermediary between your server and your user’s device. With GCM, Google’s Cloud Connection Server, often referred to as CCS, manages the persistent connections for you. It also makes sure that your push notifications are delivered securely and reliably.
Prerequisites
To follow along with me, you need:
- the latest version of Android Studio
- Python 2.7.6 or higher
- a device running Android 4.4 or higher with Google Play Services installed
1. Setting Up the Android Studio Project
Fire up Android Studio and create a new project with an empty Activity
. If you used the defaults, the project should include a Java class in MainActivity.java.
Step 1: Add the Dependencies
In this project, we will be using the Google Services gradle plugin to configure GCM. Include it in the project by adding the following line in the dependencies
section of the project’s build.gradle:
classpath 'com.google.gms:google-services:1.5.0'
Next, apply the plugin in the app
module’s build.gradle:
apply plugin: 'com.google.gms.google-services'
To be able to use the GCM API, add com.google.android.gms:play-services
as a compile
dependency in the same file:
compile "com.google.android.gms:play-services:8.3.0"
If you click the Sync Now button, you should see the following error:
Click the Install Repository and sync project link to fix the error.
Step 2: Update the Manifest
Inside the project’s AndroidManifest.xml file, create and use a custom C2D_MESSAGE permission based on your project’s package name. Make sure that the protectionLevel
of the permission is set to signature.
<permission android:name="com.github.hathibelagal.pn.permission.C2D_MESSAGE" android:protectionLevel="signature" /> <uses-permission android:name="com.github.hathibelagal.pn.permission.C2D_MESSAGE" />
The notifications are received in the form of broadcasts. To handle those broadcasts, our app needs a BroadcastReceiver
. However, we don’t have to create it manually. We can instead use the GcmReceiver
class as the BroadcastReceiver
.
The BroadcastReceiver
must have an intent-filter
that responds to the com.google.android.c2dm.intent.RECEIVE
action and the name of its category
must match your project’s package name. Add the following code to the manifest:
<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" /> <category android:name="com.github.hathibelagal.pn" /> </intent-filter> </receiver>
2. Get a Server API Key and a Sender ID
While communicating with the Cloud Connection Server, we need to identify ourselves using an API key on the server side and a sender ID on the client side. To get the API key and the sender ID, create a new project in the developers console.
Start by clicking the Pick a platform button. Next, click the Enable services for my Android App button. When you do so, you will be asked to provide a name and an Android package name for your app. Make sure that the Android package name you provide matches the package name you entered when you created the Android Studio project.
Next, click the Choose and configure services button at the bottom. You can now select the Google services you want to add to the app.
For now, click the Cloud Messaging button and then click Enable Google Cloud Messaging. After a few seconds, you will be presented with your server API key and sender ID. Make a note of the server API key and press Close.
The Google Services plugin we added earlier needs a configuration file to work correctly. Generate the file by clicking the Generate configuration files button.
Once the file has been generated, download it and place it inside your Android Studio project’s app directory.
3. Registering the Client
GCM identifies Android devices using registration tokens. Therefore, our app must be able to register itself from every Android device on which it is installed.
Step 1: Create a Registration Service
The registration must be done on a background thread because the process might take a while depending on network connectivity. Because the registration doesn’t need any inputs from the user, an IntentService
is ideal for this task.
Create a new Java class called RegistrationService.java, make it a subclass of IntentService
, and override its onHandleIntent
method.
public class RegistrationService extends IntentService { public RegistrationService() { super("RegistrationService"); } @Override protected void onHandleIntent(Intent intent) { } }
Inside the onHandleIntent
method, we can use the Instance ID API to generate or fetch the registration token. First, create an instance of the InstanceID
class, using its getInstance
method.
InstanceID myID = InstanceID.getInstance(this);
We can now use the getToken
method of the InstanceID
object to get the registration token in the form of a String
. getToken
expects the sender ID as one of its arguments. Because we’ve added the google-services.json file to our project, we can pass the sender ID to the method using R.string.gcm_defaultSenderID
.
String registrationToken = myID.getToken( getString(R.string.gcm_defaultSenderId), GoogleCloudMessaging.INSTANCE_ID_SCOPE, null );
If you want to see the contents of the registration token for debugging purposes, you can log it as a debug message using the Log.d
method.
Log.d("Registration Token", registrationToken);
At this point, you could send the registration token to your web server and store it in a database there. However, you don’t have to do this if you don’t plan to address your users individually. If you plan to send the same message to every user, you should follow the publish-subscribe approach.
I’ll now be showing you how to subscribe to a topic
called my_little_topic. It takes just two lines of code. First, create a new instance of the GcmPubSub
class using its getInstance
method. Next, call its subscribe
method and pass the registration token to it, along with the name of the topic.
GcmPubSub subscription = GcmPubSub.getInstance(this); subscription.subscribe(registrationToken, "/topics/my_little_topic", null);
Our app can now receive every push notification published to my_little_topic.
Finally, define the service in AndroidManifest.xml.
<service android:name=".RegistrationService" android:exported="false" />
The registration service is complete.
Step 2: Create an InstanceIDListenerService
Registration tokens are refreshed periodically. Consequently, every Android app that uses GCM must have an InstanceIDListenerService
that can handle those refreshes. Therefore, create a new Java file called TokenRefreshListenerService.java and make it a subclass of InstanceIDListenerService
. Inside the onTokenRefresh
method of the class, all we need to do is simply start the registration process again by starting the registration service using an Intent
and the startService
method.
Add the following code to TokenRefreshListenerService.java:
public class TokenRefreshListenerService extends InstanceIDListenerService { @Override public void onTokenRefresh() { Intent i = new Intent(this, RegistrationService.class); startService(i); } }
This service must be able to respond to the com.google.android.gms.iid.InstanceID
action. Therefore, while defining the service in AndroidManifest.xml, add the appropriate intent-filter
.
<service android:name=".TokenRefreshListenerService" android:exported="false"> <intent-filter> <action android:name="com.google.android.gms.iid.InstanceID" /> </intent-filter> </service>
Step 3: Starting the Registration Service
To make sure that the registration process begins as soon as the app starts, we must start the RegistrationService
class inside the onCreate
method of MainActivity
. To do so, create an Intent
for it and use the startService
method.
Intent i = new Intent(this, RegistrationService.class); startService(i);
4. Displaying Push Notifications
GCM automatically displays push notifications in the notification tray as soon as they are received. However, it does so only if the associated app contains a GCMListenerService
.
Create a new Java class called NotificationsListenerService and make it a subclass of GCMListenerService
. Unless you want to handle the pushed data yourself, you don’t have to write any code inside this class. We can leave this class empty for now.
public class NotificationsListenerService extends GcmListenerService { }
While defining the service in AndroidManifest.xml, make sure that you add an intent-filter
that allows it to respond to the com.google.android.c2dm.intent.RECEIVE
action.
<service android:name=".NotificationsListenerService" android:exported="false" > <intent-filter> <action android:name="com.google.android.c2dm.intent.RECEIVE" /> </intent-filter> </service>
5. Adding Push Notification Icons
Every push notification must have an icon associated with it. If you don’t have one handy, you can get one from Google’s Material Design Icons Library.
Once you download the icon, place it inside the res folder of your project. I’ll be using ic_cloud_white_48dp as the icon.
6. Running the Android App
Our Android app is now complete. Once you compile it and run it on an Android device, you will be able to see the registration token in the logcat logs.
Press the back button on your device to exit the app. This is necessary because GCM will display push notifications automatically only if the user is not using the app. If you want the notifications to be shown even when the app is running, you will have to create the notifications yourself inside NotificationsListenerService
using the Notification.Builder
class.
7. Sending Push Notifications
In the final part of this tutorial, we will create a simple Python script that can generate and send push notifications to all the Android devices on which our app is installed.
You can run this script from your local computer or from a remote web server to which you have SSH access.
Step 1: Creating the Script
Create a new file called send.py and open it using your favorite text editor.
At the top of the file, import the urllib2
and urllib
modules. We will use these modules to send data to Google’s Cloud Connection Server. Import the json
module as well because the data we send must be valid JSON. Lastly, to access command line arguments, import the sys
module.
from urllib2 import * import urllib import json import sys
Next, create a variable that stores the server API key you took note of earlier. The key needs to be part of every HTTP request we make to the CCS.
MY_API_KEY="ABCDEF123456789ABCDE--12A"
Every notification must have a title and a body. Instead of hard-coding them in our script, let’s accept the title and body as command line arguments using the argv
array.
messageTitle = sys.argv[1] messageBody = sys.argv[2]
Create a new Python dictionary object to represent the data that should be sent to the CCS. For our Android app to be able to receive the notification, it must be published to a topic called my_little_topic. Therefore, add a key called to to the dictionary and set its value to /topics/my_little_topic.
To represent the contents of the notification, add a key called notification to the dictionary and set its value to another dictionary object containing three keys:
- body
- title
- icon
Make sure that the value of the icon
key matches the name of the icon drawable in your Android project.
data={ "to" : "/topics/my_little_topic", "notification" : { "body" : messageBody, "title" : messageTitle, "icon" : "ic_cloud_white_48dp" } }
Convert the dictionary to a JSON string using the dumps
function of the json
module:
dataAsJSON = json.dumps(data)
All we need to do now is send the JSON string to https://gcm-http.googleapis.com/gcm/send. To do so, create a new Request
object and set dataAsJSON
as its data. Next, set the Authorization
header to MY_API_KEY
and the Content-type
header to application/json.
request = Request( "https://gcm-http.googleapis.com/gcm/send", dataAsJSON, { "Authorization" : "key="+MY_API_KEY, "Content-type" : "application/json" } )
Finally, to execute the request and fetch the response, pass the request object to the urlopen
function and call its read
method.
print urlopen(request).read()
The Python script is now complete and ready to use.
Step 2: Running the Script
At this point, we are ready to send push notifications to all the devices on which our app is installed. Open a terminal and enter the directory in which you created send.py.
Pass the name of the script to the python
executable along with a string for the title of the notification and one for the notification’s body. Here’s an example you can use:
python send.py "My first push notification" "GCM API is wonderful!"
If there are no errors, you should get a response that looks like this:
{"message_id":12345676892321}
If you check your Android device, you should see a new notification in the notification tray.
Conclusion
You now know how to send push notifications to your users. In this lesson, you learned how to create an Android app capable of registering itself, and receiving notifications that are published to a specific topic. You also learned how to create a Python script that can publish notifications.
Even though push notifications may feel like a great way to communicate with your users, I suggest that you use them sparingly and only if you have something useful to say, because sending too many of them too often is perhaps the quickest way to get your app uninstalled.
To learn more about Google Cloud Messaging, refer to the Cloud Messaging Guide.
Comments