Tuesday, April 23, 2013

Google Cloud Messaging example in Android | C2DM in android | GCM in Android | Push notification demo with php back-end | Messaging in Android

Hello Friends,
Today I am going to share very Important code for GCM(Google Cloud Messaging) for Android. I worked with my php developer(Ankit Garg) for back end and it is working Okay for me.
My article have 3 category-

1)Creating a Google API Project
2)PHP Back-end
3)Android Front-end



                                                         Part-A  Google API Project

1)Open Google API console from here
2)If you have not created any project create new project for your application-
3)See your browser URL and note your project ID from above some thing like that-1080127563513
https://code.google.com/apis/console/#project:1080127563513
4)In the main Google APIs Console page, select Services.
5)Turn the Google Cloud Messaging toggle to ON.
6)In the Terms of Service page, accept the terms.
7)get API Key from main Google APIs Console page, select API Access. You will see a screen that resembles the following and click on Create new Server Key:


8)Now from below window choose create button:

9)From below window note your project id and api key:


Part-B PHP Back-end Side



Just copy below file and put into your  php server inside ws folder-

1)GCM.php
<?php
$regID=$_GET['regID'];
$registatoin_ids=array($regID);
$msg=array("message"=>'HI Manish');
$url='https://android.googleapis.com/gcm/send';
$fields=array
 (
  'registration_ids'=>$registatoin_ids,
  'data'=>$msg
 );
$headers=array
 (
  'Authorization: key=AIzaSyA46UE7bBWXCpHSD5sbNxbRwI1MAKVI-jg',
  'Content-Type: application/json'
 );
$ch=curl_init();
curl_setopt($ch,CURLOPT_URL,$url);
curl_setopt($ch,CURLOPT_POST,true);
curl_setopt($ch,CURLOPT_HTTPHEADER,$headers);
curl_setopt($ch,CURLOPT_RETURNTRANSFER,true);
curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,false);
curl_setopt($ch,CURLOPT_POSTFIELDS,json_encode($fields));
$result=curl_exec($ch);
curl_close($ch);
echo $result;
?>

Part-C Android side
1)MainActivity.java
package com.manish.gcm.push;

import static com.manish.gcm.push.CommonUtilities.SENDER_ID;

import java.io.BufferedReader;
import java.io.InputStreamReader;

import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpParams;

import android.annotation.TargetApi;
import android.app.Activity;
import android.app.ProgressDialog;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.util.Log;
import android.widget.TextView;

import com.google.android.gcm.GCMRegistrar;

@TargetApi(Build.VERSION_CODES.GINGERBREAD)
public class MainActivity extends Activity {

 private String TAG = "** GCMPushDEMOAndroid**";
 private TextView mDisplay;
 String regId = "";

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

  mDisplay = (TextView) findViewById(R.id.textView1);

  regId = GCMRegistrar.getRegistrationId(this);

  if (regId.equals("")) {
   GCMRegistrar.register(this, SENDER_ID);
  } else {
   Log.v(TAG, "Already registered");
  }
  /**
   * call asYnc Task
   */
  new sendIdOnOverServer().execute();
  mDisplay.setText("RegId=" + regId);
 }

 private void checkNotNull(Object reference, String name) {
  if (reference == null) {
   throw new NullPointerException(getString(R.string.error_config,
     name));
  }

 }

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

 public class sendIdOnOverServer extends AsyncTask {

  ProgressDialog pd = null;

  @Override
  protected void onPreExecute() {
   pd = ProgressDialog.show(MainActivity.this, "Please wait",
     "Loading please wait..", true);
   pd.setCancelable(true);

  }

  @Override
  protected String doInBackground(String... params) {
   try {
    HttpResponse response = null;
    HttpParams httpParameters = new BasicHttpParams();
    HttpClient client = new DefaultHttpClient(httpParameters);
    String url = "http://10.0.0.30//parsing/GCM.php?" + "&regID="
      + regId;
    Log.i("Send URL:", url);
    HttpGet request = new HttpGet(url);

    response = client.execute(request);

    BufferedReader rd = new BufferedReader(new InputStreamReader(
      response.getEntity().getContent()));

    String webServiceInfo = "";
    while ((webServiceInfo = rd.readLine()) != null) {
     Log.d("****Status Log***", "Webservice: " + webServiceInfo);

    }
   } catch (Exception e) {
    e.printStackTrace();
   }
   return null;

  }

  @Override
  protected void onPostExecute(String result) {
   pd.dismiss();

  }

 }

}
2)GCMIntentService.java
package com.manish.gcm.push;

