GCM Demo

Hello All,

Android has replacing C2DM (Cloude to Device Messaging) service with GCM (Google Cloude Messaging). Recently Google introduced Google Drive which is based on Cloude computing and now GCM which shows future is Cloude computing. With this GCM your application can receive only from specified servers message that is the flow of c2dm and gcm are exactly same other than you can let google know from which server application will receive message. Also in c2dm we required a developers gmail id to register for c2dm now we don’t need gmail id to send for authentication but instead you need to create a project on Google which has a id which we will send as “sender id”.

I am providing you all the steps by following these you can implement GCM in your projects..
1) Goto https://code.google.com/apis/console and create a project same name as your application you will see the browser link has changed as https://code.google.com/apis/console/#project:4815162342 it contains your project id (4815162342 in this example) copy that we reuired that in your applciation as sender id.
2) In the main Google APIs Console page, select Services. Turn the Google Cloud Messaging toggle to ON. In the Terms of Service page, accept the terms.
3) In the main Google APIs Console page, select API Access. Now you can see there is API key if you use that key your application can receive messages from any server & if you want to restrict servers you can generate new server key using button there as “Create new server key…”. Once you clicked this button it will show you anthore view where you need to give server ip address from which you applciation will receive message.

Now you have sender id & api key so lets move to your application & lets make changes in to authenticate & receive message from server.

1) Copy the gcm.jar file from the SDK’s gcm-client/dist directory to your application classpath. As external jar.
2) now your manifest files will look like


<manifest xmlns:android="http://schemas.android.com/apk/res/android"
 package="com.androidmyway.demo.gcmdemo"
 android:versionCode="1"
 android:versionName="1.0" >

<!-- GCM requires Android SDK version 2.2 (API level 8) or above. -->
 <!-- The targetSdkVersion is optional, but it's always a good practice
 to target higher versions. -->
 <uses-sdk
 android:minSdkVersion="8"
 android:targetSdkVersion="15" />

<!-- GCM connects to Google Services. -->
 <uses-permission android:name="android.permission.INTERNET" />
 <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
 <uses-permission android:name="android.permission.READ_PHONE_STATE" />

<!-- GCM requires a Google account. -->
 <uses-permission android:name="android.permission.GET_ACCOUNTS" />

<!-- Keeps the processor from sleeping when a message is received. -->
 <uses-permission android:name="android.permission.WAKE_LOCK" />

<!--
 Creates a custom permission so only this app can receive its messages.

NOTE: the permission *must* be called PACKAGE.permission.C2D_MESSAGE,
 where PACKAGE is the application's package name.
 -->
 <permission
 android:name="com.androidmyway.demo.gcmdemo.permission.C2D_MESSAGE"
 android:protectionLevel="signature" />
 <uses-permission
 android:name="com.androidmyway.demo.gcmdemo.permission.C2D_MESSAGE" />

<!-- This app has permission to register and receive data message. -->
 <uses-permission
 android:name="com.google.android.c2dm.permission.RECEIVE" />
 <!-- Keeps the device on vibrating mode when a message is received. -->
 <uses-permission android:name="android.permission.VIBRATE" />

 <application
 android:icon="@drawable/ic_launcher"
 android:label="@string/app_name"
 android:theme="@android:style/Theme.Black.NoTitleBar" >
 <activity
 android:name=".MainActivity"
 >
 <intent-filter>
 <action android:name="android.intent.action.MAIN" />

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

 <!--
 BroadcastReceiver that will receive intents from GCM
 services and handle them to the custom IntentService.

The com.google.android.c2dm.permission.SEND permission is necessary
 so only GCM services can send data messages for the app.
 -->
 <receiver
 android:name="com.google.android.gcm.GCMBroadcastReceiver"
 android:permission="com.google.android.c2dm.permission.SEND" >
 <intent-filter>
 <!-- Receives the actual messages. -->
 <action android:name="com.google.android.c2dm.intent.RECEIVE" />
 <!-- Receives the registration id. -->
 <action android:name="com.google.android.c2dm.intent.REGISTRATION" />
 <category android:name="com.androidmyway.demo.gcmdemo" />
 </intent-filter>
 </receiver>

 <!--
 Application-specific subclass of GCMBaseIntentService that will
 handle received messages.

