Android Google Cloud Messaging Push Notifications (GCM) Tutorial

Push notifications are the best way to reach customers and get users engaged with application. There are different vendors provide push notification services for eg: Google, Parse, Amazon, Apple etc… Today we shall see on how to configure Google server and send push notifications for Android devices.

Few facts and limitations about Google Cloud Messaging:

  1. GCM requires devices running Android 2.2 or higher.
  2. Play store services needs to be installed in the device or emulator.
  3. Minimum Android version 2.3 is required to run the app in play store.
  4. To receive notifications Google account is not mandatory for devices running Android 4.0.4 or higher.

Cloud messaging architecture has 3 components, client application, app server and push notification server.

GCM in Android architecture image

Google Cloud Messaging Server configuration.

  • Generate config file here and move to app folder.
  • Fill up app name, package name and proceed to next screen. (Refer below image for more info)

App_name_package_name_config_file_GCM

  • Copy server key and sender ID, Server key is required in App server. Sender ID is for generating token.

Enable Cloud messaging services in GCM server

  • Download the Json file and move to app/ or mobile/ directory of your project.

Copy Config file

Client side coding to receive GCM notifications.

Update App Gradle file with these dependencies.

apply plugin: 'com.google.gms.google-services'
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
testCompile 'junit:junit:4.12'
compile 'com.android.support:appcompat-v7:23.1.1'
compile 'com.android.support:design:23.1.1'
compile "com.google.android.gms:play-services:8.3.0"
}

Update project gradle file with these dependencies.

dependencies {
classpath 'com.android.tools.build:gradle:1.5.0'
classpath 'com.google.gms:google-services:1.5.0-beta2'
}

Following permissions needs to be added in client manifest file:

<!-- Provide access to internet Services. -->
<uses-permission android:name="android.permission.INTERNET" />

<!-- Messages will be received even if the application is in sleep mode. -->
<uses-permission android:name="android.permission.WAKE_LOCK"/>

<!-- This avoid other apps to register and receive messages from server. -->
<permission android:name="com.feelzdroid.gcmexample.permission.C2D_MESSAGE"
    android:protectionLevel="signature"/>

<uses-permission android:name="com.feelzdroid.gcmexample.permission.C2D_MESSAGE"/>

<!-- For GcmReceiver service handles message sent from GCM server, this permission is
required to receive message-->
<uses-permission android:name="com.google.android.c2dm.permission.SEND"/>

Add the service declarations in Manifest file, we require both service & receiver entries to receive notification from Google server.

<!-- [START the default gcm receiver] -->
<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.feelzdroid.gcmexample" />
 </intent-filter>
</receiver>
<!-- [End default gcm receiver] -->

<!-- [Custom service gets push notification from server, add code in this service to show notifications] -->
<service
 android:name=".myGCMListener"
 android:exported="false" >
 <intent-filter>
 <action android:name="com.google.android.c2dm.intent.RECEIVE" />
 </intent-filter>
</service>

Check for playstore services in user device, if not throw error dialog to install services.

//code to check Google play services availability.
private boolean isPlayServicesInstalled() {
    GoogleApiAvailability getGoogleapiAvailability = GoogleApiAvailability.getInstance();
    int Code = getGoogleapiAvailability.isGooglePlayServicesAvailable(this);
    if (Code != ConnectionResult.SUCCESS) {
        if (getGoogleapiAvailability.isUserResolvableError(Code)) {
            getGoogleapiAvailability.getErrorDialog(this, Code, 9000)
                    .show();
        } else {
            Log.i("MainActivity", "This device is not supported.");
            finish();
        }
        return false;
    }
    return true;
}

In the client android app generate the unique token and store it securely in app server.

public String getDeviceIDForGCM()
{
    String token = "";
    try {
        InstanceID gcmTokenistanceID = InstanceID.getInstance(this);
        //we will get gcm_defaultSenderId by applying plugin: 'com.google.gms.google-services' 
        token = gcmTokenistanceID.getToken(getString(R.string.gcm_defaultSenderId),
                GoogleCloudMessaging.INSTANCE_ID_SCOPE, null);
    }
    catch (Exception e)
    {
        Log.i("TAG", "GCM Registration Token: " + e.getMessage().toString());
    }
  //Keep this token securely, we use this to send message, refer in URL we have added this ID as parameter
    return token;
}

Once Google sends notification, it will come to custom service first. Read the bundle data & show notification.

Note: Refer this post about How to show notifications in Android. However i have added the same code again for easy accessibility. Here one method shows simple notification and another displays big picture notification. Image URL comes from app server. 

public class myGCMListener extends GcmListenerService {
    @Override
    public void onMessageReceived(String from, Bundle data) {

        Log.i("TAG", "Notification received");

        String message = data.getString("message");
        String title = data.getString("title");
        String tikerText = data.getString("tickerText");

        String smallIconURL = data.getString("smallIcon");
        String LargeIconURL = data.getString("largeIcon");

        Bitmap smalliconbitmap = getBitmapFromURL("https://cdn4.iconfinder.com/data/icons/iconsimple-logotypes/512/github-512.png");

        //ShowSimpleNotifications(message,title,tikerText,smalliconbitmap);
        //Bitmap largeiconbitmap = getBitmapFromURL(LargeIconURL);
        showBigPictureStyleNotifications(message,title,tikerText,smalliconbitmap,smalliconbitmap);
    }


