Phonegap 3.0+ Integration with PushPlugin – Google Cloud Messaging

In this blog post i will write about Google Cloud Messaging Service and it’s integration with phonegap. The is a official phonegap PushPlugin which we will use and see how it works. I have also tweaked the PushPlugin on one minor point, which is believe is required.

What is GCM

GCM or Google Cloud Messaging, is a free service provided by google for android app. It’s purpose is simple

To send data from your server (website or any other service) to your mobile app.

Here is the official guide on GCM http://developer.android.com/google/gcm/index.html

It is very helpful if you want to send any notification from a server to android app. Let’s say for an ecommerce store, you need to inform your customer if a product has come back in stock, and you need to send a message to your mobile app. GCM is best suited for this purpose.

If GCM didn’t exist, for the above case you would have implement a background server in android which periodically check your magento website for the product to come back in stock, and when the product comes to stock your app would display a notification. This process add’s cpu time to both your server and android app when you periodically check your website.

With GCM, this what happens.

1. Your server/website will send a request to Google GCM Server when the product comes in stock.
2. GCM will automatically notify your app and many 1000’s of your app download as soon as the app gets online.
3. In your app you can write code how to handle it.

GCM will notify you app (i.e start an activity) when your online. It doesn’t matter if the app is running or not, it will still notify. You app may be running on background, foreground or has exited still GCM will start the activity.

Google API Key and Sender ID

To start using GCM for your application, you first need to get an api key and sender id. To do this open https://code.google.com/apis/console/

Click on Create Project button and put any name in project name.
Once you create the project, you Sender ID is your Project Number as shown in the image.
Google Developers Console

Next click on “API’s and Auth” and click on “Credentials”. Then on the Public Access Section click on “Create New Key” and then select “Server Key”
Google Developers Console

In the IP Section you can use “0.0.0.0/0” for testing purpose. But in production you need to put your server ip here. This will generate your API Key.Google Developers Console

Now you have your sender id and api key. Sender ID is require in the mobile app and API Key is required for server.

How GCM Works- Technical Process

As per google’s documentation given here http://developer.android.com/google/gcm/client.html below is how a GCM Client should be implemented

1. In your android app, you should create a “Register ID” by calling GCM API using your Sender ID. “Register ID” is a unique id assigned to each android app.
2. Store this “Register ID” in local storage or android shared prefs.
3. Send this “Register ID” to your website/server and store it in your database.
4. On deviceready event, check if your app version has changed from when you created the “Register ID”. If it has changed, recreated the “Register ID” and repeat the above process.
5. When there is any requirement for a notification from your server. Send a request from your server (using curl or other method) with API Key and send it to all the “Registered ID”
6. GCM will automatically start an Activity in your android app when it receives the notification and pass the data to the activity.
7. Based on the data, either you can dismiss it, show a notification or take action as per your logic.

Integration with PhoneGap

Here is the official guide on the integration https://github.com/phonegap-build/PushPlugin

If you follow the documentation it work quite well. Still here are steps that you need to do

1. Add the plugin to your app. In netbeans, open the plugin.properties file an write

com.phonegap.plugins.PushPlugin=https://github.com/phonegap-build/PushPlugin

or if your command line write

cordova plugin add https://github.com/phonegap-build/PushPlugin

2. In your javascript file in the device ready event