By default, it must be named .GCMIntentService, unless the
 application uses a custom BroadcastReceiver that redefines its name.
 -->
 <service android:name=".GCMIntentService" />

 </application>

</manifest>

3) now you need to create GCMIntentService as follows

package com.androidmyway.demo.gcmdemo;

import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
import android.util.Log;

import com.google.android.gcm.GCMBaseIntentService;

public class GCMIntentService extends GCMBaseIntentService{

public GCMIntentService(){
 super(Utils.GCMSenderId);
 }

@Override
 protected void onError(Context context, String regId) {
 // TODO Auto-generated method stub
 Log.e("", "error registration id : "+regId);
 }

@Override
 protected void onMessage(Context context, Intent intent) {
 // TODO Auto-generated method stub
 handleMessage(context, intent);
 }

@Override
 protected void onRegistered(Context context, String regId) {
 // TODO Auto-generated method stub
// Log.e("", "registration id : "+regId);
 handleRegistration(context, regId);
 }

@Override
 protected void onUnregistered(Context context, String regId) {
 // TODO Auto-generated method stub

 }

@SuppressWarnings({ "deprecation", "static-access" })
 private void handleMessage(Context context, Intent intent) {
 // TODO Auto-generated method stub
 Utils.notiMsg = intent.getStringExtra("msg");
 Utils.notiTitle = intent.getStringExtra("title");
 Utils.notiType = intent.getStringExtra("type");
 Utils.notiUrl = intent.getStringExtra("url");

 int icon = R.drawable.ic_launcher; // icon from resources
 CharSequence tickerText = Utils.notiTitle;//intent.getStringExtra("me"); // ticker-text

 long when = System.currentTimeMillis(); // notification time
 CharSequence contentTitle = ""+Utils.notiMsg; //intent.getStringExtra("me"); // message title

NotificationManager notificationManager =
 (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
 Notification notification = new Notification(icon, tickerText, when);
 Intent notificationIntent = new Intent(context, MainActivity.class);
 PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, notificationIntent, 0);

notification.setLatestEventInfo(context, contentTitle, "", pendingIntent);
 notification.flags|=notification.FLAG_INSISTENT|notification.FLAG_AUTO_CANCEL;
 notification.defaults |= Notification.DEFAULT_SOUND|Notification.DEFAULT_LIGHTS;
 notification.vibrate=new long[] {100L, 100L, 200L, 500L};
 notificationManager.notify(1, notification);
 Utils.notificationReceived=true;
 PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
 WakeLock wl = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP, "TAG");
 wl.acquire();

 }

 private void handleRegistration(Context context, String regId) {
 // TODO Auto-generated method stub
 Utils.registrationId = regId;
 Log.e("", "registration id : "+regId);

 }
}

4) now I am creating a class which keeps all static variables I am using throughout the application which has sender id messge recived from server and also a special boolean varible which will tell our application that is there a notification recivied or not. Which will look like below.

package com.androidmyway.demo.gcmdemo;

import android.app.Application;

public class Utils extends Application{

public static String GCMSenderId = "Your sender ID";
 public static boolean notificationReceived;
 public static String notiTitle="",notiType="",notiMsg="",notiUrl="",registrationId = "";

}

5)Now your activity which will send “senderID” to server. Generally I register device in splash acitivity but as I am creating a demo so I have only one activity. You can write this code in activity which shows a splash screen to user or activity which comes after this splash activity. Code will be like this

package com.androidmyway.demo.gcmdemo;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
import android.util.Log;

import com.google.android.gcm.GCMRegistrar;