    public Bitmap getBitmapFromURL(String strURL) {
        try {
            URL url = new URL(strURL);
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            connection.setDoInput(true);
            connection.connect();
            InputStream input = connection.getInputStream();
            Bitmap myBitmap = BitmapFactory.decodeStream(input);
            return myBitmap;
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    }

    public void showBigPictureStyleNotifications(String message, String title, String tickertext, Bitmap smallIcon,
                                                 Bitmap largeIcon)
    {
        //Create notification object and set the content.
        NotificationCompat.Builder nb= new NotificationCompat.Builder(this);
        nb.setSmallIcon(R.drawable.common_ic_googleplayservices);

        nb.setLargeIcon(smallIcon);
        nb.setContentTitle(title);
        nb.setContentText(message);
        nb.setTicker(tickertext);

        NotificationCompat.BigPictureStyle s = new NotificationCompat.BigPictureStyle().bigPicture(largeIcon);
        s.setSummaryText(message);
        nb.setStyle(s);

        Intent resultIntent = new Intent(this, MainActivity.class);
        TaskStackBuilder TSB = TaskStackBuilder.create(this);
        TSB.addParentStack(MainActivity.class);
        // Adds the Intent that starts the Activity to the top of the stack
        TSB.addNextIntent(resultIntent);
        PendingIntent resultPendingIntent =
                TSB.getPendingIntent(
                        0,
                        PendingIntent.FLAG_UPDATE_CURRENT
                );

        nb.setContentIntent(resultPendingIntent);
        nb.setAutoCancel(true);
        NotificationManager mNotificationManager =
                (NotificationManager) this.getSystemService(Context.NOTIFICATION_SERVICE);
        // mId allows you to update the notification later on.
        mNotificationManager.notify(11221, nb.build());
    }

    public void ShowSimpleNotifications(String message, String title, String tickertext, Bitmap smallIcon) {

        NotificationCompat.Builder nb = new NotificationCompat.Builder(this);
        nb.setSmallIcon(R.drawable.common_ic_googleplayservices);
        nb.setLargeIcon(smallIcon);
        nb.setContentTitle(title);
        nb.setContentText(message);
        nb.setTicker(tickertext);

        NotificationCompat.BigTextStyle bigTextnotifications = new NotificationCompat.BigTextStyle();
        bigTextnotifications.bigText(message);
        bigTextnotifications.setBigContentTitle(title);
        bigTextnotifications.setSummaryText("feelZdroid");
        nb.setStyle(bigTextnotifications);

        Intent resultIntent = new Intent(this, MainActivity.class);
        TaskStackBuilder TSB = TaskStackBuilder.create(this);
        TSB.addParentStack(MainActivity.class);
        // Adds the Intent that starts the Activity to the top of the stack
        TSB.addNextIntent(resultIntent);
        PendingIntent resultPendingIntent =
                TSB.getPendingIntent(
                        0,
                        PendingIntent.FLAG_UPDATE_CURRENT
                );

        nb.setContentIntent(resultPendingIntent);
        nb.setAutoCancel(true);
        NotificationManager mNotificationManager =
                (NotificationManager) this.getSystemService(Context.NOTIFICATION_SERVICE);
        // mId allows you to update the notification later on.
        mNotificationManager.notify(11221, nb.build());

    }
}

App server implementation to send push notifications:

Now write server side code, you can use language like php, Jsp, Asp etc… Here we have taken simple php snippet. Refer Git hub link for full PHP code. Save the file as GCM_example.php

In PHP script provide server API key generated in GCM configuration, have look at the above 4th  images for more info.

define( 'API_ACCESS_KEY', 'AIzaSyAHzIdEKweZuUpI8mmZpOJcjgOxqKZ7Yjw' );

fill up the array with message, small icon & big picture icon details, you can also pass additional parameters.

$msg = array
(
'message' => 'Hello, this is your notification message, We use this variable to store the message text.',
'title' => 'This place is for title of the notification',
'tickerText' => 'Ticker text for your notifications, Lollipop does not show ticker text by default',

'BigpictureIcon' => 'https://cdn4.iconfinder.com/data/icons/iconsimple-logotypes/512/github-512.png'

//Optional variable for your reference, you can remove it if its not required
'vibrate' => 1, 
'sound' => 2, 

//Icon Names or URL for notifications.
'largeIcon' => 'large_icon_URL',
'smallIcon' => 'small_icon_URL'
);

Now we need to send the message to individual devices which are opted for GCM, so we are using the Unique token generated at the time of registration and pass it as external parameter in the URL. For eg:

http://localhost/gcm_example.php?id=UNIQUE_TOKEN_GENERATED_FOR_DEVICE.

“http://localhost/gcm_example.php?id=cXptXKISwcE:APA91bEnki5ebRFI_ouK9mhhrxU_uT6jSwhD31zfVVXUgEOq3Y_Po-rYLzGbzyxwUVlVbEKifwbLRN9g5dRj8YVnCegPKmseRC3iWKg-MV1NqHCCoEd9uqPrhMJLVUAyUnTFXvfjN4K5”

Here how the GCM big picture notification looks.

GCM notification

each time you hit the URL, a message will be sent to individual devices. The Unique token should be kept as secret in your server database.