import static com.manish.gcm.push.CommonUtilities.SENDER_ID;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.util.Log;

import com.google.android.gcm.GCMBaseIntentService;

public class GCMIntentService extends GCMBaseIntentService {

 public GCMIntentService() {
  super(SENDER_ID);
 }

 private static final String TAG = "===GCMIntentService===";

 @Override
 protected void onRegistered(Context arg0, String registrationId) {
  Log.i(TAG, "Device registered: regId = " + registrationId);
 }

 @Override
 protected void onUnregistered(Context arg0, String arg1) {
  Log.i(TAG, "unregistered = " + arg1);
 }

 @Override
 protected void onMessage(Context context, Intent intent) {
  Log.i(TAG, "new message= ");
  String message = intent.getExtras().getString("message");
  generateNotification(context, message);
 }

 @Override
 protected void onError(Context arg0, String errorId) {
  Log.i(TAG, "Received error: " + errorId);
 }

 @Override
 protected boolean onRecoverableError(Context context, String errorId) {
  return super.onRecoverableError(context, errorId);
 }

 /**
  * Issues a notification to inform the user that server has sent a message.
  */
 private static void generateNotification(Context context, String message) {
  int icon = R.drawable.ic_launcher;
  long when = System.currentTimeMillis();
  NotificationManager notificationManager = (NotificationManager) context
    .getSystemService(Context.NOTIFICATION_SERVICE);
  Notification notification = new Notification(icon, message, when);
  String title = context.getString(R.string.app_name);
  Intent notificationIntent = new Intent(context, MainActivity.class);
  notificationIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP
    | Intent.FLAG_ACTIVITY_SINGLE_TOP);
  PendingIntent intent = PendingIntent.getActivity(context, 0,
    notificationIntent, 0);
  notification.setLatestEventInfo(context, title, message, intent);
  notification.flags |= Notification.FLAG_AUTO_CANCEL;
  notificationManager.notify(0, notification);
 }
}

3)CommonUtilities .java
package com.manish.gcm.push;

public final class CommonUtilities {
//put here your sender Id
static final String SENDER_ID = "311451115764";

}

4)activity_main.xml


    


5)manifest.xml


    

    

    
    
    
    
    

    
        
            
                

                
            
        

        
            
                
                

                
            
        

        
    


6)Download Zip Code

Thanks,
Please write your comment and feedback below:

61 comments :

  1. Nice tutorial can you please help me? how to use sql database to send push?

    ReplyDelete
    Replies
    1. Please see demo i am using mysql. You can use any...

      Delete
  2. Hi Can u upload the whole project source code ...
    I thinks it's gonna be more helpful for us than some peace of code.
    the project can be built .
    Thanks in advance.

    ReplyDelete
  3. Hi, I'm new to java and android but I think there could be a problem with your example.
    If the device has not registered before, GetRegistrationId will return an empty string and so you then call register. That returns the new registrationId in the GCMIntentService as a local variable.
    So when you call sendIdOnOverServer the registrationId might not have been received but even if it has been received, it will not be the registrationId that is sent to the server in MainActivity. That one will still be blank.

    Or am I missing something?

    Thanks.

    ReplyDelete
    Replies
    1. No no this demo always send registration id before get a push..
      It should not be blank any time...
      I have tested it no issue here and i am using it in my app also...

      Delete
  4. I'm sure you know your program better than I do but I'm confused as to how it is working. This is how I see it:

    The first ever time you call getRegistrationId it will return an empty string. You then call register to get a regId from GCM but that call returns immediately and the regId is returned seconds later in the intent service.

    You call sendIdOnOverServer immediately after the call to register and hence regId will be empty at that time so an empty string will be sent to your server.

    The next time the progam runs, it will work fine because getRegistrationId will return the last registration and so regId will not now be empty and so a valid regId will be sent to your server.

    If I am wrong about this I'd appreciate to know how it works. I can understand that your app may work long term but I think first time, it will effectively fail.

    ReplyDelete
    Replies
    1. No John its work all time fine because this app send registration id on server every time.. I have tested it..

      Delete
  5. upload full project source code please

    ReplyDelete
    Replies
    1. Sure I will Upload on GIT server, keep in touch..

      Thanks,

      Delete
  6. Hello Manish thanks for your tutorial. but i think there is a problem..

    in your manifest file you are declaring
    android:minsdkversion="7"

    but i think it should be
    GCM requires Android SDK version 2.2 (API level 8) or above.
    android:minSdkVersion="8"

    Deepak

    ReplyDelete
    Replies
    1. Yes may be if google not allow us we can't send push message..

      Delete
  7. This comment has been removed by the author.

    ReplyDelete
    Replies
    1. Note down the project id which will be used as SENDER ID in android project=311451115764;

      Delete
  8. sender Id is project_Id? and i have copied your code in that "GCM registrar" shown error line...!pls help brothr

    ReplyDelete
    Replies
    1. Yes sender id= project id..
      Where you are facing trouble please let me know..

      Delete
  9. Nice tutorial,it shows error in this line...public class sendIdOnOverServer extends AsyncTask, the error is Syntax error on tokens, Dimensions expected instead. I am using ROR framework,do you know how to write server side code for that one to send push notification,if i add data in server the push notification has to come in my android apps.Help me dude

    ReplyDelete
    Replies
    1. I am using eclipse, and code is working for me.I have put all code of=n Git Server please download from there. And a download link on my post also.

      https://github.com/manishsri01/GCMPushDemo

      Thanks,

      Delete
  10. The code is completely mangled up, probably a fault of the syntax highlighter, but it ruins the entire tut.

    For e.g. a theres a complete loss of capitalization in the xml tags for (also in the manifest):





    ReplyDelete
    Replies
    1. I have add a download link on my post please download zip code and try again...

      Thanks,

      Delete
  11. This comment has been removed by the author.

    ReplyDelete
  12. Hi Manish, Is there anyway to contact you via chat?

    ReplyDelete
    Replies
    1. Can you share your problem here? It will usefull to others visitor. Well you can email me at manishupacc@gmail.com

      Delete
  13. Hi Manish,

    It is a nice tutorial but I see your GCM.php starts with some weird syntax. Can you clarify the GCM.php file. it gives error of variable registatoion_ids and msg not defined.

    Thanks

    ReplyDelete
    Replies
    1. Hello Pragmatute!

      Thanks for your suggestion, I change the code please check now...

      Delete
  14. Hi Manish,

    It is a nice tutorial but I have doubt when we get $_GET['regID'];

    ReplyDelete
    Replies
    1. It is not working?
      It should work any problem in code?

      Delete
    2. No problem in code but its my doubt
      How we get registration id?

      Delete
    3. You will get reg-id from client side in this method-
      http://10.0.0.30//parsing/GCM.php?&regID=+regId

      Delete
    4. Hi
      When i use this code i get the following error

      {"error":"InvalidRegistration"}

      Delete
    5. Have you short out problem? Have you created new project on Google developer?

      Delete
  15. This comment has been removed by the author.

    ReplyDelete
  16. in logcate it's display

    09-17 12:22:40.017: V/GCMRegistrar(342): Registering app com.manish.gcm.push of senders 386632392116
    09-17 12:22:40.017: V/GCMRegistrar(342): Creating pending intent to get package name
    09-17 12:22:40.297: V/GCMBroadcastReceiver(342): onReceive: com.google.android.c2dm.intent.REGISTRATION
    09-17 12:22:40.297: V/GCMBroadcastReceiver(342): GCM IntentService class: com.manish.gcm.push.GCMIntentService
    09-17 12:22:40.327: I/Send URL:(342): http://10.0.2.2//parsing/GCM.php?&regID=
    09-17 12:22:40.357: V/GCMBaseIntentService(342): Intent service name: GCMIntentService-386632392116-3
    09-17 12:22:40.387: D/GCMBaseIntentService(342): handleRegistration: registrationId = null, error = ACCOUNT_MISSING, unregistered = null
    09-17 12:22:40.387: D/GCMBaseIntentService(342): Registration error: ACCOUNT_MISSING
    09-17 12:22:40.387: I/===GCMIntentService===(342): Received error: ACCOUNT_MISSING
    09-17 12:22:40.527: I/global(342): Default buffer size used in BufferedReader constructor. It would be better to be explicit if an 8k-char buffer is required.

    i have few question pls help me
    i had set senderid as per google account regiser
    i had make GCM.php file put it into parsing/GCM.php file in wamp server
    but i had not create any talbe nothing so where it store?
    second thing how can i send any message on device using this?

    ReplyDelete
  17. Hi Pankaj!

    Let me clear all of your doubts.

    1)Its not must your device return always registration id. Please try 1-3 time if you did not got registration id in your application.

    2)Here we are not storing any thing in database just we are getting registration-id from device and we hit the google server and google send push message on mobile device.

    3)Please check your project on google developer console and put sender-id same as your project-id, both are same.

    4)In your php code change 'Authorization: key=AIzaSyA46UE7bBWXCpHSD5sbNxbRwI1MAKVI-jg', with your project key generated by you.

    Note: I think you are using same package name whats in my demo app so be sure your application package name should be same on Google console. I think you should change package name in your android code and create new project on Google console.

    Here I am explaining php code line by line hope it will help you.

    'HI Manish'); //here I create json array message to send to user device
    $url='https://android.googleapis.com/gcm/send'; //this is url where we hit for sending push message on device from php server
    $fields=array
    (
    'registration_ids'=>$registatoin_ids,
    'data'=>$msg
    );
    $headers=array
    (
    'Authorization: key=AIzaSyA46UE7bBWXCpHSD5sbNxbRwI1MAKVI-jg', //this is your google app project key
    'Content-Type: application/json'
    );
    $ch=curl_init(); // init method is used for start curl
    curl_setopt($ch,CURLOPT_URL,$url);
    curl_setopt($ch,CURLOPT_POST,true);
    curl_setopt($ch,CURLOPT_HTTPHEADER,$headers);
    curl_setopt($ch,CURLOPT_RETURNTRANSFER,true);
    curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,false);
    curl_setopt($ch,CURLOPT_POSTFIELDS,json_encode($fields));
    $result=curl_exec($ch);
    curl_close($ch);
    echo $result; // it will return result
    ?>


    ReplyDelete
  18. Hi this is Maheswaran, I get only the empty Reg Id while I am running your demo app. I want to send notification to my application users when created a new Events, Can u please help me to integrate your code in my app?

    ReplyDelete
    Replies
    1. Have you check all necessary thing like manifest permissions? and You are using mobile device instead of emulator ? and have you created your own project on Google Developer and change project-key with yours?

      Delete
  19. Yes, I have checked everything what you are asking me, Is it possible to send notification to multiple users? I am using Emulator only not a mobile. Can you please come to chat? mmaheswaran87@gmail.com this my mail ID.

    ReplyDelete
    Replies
    1. Please use mobile device instead of emulator, because we can't guaranty its give you reg-id. And yes I have messaged you check your gtalk.

      Delete
  20. Hello Manish .....


    I just download the whole source code to see how it works. I've use my sender ID and uploaded the GCM.php file on my server. But when i run the app it just give me a screen tell " RegId = "

    Any Idea why so ?

    ReplyDelete
    Replies
    1. Are you using mobile phone? And please see log cat. may be there correct reg-id. And please try 1-2 time may be in first time we did not reg-id.

      Delete
  21. Can we send notification to IPHONE from android? This is, if my application installed in IPhone means, the notification will send or not?

    ReplyDelete
    Replies
    1. No dear you can't send notification to IPHONE from android device. You should use APNS(apple push notification services) for that.

      Delete
  22. Is it any possible to send notification to IPhone device through this code? I can send notification to Android Mobiles.

    ReplyDelete
    Replies
    1. See dear both are competitor and they will not allow for messaging between each other. write web-service in php and use GCM for android and APNS for iphone and send push message from php server. I think this is the best way..

      Delete
  23. when im trying to import this app zip its telling no projects are found to import. could you please solve this problem?
    advance thanks for solving this

    ReplyDelete
    Replies
    1. Don't import, create new project from exiting code.

      Delete
  24. Hii Manish,,Great thanks for this tutorial

    ReplyDelete
  25. Hii Manish,Thanks for saving My Time......Great Work

    ReplyDelete
  26. Hello Manish the demo works fine on my device but all I see is the regID. How can i get to see the messege "Hi Minash"

    ReplyDelete
  27. Hi Manish,
    I am following this tutorial, I am able to get reg Id for android emulator in which I have configure google account, so my android app side is ok, but to register application server i.e tomcat to c2dm i am using java REST web service in place of your php web service calling. Here from web service i am getting 401 response code and not getting push message from c2dm.
    I have changed your web service calling line i.e String url = "http://10.0.0.30//parsing/GCM.php?" + "&regID=" + regId; r with my webservice calling i.e String url = "http://my_ip_add:port_number/Operations/registertogoogle?" + "&registrationid=" + regId;

    and web service is code is as follows:

    @Path("/registertogoogle")
    @GET
    @Produces("application/json")
    public String registertogoogle(@QueryParam("registrationid") String registrationid)
    {
    System.out.println(" register google:"+registrationid);
    //GetAuthenticationToken.setAuthentication();
    String auth_token="key=AIzaSyB6w2Acf4C3DN2IPefgXd-etU9SQqpzuAo";
    //"key=AIzaSyB6w2Acf4C3DN2IPefgXdetU9SQqpzuAo";//ServerConfiguration.getAUTHENTICATION_TOKEN();
    System.out.println("authtocken:"+auth_token);

    JSONObject jsonObject = new JSONObject();
    try {
    StringBuilder postDataBuilder = new StringBuilder();
    postDataBuilder.append(PARAM_REGISTRATION_ID).append("=")
    .append(registrationid);
    postDataBuilder.append("&").append(PARAM_COLLAPSE_KEY).append("=")
    .append("0");
    postDataBuilder.append("&").append("data.payload").append("=")
    .append(URLEncoder.encode("This works fine", UTF8));

    byte[] postData = postDataBuilder.toString().getBytes(UTF8);

    // Hit the dm URL.

    URL url = new URL("https://android.apis.google.com/c2dm/send");//https://android.clients.google.com/c2dm/send");
    HttpsURLConnection
    .setDefaultHostnameVerifier(new CustomizedHostnameVerifier());
    HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
    conn.setDoOutput(true);
    conn.setUseCaches(false);
    conn.setRequestMethod("POST");
    conn.setRequestProperty("Content-Type",
    "application/x-www-form-urlencoded;charset=UTF-8");
    conn.setRequestProperty("Content-Length",
    Integer.toString(postData.length));
    conn.setRequestProperty("Authorization", auth_token);//"GoogleLogin auth=" +
    System.out.println("Connectopn:"+conn.toString());
    OutputStream out = conn.getOutputStream();
    out.write(postData);
    out.close();

    int responseCode = conn.getResponseCode();
    System.out.println("responsecode:"+responseCode);
    jsonObject.put("responsecode",responseCode);

    } catch (JSONException e) {
    e.printStackTrace();
    } catch (UnsupportedEncodingException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    } catch (MalformedURLException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    } catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    }
    return jsonObject.toString();
    }

    private static class CustomizedHostnameVerifier implements HostnameVerifier {
    public boolean verify(String hostname, SSLSession session) {
    return true;
    }
    }
    I have searched for 401 error code it's about authentication but not able to get exact solution to fix this issue, could please give your suggestion!!!!!

    ReplyDelete
    Replies
    1. Sorry Dear i have no more idea about web-services so I can't say anything. well error 401 means "Authorization Required error" That mean your server or Google server some where authentication is required.

      Delete
  28. I have download this code from this link https://github.com/manishsri01/GCMPushDemo . But when I import this project in eclipse . It will not import and error is that "No projects are found to import". give me solution ?

    ReplyDelete
    Replies
    1. Please go through file menu and and create new project using exciting code.

      Delete
  29. Hi Marnish,
    Nice tutorial and I have copied your source code in my apps and it works. However, i have little problem.
    It seems I have got the registration ID but I in the app, it always shows "RegId=", however, i can see i have got the id in the cat log:03-29 19:06:41.241: I/===GCMIntentService===(7156): Device registered: regId = APA91bFFkVQMPl5SAQtofT-KXu5OwsU7sY2dFfRs5P0PyGFrjMxkwjr3k38M5C_k7as71bqEkYzP6sHSDVo0R9qqZ4Qsj0z2vIO7kPsbX77ta20nYa2HH3aBy-gnb4WChJKaNrC1R2hF0M3fwF_kMkMcsR2vqJFfKA


    But in the status log, it create error:
    03-29 19:06:42.151: D/****Status Log***(7156): Webservice: {"multicast_id":6265367446240819368,"success":0,"failure":1,"canonical_ids":0,"results":[{"error":"MissingRegistration"}]}
    03-29 19:06:42.191: E/ViewRootImpl(7156): sendUserActionEvent() mView == null\

    could you please help me? thanks!!

    ReplyDelete
    Replies
    1. Please add this line inside onPostExcute() method -
      mDisplay.setText("RegId=" + regId);

      Delete
  30. Part - A
    Number : 8

    what i add in Accept requests from these server IP addresses:???

    i can not get RegId now .

    i change SenderID in Java class and API key in PHP

    ReplyDelete
  31. In my case, 9 out of 10 times sendIdOnOverServer has been executed before GCMRegistrar returns an ID. Logcat shows one second difference between sending ID and GCMBaseIntent.handleregistration. How to avoid empty RegId strings?

    Peet

    ReplyDelete