public class MainActivity extends Activity {

@Override
 public void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.activity_main);
 GCMRegistrar.checkDevice(this);

 // Make sure the device has the proper dependencies.
 GCMRegistrar.checkDevice(this);
 // Make sure the manifest was properly set - comment out this line
 // while developing the app, then uncomment it when it's ready.
 GCMRegistrar.checkManifest(this);

 final String regId = GCMRegistrar.getRegistrationId(this);

 if (regId.equals("")) {
 GCMRegistrar.register(this, Utils.GCMSenderId);
 } else {
 Log.v("", "Already registered: "+regId);
 }

 /**
 We set this varible true when we recive notification
 (this code must be in activity which not showing your applciaiton splash screen).
 */
 if (Utils.notificationReceived) {
 onNotification();
 }
 }

 @Override
 protected void onDestroy() {
 GCMRegistrar.onDestroy(this);
 super.onDestroy();
 }

 public void onNotification(){
 Utils.notificationReceived=false;
 PowerManager pm = (PowerManager) getSystemService(POWER_SERVICE);
 WakeLock wl = pm.newWakeLock(PowerManager.ACQUIRE_CAUSES_WAKEUP, "TAG");
 wl.acquire();

AlertDialog.Builder mAlert=new AlertDialog.Builder(this);
 mAlert.setCancelable(true);

mAlert.setTitle(Utils.notiTitle);
 mAlert.setMessage(Utils.notiMsg);
 mAlert.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
 public void onClick(DialogInterface dialog, int which) {
 // TODO Auto-generated method stub
 dialog.dismiss();
 }
 });
 mAlert.setNegativeButton("No", new DialogInterface.OnClickListener() {
 public void onClick(DialogInterface dialog, int which) {
 // TODO Auto-generated method stub
 dialog.dismiss();
 }
 });

 mAlert.show();
 }

}

You need to make changes in onNotification() method which will show alertbox.

Now your client sode is ready but still you required server side which will be like below. Now I am using curl functionality from php which is used to comunicate between http, shttp, etc… This code will required your device registration id, api key, message title, message body. this code will look like
Serverside code

<?php
 $url = 'https://android.googleapis.com/gcm/send';
 $serverApiKey = "Your Api key";
 $reg = "Device registration id";

$headers = array(
 'Content-Type:application/json',
 'Authorization:key=' . $serverApiKey
 );

 $data = array(
 'registration_ids' => array($reg)
 , 'data' => array(
 'type' => 'New'
 , 'title' => 'GCM'
 , 'msg' => 'Here we completed GCM demo.'
 , 'url' => 'https://androidmyway.wordpress.com'
 )
 );

 $ch = curl_init();
 curl_setopt($ch, CURLOPT_URL, $url);
 if ($headers)
 curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
 curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
 curl_setopt($ch, CURLOPT_POST, true);
 curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
 curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));

 $response = curl_exec($ch);

curl_close($ch);
 print ($response);

?>

Note:—
1) In above code you can see there is a data array which has few key value pairs you can customize them as you want currently they are just as I want.
If you get any error then you need to activate curl in php settings.
2) Here as we are required device resigstration id to which we need to send message you need to make changes in “handleRegistration” in “GCMIntentService” so that you can send device registation id to your server which will save them to send messages.
3) you can send messages to multiple devices just need to mentions all registration ids in a array seperated by comma.
If any help needed please let me know & if any process I written wrong please inform me.

For more help check  http://developer.android.com/guide/google/gcm/gs.html

Thank You

Added code on GitHub
https://github.com/sandipmjadhav/GCMDemo

