Android Push Notifications using Google Cloud Messaging (GCM)

Android Push Notification is a very important and essential feature. Even you’ll find it in every 8 out of 10 Android application.

As per google’s documentation “Google Cloud Messaging for Android (GCM) is a service that helps developers send data from servers to their Android applications on Android devices”. GCM is a service provided by Google for developer that helps developer to send data from server to any number of Android devices. It’s a free service means any developer can send any number of notifications using GCM in a day for any number of Android devices.

Google Cloud Messaging(GCM) ?

  • GCM can be used as a notification engine. It means on an event it can send a notification to an android device.
  • A notification can be just a string message or some sort of data. Using GCM, maximum 4kb of payload can be sent in a notification.
  • Google provides GCM as a free to use service. And there is no limit on number of messages per day either.
  • Android App can receive the message from Google cloud messaging server (GCM) even if the app is not running via Intent broadcasting.

How GCM interacts with android devicesNow GCM can be implemented in a project in two part like:

  1. First we will implement a web application which runs on a web server. Here after we’ll refer to this as GCM server application.
  2. Second we will implement functionality in our android app to receive and process Notifications from GCM server. And for this we’ll refer it as GCM client application.

 

1. GCM Server Application

There are two parts in this step and they are:

First we have to obtain Server Key from Google developer console and Google provides server key after creating an application in developer console to use GCM service. You can get it by following below steps:

  • Create Google Project: Go to the URL https://cloud.google.com/console/project then create a project and navigate into it.
  • Enable Google Cloud Messaging For Android: Go to menu “APIs & auth –> APIs” and switch on.
  • Create Server Key: Go to Menu “Credentials” and under the section Public API access, click Create New Key. There are different types of keys and here we should use “Sever Key”.
  • Edit Allowed IPs: This is to white-list a set of IP addresses as the server key is tied to IP addresses for security. To get your public IP address, in Google search type ‘my public ip address’. Click ‘Edit allowed IPs’ and update your IP.

After obtaining the Server Key from Google developer console our only work to implement GCM Server is develop a web application. For simplicity here i saved gcm reg id in a text file and i’ll use this text file to read gcm reg id during sending a message to that android device. Actually reg id uniquely identifies an android device from another. I used several Google Helper libraries.
Overall it’s very easy and it’s just a couple of lines of codes like below:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<%
	String pushStatus = "";
	Object pushStatusObj = request.getAttribute("pushStatus");

	if (pushStatusObj != null) {
		pushStatus = pushStatusObj.toString();
	}
%>
<head>
<title>Google Cloud Messaging (GCM) Server in PHP</title>
</head>
<body>

	<h1>Google Cloud Messaging (GCM) Server in Java</h1>

	<form action="GCMNotification" method="post">

		<div>
			<textarea rows="2" name="message" cols="23"
				placeholder="Message to transmit via GCM"></textarea>
		</div>
		<div>
			<input type="submit" value="Send Push Notification via GCM" />
		</div>
	</form>
	<p>
		<h3>
			<%=pushStatus%>
		</h3>
	</p>
</body>
</html>

And here is Servlet code to send notifications to Android devices.

package com.hprog99.gcm;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.google.android.gcm.server.Message;
import com.google.android.gcm.server.Result;
import com.google.android.gcm.server.Sender;
@WebServlet("/GCMNotification")
public class GCMNotification extends HttpServlet {
private static final long serialVersionUID = 1L;
// Put your Google API Server Key here
private static final String GOOGLE_SERVER_KEY = ""; //Server key got from Google developer console
static final String MESSAGE_KEY = "message";
public GCMNotification() {
super();
}
protected void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
protected void doPost(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
Result result = null;
String share = request.getParameter("shareRegId");
// GCM RedgId of Android device to send push notification
String regId = "";
if (share != null && !share.isEmpty()) {
regId = request.getParameter("regId");
PrintWriter writer = new PrintWriter("GCMRegId.txt");
writer.println(regId);
writer.close();
request.setAttribute("pushStatus", "GCM RegId Received.");
request.getRequestDispatcher("index.jsp")
.forward(request, response);
} else {
try {
BufferedReader br = new BufferedReader(new FileReader(
"GCMRegId.txt"));
regId = br.readLine();
br.close();
String userMessage = request.getParameter("message");
Sender sender = new Sender(GOOGLE_SERVER_KEY);
Message message = new Message.Builder().timeToLive(30)
.delayWhileIdle(true).addData(MESSAGE_KEY, userMessage).build();
System.out.println("regId: " + regId);
result = sender.send(message, regId, 1);
request.setAttribute("pushStatus", result.toString());
} catch (IOException ioe) {
ioe.printStackTrace();
request.setAttribute("pushStatus",
"RegId required: " + ioe.toString());
} catch (Exception e) {
e.printStackTrace();
request.setAttribute("pushStatus", e.toString());
}
request.getRequestDispatcher("index.jsp")
.forward(request, response);
}
}
}
view raw GCM_Server.java hosted with ❤ by GitHub