var pushNotification;
document.addEventListener("deviceready", onDeviceReady, false);
function onDeviceReady(){
    pushNotification = window.plugins.pushNotification;
    if ( device.platform == 'android' || device.platform == 'Android' )
    {
    pushNotification.register(
        successHandler,
        errorHandler, {
            "senderID":"replace_with_sender_id",
            "ecb":"onNotificationGCM"
        });
    }
}
// Android
function onNotificationGCM(e) {
    $("#app-status-ul").append('<li>EVENT -> RECEIVED:' + e.event + '</li>');

    switch( e.event )
    {
    case 'registered':
        if ( e.regid.length > 0 )
        {
            $("#app-status-ul").append('<li>REGISTERED -> REGID:' + e.regid + "</li>");
           
            console.log("regID = " + e.regid);
        }
    break;

    case 'message':
        if ( e.foreground )
        {
            $("#app-status-ul").append('<li>--INLINE NOTIFICATION--' + '</li>');
            var my_media = new Media("/android_asset/www/"+e.soundname);
            my_media.play();
        }
        else
        {  
            if ( e.coldstart )
            {
                $("#app-status-ul").append('<li>--COLDSTART NOTIFICATION--' + '</li>');
            }
            else
            {
                $("#app-status-ul").append('<li>--BACKGROUND NOTIFICATION--' + '</li>');
            }
        }

        $("#app-status-ul").append('<li>MESSAGE -> MSG: ' + e.payload.message + '</li>');
        $("#app-status-ul").append('<li>MESSAGE -> MSGCNT: ' + e.payload.msgcnt + '</li>');
    break;

    case 'error':
        $("#app-status-ul").append('<li>ERROR -> MSG:' + e.msg + '</li>');
    break;

    default:
        $("#app-status-ul").append('<li>EVENT -> Unknown, an event was received and we do not know what it is</li>');
    break;
  }
}

In the above code, on every device ready you need to call the register function and generate a new register id. The “onNotificationGCM” is called when any event like “register id” generated or GCM notifying the app happens.

Next as per the documentation on app exit, you need to unregister() your id.

function onDeviceReady() {
    $("#app-status-ul").append('<li>deviceready event received</li>');

    document.addEventListener("backbutton", function(e)
    {
        $("#app-status-ul").append('<li>backbutton event received</li>');

        if( $("#home").length > 0 )
        {
            e.preventDefault();
            pushNotification.unregister(successHandler, errorHandler);
            navigator.app.exitApp();
        }
        else
        {
            navigator.app.backHistory();
        }
    }, false);

    // aditional onDeviceReady work…
}

So as per their documentation you need to reigster() and unregister() each time when the app starts and closes.

I found this implementation not to match with Google’s documentation suggests.

My Personal GCM Implementation

The reason i chose to do a person GCM implementation is because

1. Official google guide states that, you should store GCM in local storge or android prefs and regenerate only when app version changes.
2. The Offical Phonegap plugin advices you to register() and unregister() each time app starts and exits.

So i made a slightly different implementation which can be found here
https://github.com/manishiitg/PushPlugin

I added an extra method “GET_CACHE” only to initialize the plugin on deviceready, and then if required we will call the register() function. You can find my code change here

On device ready i call the GET_CACHE method instead of REGISTER. and only if app version has changed, i regenerated the “Registed ID”
You can find my frontend code here https://github.com/manishiitg/PushPlugin/blob/master/Example/www/gcm.js

Here i store the “register id” in android prefs, and check with app version if an update is required.

Only issue with code is that, we cannot detect if our Register ID got invalidated by google in the background. For that we need to write our own custom logic to check if a notification generated by our server, reached a customer or not.

  • inder preet

    Hi, I’ve tried out your code but i’m having some issues.

    When i try to push from my server i get the following response, which i think is a succesfull push:

    “{“multicast_id”:4652607928164468840,”success”:1,”failure”:0,”canonical_ids”:0,”results”:[{“message_id”:”0:1375262603215512%760e4cd6f9fd7ecd”}]}”

    But the message is not delivered to my device. Also, i am not recieving the alerts from the successHandler nor the errorHandler functions. I am, however, recieving the registration alert along with the device id, but i have a suspicion it’s not really registering because the succesHandler function is not alerting.

    Am i doing something wrong, or is this a common issue?

    Regards, Inder

    • Manish Prakash

      Have you setup log through DDMS?

      in DDMS 3 set log filter by TAG and use these tags
      1. PushPlugin
      2. GCMIntentService
      3. PushHandlerActivity

      And see what all debug messages you get. It will help you further debug the problem.