40 thoughts on “GCM Demo

  1. Hi
    First of all thanks a lot for wonderfull efforts. Need your help in one part on which I am really very new. How to get the device ID ? I really tried a lot but couldnt find out how to know the device ID or send it to my own server.

  2. Sorry but since I am more comfortable with phonegap,I’ll really appreciate if its possible for you to share the details in that.

    • Android doesn’t provide anything by which you can get same device id every time but still we are using following piece of code to get device id. more important it may change if user changes sim card or removes it.
      final TelephonyManager tm = (TelephonyManager) getBaseContext().getSystemService(Context.TELEPHONY_SERVICE);
      final String tmDevice, tmSerial, androidId;
      tmDevice = “” + tm.getDeviceId();
      tmSerial = “” + tm.getSimSerialNumber();
      androidId = “” + android.provider.Settings.Secure.getString(getContentResolver(), android.provider.Settings.Secure.ANDROID_ID);

      UUID deviceUuid = new UUID(androidId.hashCode(), ((long)tmDevice.hashCode() << 32) | tmSerial.hashCode());

  3. Hi Jadhav,
    Nice post for the GCM. I can understand the part for Android, but not the Web App part.
    I would like to ask whether you have experience on writing the GCM server app in JAVA format, because I’m not familiar with PHP and don’t have much experience in Web Apps as well.
    Thanks!

  4. Hello! Thank you for your post! It helped me a lot.
    (Sorry for my poor English… and I’m very new to android. )
    Now, i have a list, and i want to send messages to those users i picked on this list. So I am trying to figure out how to use the GCM service.
    Using your code, i can get the registrationId, but i coudn’t get the notification…
    I posted the regId to the php, like this:

    private void handleRegistration(Context context, String regId) {
    // TODO Auto-generated method stub
    Utils.registrationId = regId;
    Log.e(“”, “registration id : “+regId);

    ArrayList postParameters = new ArrayList();
    postParameters.add(new BasicNameValuePair(“regId”, regId));
    String response = null;
    try {
    response = CustomHttpClient.executeHttpPost(“http://yuicholina.com/~yoyo/php/android_gcm.php”, postParameters);
    String res=response.toString();
    Toast.makeText(this, res, Toast.LENGTH_LONG).show();
    } catch (Exception e) {

    }
    }

    in the php, i just changed the API key and $reg = $_POST[‘regId’],
    and i added the Toast to see the error of php, but get nothing…

    Could you tell me what’s the problem? Please help me!!
    Thank you very much!

    • Hello Xu if you want to send message to multiple devices then you must store registration id’s of these devices on server
      For sending Registration id to server I use following code
      final String URL = apiUrl + “cmd=a_add&device_id=”+Utils.deviceID+”&device_tocken=”+Utils.deviceToken+”&app_name=BrainBooster”;
      try {
      ele = XmlParser.parse(URL);
      } catch (ParserConfigurationException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
      } catch (SAXException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
      } catch (IOException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
      }

      I will check your code & see why it’s not working

      • Thank you so much!
        I write the same code which is sending the regId to the php in Main.Activity instead of GCMIntentService (handleRegistration part), it succeeded! Thank u!

        So, i should take every device ‘s registration id when user log in and store registration ids into my database. Then when i want to send messages, i use the php to select these ids from my database and send messages.
        Is that right?

      • Ya XU it’s right
        May be you also want device id’s. Registration id’s generates multiple time some time may be they are different so you need to create a device id ( you can use following code) which is your primary key in database on server & while inserting check for this device id first in your database & if device id present just update that record & if not then just add that record.
        public void getDeviceID() {
        final TelephonyManager tm = (TelephonyManager) getBaseContext().getSystemService(Context.TELEPHONY_SERVICE);
        final String tmDevice, tmSerial, androidId;
        tmDevice = “” + tm.getDeviceId();
        tmSerial = “” + tm.getSimSerialNumber();
        androidId = “” + android.provider.Settings.Secure.getString(getContentResolver(), android.provider.Settings.Secure.ANDROID_ID);
        UUID deviceUuid = new UUID(androidId.hashCode(), ((long)tmDevice.hashCode() << 32) | tmSerial.hashCode());
        //Log.v("Device Id", deviceUuid.toString());
        Utils.deviceID = deviceUuid.toString();
        /*Here Utils is a my class which holds all the static values so that I can use it anywhere in application*/
        }

  5. Hi Sandip,
    First of all, i would like to appreciate your work..Its really superb…
    I have a few quires from my side…
    (1) Can we design the same(entire concept) using PHONEGAP i.e HTML5,JAVASCRIPT,CSS,JSON,JQUERY.
    (2) I read that, during registration with GCM, each app will be registered with UNIQUE ID, now, Suppose that i have deployed my app in 20 mobile.. Then after registration, how will the message be delivered to all mobiles (My question is–“WILL ALL THE APPLICATIONS GET REGISTERED WITH SAME ID”)
    (3) I am trying to implement this entire concept using ANDROID–PHONEGAP, so, for time being, can i check the output in EMULATOR….

    Thanks in advance..

  6. Hello Nataraj,
    First Thank You, Now answers to your queries
    (1) I never tried so I am not sure on this
    (2) For this you need to store registration id’s on server
    Check my reply to Xu’s comment..
    (3) If you are testing it in Emulator you Google account configured on that Emulator & for that Emulator must have Google Api.

    If you got success in implementation of this in Phonegap Try to share with us .

    Thank You

    • Hi Sandip,
      Thanks for your immediate response..
      Can you please upload the Detailed ARCHITECTURAL FLOW (Diagrammatically Representation) of the entire concept(i.e –>client who sends the message+ GCM+ multiple mobiles which receives the transmitted message)..
      Also plot the corresponding Sender ID, Receiver ID,API key,Registraion Id’s on top of the blocks for better understanding ….

      Thanks in Advance

  7. Hi Jadhav,

    First of all superb post yar..Great work….keep it up
    I am very much keen about your reply which Mr.Nataraj posed you…
    I would like to see the block diagram of this entire flow with multiple users…
    Expecting a quicker response…

  8. I got this error from php file
    “{“multicast_id”:xxxxxxxx,”success”:0,”failure”:1,”canonical_ids”:0,”results”:[{“error”:”InvalidRegistration”}]}”

    I already done step 1-3 but it got that error. Please help. Thank you

  9. Hello I do not write very well in English, but I’ll try.
    I have problems with your demo, php works right, works the notification, the problem is that when you touch the notification, I get this error, I’m using your own demo.

    10-10 12:49:42.303: E/AndroidRuntime(1040): FATAL EXCEPTION: main
    10-10 12:49:42.303: E/AndroidRuntime(1040): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.androidmyway.demo.gcmdemo/com.androidmyway.demo.gcmdemo.MainActivity}: java.lang.IllegalArgumentException

      • friend, does not work, I have internet permits ready, I have your same code. and do not understand why I get this error.
        I have enabled the libraries all good …

        up when I install the application, it works fine.
        the problem is when the notification arrives and pressed, opens the application and black error screen.

        Error:
        10-10 13:06:43.483: W/dalvikvm(3611): threadid=1: thread exiting with uncaught exception (group=0x40020ac0)
        10-10 13:06:43.513: E/AndroidRuntime(3611): FATAL EXCEPTION: main
        10-10 13:06:43.513: E/AndroidRuntime(3611): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.androidmyway.demo.gcmdemo/com.androidmyway.demo.gcmdemo.MainActivity}: java.lang.IllegalArgumentException
        10-10 13:06:43.513: E/AndroidRuntime(3611): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2663)
        10-10 13:06:43.513: E/AndroidRuntime(3611): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2679)
        10-10 13:06:43.513: E/AndroidRuntime(3611): at android.app.ActivityThread.access$2300(ActivityThread.java:125)
        10-10 13:06:43.513: E/AndroidRuntime(3611): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2033)
        10-10 13:06:43.513: E/AndroidRuntime(3611): at android.os.Handler.dispatchMessage(Handler.java:99)
        10-10 13:06:43.513: E/AndroidRuntime(3611): at android.os.Looper.loop(Looper.java:123)
        10-10 13:06:43.513: E/AndroidRuntime(3611): at android.app.ActivityThread.main(ActivityThread.java:4627)
        10-10 13:06:43.513: E/AndroidRuntime(3611): at java.lang.reflect.Method.invokeNative(Native Method)
        10-10 13:06:43.513: E/AndroidRuntime(3611): at java.lang.reflect.Method.invoke(Method.java:521)
        10-10 13:06:43.513: E/AndroidRuntime(3611): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:860)
        10-10 13:06:43.513: E/AndroidRuntime(3611): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:618)
        10-10 13:06:43.513: E/AndroidRuntime(3611): at dalvik.system.NativeStart.main(Native Method)
        10-10 13:06:43.513: E/AndroidRuntime(3611): Caused by: java.lang.IllegalArgumentException
        10-10 13:06:43.513: E/AndroidRuntime(3611): at android.os.PowerManager$WakeLock.(PowerManager.java:223)
        10-10 13:06:43.513: E/AndroidRuntime(3611): at android.os.PowerManager.newWakeLock(PowerManager.java:367)
        10-10 13:06:43.513: E/AndroidRuntime(3611): at com.androidmyway.demo.gcmdemo.MainActivity.onNotification(MainActivity.java:55)
        10-10 13:06:43.513: E/AndroidRuntime(3611): at com.androidmyway.demo.gcmdemo.MainActivity.onCreate(MainActivity.java:42)
        10-10 13:06:43.513: E/AndroidRuntime(3611): at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1047)
        10-10 13:06:43.513: E/AndroidRuntime(3611): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2627)
        10-10 13:06:43.513: E/AndroidRuntime(3611): … 11 more

  10. Dear, I managed to find the error, delete the following line of code and fix the problem:

    PowerManager pm = (PowerManager) getSystemService(POWER_SERVICE);
    WakeLock wl = pm.newWakeLock(PowerManager.ACQUIRE_CAUSES_WAKEUP, “TAG”);
    wl.acquire();

    The question I have is that makes that line of code?
    and the other for serving:

      ‘url’ => ‘https://androidmyway.wordpress.com’

    at that time it is used, and I do not see when running the application.

  11. I have problems with the mass sending push messages.
      $ reg = “Device registration id”;

    I replace it

      $ reg = array (“Device registration 1”, “Device registration 2”, “Device registration 3”);

    Error:
    “multicast_id”:7309478627312922123,”success”:0,”failure”:1,”canonical_ids”:0,”results”:[{“error”:”InvalidRegistration”}]

    I do not understand because if according to what you put in your hand, you had to create an array with the device id, if I do only work, but to create the array goes down.

  12. Hi,

    Nice tutorial… but, i got error like this, ” 10-24 17:31:47.289: E/GCMRegistrar(370): internal error: retry receiver class not set yet “. Can u pls suggest me the solution for this.

  13. Hey, Thanks so much for this demo it has helped me tons. I am having one problem though. Whenever I send a mesg it keeps on beeping and vibrating till I pull down the notification area. I have your code in my splashactivity. Any ideas?

    • Nevermind

      notification.flags|=notification.FLAG_INSISTENT|notification.FLAG_AUTO_CANCEL;
      to

      notification.flags|=notification.FLAG_AUTO_CANCEL;

      Thanks again

  14. Pretty section of content. I just stumbled upon your site and
    in accession capital to assert that I get in fact enjoyed account your blog
    posts. Anyway I’ll be subscribing to your feeds and even I achievement you access consistently quickly.

  15. Please help.
    i used this tutorial and it`s working but when i click at the notification, it opens my app but there is no alert to display my message.

  16. it’s a very nice tutorial…
    though i have a question that can we set up server id, API key and make the google cloud messaging toggle turn on programmatically..?

Leave a reply to Sandip Jadhav Cancel reply