2. GCM Client Application

Usually an android application with GCM implemented do the following tasks.

  • Register with GCM Server and receive reg id.
  • Share the reg id with application server.
  • Receive and process Push notifications from application server.

Before continue any further with GCM Application We have to fulfill some Prerequisite first like:

  • Google Play Services in SDK
  • Google APIs
  • Google Play Services Lib project as Android dependency
  • Google Project Id – You will get it from Google developer consoler in project’s screen.
  • Register/login with a Google account in the AVD

If our application/android env doesn’t meet any of the above conditions then when we try to test our GCM implementation then it doesn’t produce any error but you’ll not get any notifications from server as well.

  1. Just put below code in your project’s activity code which you use for registration purpose or you can put it in anywhere in a activity. These lines does nothing just on invoking they communicate with Google and then in return they give you reg id. And this reg id is used in sending notifications from application server to device.
GoogleCloudMessaging gcm;
String msg = "";
String regId = "";
if (gcm == null) {
   gcm = GoogleCloudMessaging.getInstance(context);
	}
   regId = gcm.register(Config.GOOGLE_PROJECT_ID);
   Log.d("RegisterActivity", "registerInBackground - regId: "
							+ regId);
   msg = "Device registered, registration ID=" + regId;

Next we’ll need to implement a BroadcastReceiver and a Service to notify an user about notification and receive notifications from application server.

  • GCMBroadcastReceiver.java
package com.hprog99.android;

import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.support.v4.content.WakefulBroadcastReceiver;

public class GcmBroadcastReceiver extends WakefulBroadcastReceiver {

	@Override
	public void onReceive(Context context, Intent intent) {
		ComponentName comp = new ComponentName(context.getPackageName(),
				GCMNotificationIntentService.class.getName());
		startWakefulService(context, (intent.setComponent(comp)));
		setResultCode(Activity.RESULT_OK);
	}
}

 

  • GCMNotificationService.java
package com.hprog99.android;
import android.app.IntentService;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.SystemClock;
import android.support.v4.app.NotificationCompat;
import android.util.Log;
import com.google.android.gms.gcm.GoogleCloudMessaging;
public class GCMNotificationIntentService extends IntentService {
public static final int NOTIFICATION_ID = 1;
private NotificationManager mNotificationManager;
NotificationCompat.Builder builder;
public GCMNotificationIntentService() {
super("GcmIntentService");
}
public static final String TAG = "GCMNotificationIntentService";
@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: "
+ extras.toString());
} else if (GoogleCloudMessaging.MESSAGE_TYPE_MESSAGE
.equals(messageType)) {
sendNotification("Message Received from Google GCM Server: "
+ extras.get(Config.MESSAGE_KEY));
Log.i(TAG, "Received: " + extras.toString());
}
}
GcmBroadcastReceiver.completeWakefulIntent(intent);
}
private void sendNotification(String msg) {
Log.d(TAG, "Preparing to send notification...: " + 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.hprog99)
.setContentTitle("GCM Notification")
.setStyle(new NotificationCompat.BigTextStyle().bigText(msg))
.setContentText(msg);
mBuilder.setContentIntent(contentIntent);
mNotificationManager.notify(NOTIFICATION_ID, mBuilder.build());
Log.d(TAG, "Notification sent successfully.");
}
}
  • And now last work remaining to do i.e. modify Android Manifest file
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.hprog99.android"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.GET_ACCOUNTS" />
    <uses-permission android:name="android.permission.WAKE_LOCK" />

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

    <uses-permission android:name="com.hprog99.android.permission.C2D_MESSAGE" />
    <uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.VIBRATE" />

    <uses-sdk
        android:minSdkVersion="9"
        android:targetSdkVersion="16" />

    <application
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name" >

        <activity
            android:name=".RegisterActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <activity
            android:name="com.hprog99.android.MainActivity"
            android:label="@string/app_name" >
        </activity>

        <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.hprog99.android" />
            </intent-filter>
        </receiver>

        <service android:name=".GCMNotificationIntentService" />
    </application>

</manifest>

Please give special attention while you modify your manifest file because event after implemented everything exactly right but a minor mistake in manifest file during adding those implemented components to it can lead to unwanted conditions.

That’s all we have to do to implement Android Push notifications.

3 thoughts on “Android Push Notifications using Google Cloud Messaging (GCM)

  1. Pingback: Doze? – An Overview of Android Alarms | 4Knahs

Leave a comment