Android Push Notification using Google Cloud Messaging (GCM) – Part 2

If you are here, you are already done with Google API Console Registration and WebServer Configuration. If not, it is suggested to refer Google API Console Registration and WebServer Configuration before proceeding further.

GCM Enabled Android Application

[su_carousel source=”media: 333,334″ link=”lightbox” width=”700″ height=”600″ items=”2″ title=”no” mousewheel=”no”]

[su_button url=”http://cs2guru.com/samples/GCMSample.zip” target=”blank” style=”soft” background=”#51d461″ color=”#ffffff” size=”6″ center=”yes” icon=”icon: arrow-circle-o-down”]Download Complete Source Code[/su_button]

1. Setting Google Play Service For enabling support, Google Play Services library is required to add in project. Refer to Google Play Services Setup.

If you are eclipse user, Go to menu Window -> Android SDK Manager -> Extras. Install Google Play Service library from there. It will be downloaded to “sdk\extras\google\google_play_services”.

2. Preparing application manifest Add following permissions in your application manifest file. Declare a receiver in your manifest to receive GCM message and registration id. Add meta data for google play services. Add a service for handling GCM messages in background. Replace all occurrences of com.androidsrc.gcmsample with your package name.

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.androidsrc.gcmsample"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="14"
        android:targetSdkVersion="21" />

	<!-- For accessing Internet -->
    <uses-permission android:name="android.permission.INTERNET"/>
    <!-- For checking current network state -->
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
    <!-- For waking device from sleep for showing notification -->
    <uses-permission android:name="android.permission.WAKE_LOCK"/>
    <!-- For vibrating device -->
    <uses-permission android:name="android.permission.VIBRATE"/>
    <!-- For receiving GCM messages -->
    <uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
    <!-- For protecting GCM messages so that only your app can receive them -->
    <permission
        android:name="com.androidsrc.gcmsample.permission.C2D_MESSAGE"
        android:protectionLevel="signature" />
    <uses-permission android:name="com.androidsrc.gcmsample.permission.C2D_MESSAGE" />

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

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

 		<!-- For receiving GCM message and registration success -->
        <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.androidsrc.gcmsample" />
            </intent-filter>
        </receiver>

        <service android:name=".GCMIntentService" />
         <!-- make sure to add google-play-services_lib from  project properties->android->library-->
         <meta-data
            android:name="com.google.android.gms.version"
            android:value="@integer/google_play_services_version" />
    </application>

</manifest>

 

3. Setting up UI We will keep it simple. Our launcher activity will have simple one button to register it with GCM server. And one text view for showing registration id after successful registration. Modify your layout res/layout/activity_main.xml as below.

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center"
    android:orientation="vertical"
    tools:context="com.androidsrc.gcmsample.MainActivity" >
    <Button
        android:id="@+id/register_gcmserver"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:gravity="center_vertical|center_horizontal"
        android:text="Register with GCM Server" />
    <TextView
        android:id="@+id/regId"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="20dp"
        android:gravity="center_vertical|center_horizontal"
        android:textSize="30dp" />
</LinearLayout>

 

4. Setting up SRC files

Create GCMBroadcastReceiver which will extend WakefulBroadcastReceiver in order to keep device awake while processing message from GCM.

package com.androidsrc.gcmsample;

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) {
        // Attach component of GCMIntentService that will handle the intent in background thread
        ComponentName comp = new ComponentName(context.getPackageName(),
                GCMIntentService.class.getName());
        // Start the service, keeping the device awake while it is launching.
        startWakefulService(context, (intent.setComponent(comp)));
        setResultCode(Activity.RESULT_OK);
    }
}

 

Create service GCMIntentService which will extend IntentService to perform task of showing notification in a background thread.

package com.androidsrc.gcmsample;

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.support.v4.app.NotificationCompat;

public class GCMIntentService extends IntentService {

    public static final int NOTIFICATION_ID = 1000;
    NotificationManager mNotificationManager;
    NotificationCompat.Builder builder;

    public GCMIntentService() {
        super(GCMIntentService.class.getName());
    }

    @Override
    protected void onHandleIntent(Intent intent) {
        Bundle extras = intent.getExtras();

        if (!extras.isEmpty()) {

            // read extras as sent from server
            String message = extras.getString("message");
            String serverTime = extras.getString("timestamp");
            sendNotification("Message: " + message + "\n" + "Server Time: "
                    + serverTime);
        }
        // Release the wake lock provided by the WakefulBroadcastReceiver.
        GCMBroadcastReceiver.completeWakefulIntent(intent);
    }

    private void sendNotification(String msg) {
        mNotificationManager = (NotificationManager) 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.ic_launcher)
                .setContentTitle("Notification from GCM")
                .setStyle(new NotificationCompat.BigTextStyle().bigText(msg))
                .setContentText(msg);

        mBuilder.setContentIntent(contentIntent);
        mNotificationManager.notify(NOTIFICATION_ID, mBuilder.build());
    }
}

 

In MainActivity.java, on clicking of register button we will handle task of registering our application with help of GoogleCloudMessaging api’s. After getting registration id from GCM, we will register with our web server for saving registration id.

package com.androidsrc.gcmsample;

import android.app.Activity;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.text.TextUtils;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;

import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GooglePlayServicesUtil;
import com.google.android.gms.gcm.GoogleCloudMessaging;

import java.io.IOException;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.ProtocolException;
import java.net.URL;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;

public class MainActivity extends Activity {

    // Resgistration Id from GCM
    private static final String PREF_GCM_REG_ID = "PREF_GCM_REG_ID";
    private SharedPreferences prefs;
    // Your project number and web server url. Please change below.
    private static final String GCM_SENDER_ID = "YOUR_PROJECT ID";
    private static final String WEB_SERVER_URL = "YOUR_WER_SERVER_URL";

    GoogleCloudMessaging gcm;
    Button registerBtn;
    TextView regIdView;

    private static final int ACTION_PLAY_SERVICES_DIALOG = 100;
    protected static final int MSG_REGISTER_WITH_GCM = 101;
    protected static final int MSG_REGISTER_WEB_SERVER = 102;
    protected static final int MSG_REGISTER_WEB_SERVER_SUCCESS = 103;
    protected static final int MSG_REGISTER_WEB_SERVER_FAILURE = 104;
    private String gcmRegId;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        registerBtn = (Button) findViewById(R.id.register_gcmserver);
        registerBtn.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                // Check device for Play Services APK.
                if (isGoogelPlayInstalled()) {
                    gcm = GoogleCloudMessaging.getInstance(getApplicationContext());

                    // Read saved registration id from shared preferences.
                    gcmRegId = getSharedPreferences().getString(PREF_GCM_REG_ID, "");

                    if (TextUtils.isEmpty(gcmRegId)) {
                        handler.sendEmptyMessage(MSG_REGISTER_WITH_GCM);
                    } else {
                        regIdView.setText(gcmRegId);
                        Toast.makeText(getApplicationContext(), "Already registered with GCM", Toast.LENGTH_SHORT).show();
                    }
                }

            }
        });
        regIdView = (TextView) findViewById(R.id.regId);
    }

    private boolean isGoogelPlayInstalled() {
        int resultCode = GooglePlayServicesUtil
                .isGooglePlayServicesAvailable(this);
        if (resultCode != ConnectionResult.SUCCESS) {
            if (GooglePlayServicesUtil.isUserRecoverableError(resultCode)) {
                GooglePlayServicesUtil.getErrorDialog(resultCode, this,
                        ACTION_PLAY_SERVICES_DIALOG).show();
            } else {
                Toast.makeText(getApplicationContext(),
                        "Google Play Service is not installed",
                        Toast.LENGTH_SHORT).show();
                finish();
            }
            return false;
        }
        return true;

    }

    private SharedPreferences getSharedPreferences() {
        if (prefs == null) {
            prefs = getApplicationContext().getSharedPreferences(
                    "AndroidSRCDemo", Context.MODE_PRIVATE);
        }
        return prefs;
    }

    public void saveInSharedPref(String result) {
        // TODO Auto-generated method stub
        Editor editor = getSharedPreferences().edit();
        editor.putString(PREF_GCM_REG_ID, result);
        editor.commit();
    }

    Handler handler = new Handler() {
        public void handleMessage(android.os.Message msg) {
            switch (msg.what) {
                case MSG_REGISTER_WITH_GCM:
                    new GCMRegistrationTask().execute();
                    break;
                case MSG_REGISTER_WEB_SERVER:
                    new WebServerRegistrationTask().execute();
                    break;
                case MSG_REGISTER_WEB_SERVER_SUCCESS:
                    Toast.makeText(getApplicationContext(),
                            "registered with web server", Toast.LENGTH_LONG).show();
                    break;
                case MSG_REGISTER_WEB_SERVER_FAILURE:
                    Toast.makeText(getApplicationContext(),
                            "registration with web server failed",
                            Toast.LENGTH_LONG).show();
                    break;
            }
        }

        ;
    };

    private class GCMRegistrationTask extends AsyncTask<Void, Void, String> {

        @Override
        protected String doInBackground(Void... params) {
            // TODO Auto-generated method stub
            if (gcm == null && isGoogelPlayInstalled()) {
                gcm = GoogleCloudMessaging.getInstance(getApplicationContext());
            }
            try {
                gcmRegId = gcm.register(GCM_SENDER_ID);
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }

            return gcmRegId;
        }

        @Override
        protected void onPostExecute(String result) {
            if (result != null) {
                Toast.makeText(getApplicationContext(), "registered with GCM",
                        Toast.LENGTH_LONG).show();
                regIdView.setText(result);
                saveInSharedPref(result);
                handler.sendEmptyMessage(MSG_REGISTER_WEB_SERVER);
            }
        }
    }

    private class WebServerRegistrationTask extends AsyncTask<Void, Void, Void> {

        @Override
        protected Void doInBackground(Void... params) {
            URL url = null;
            try {
                url = new URL(WEB_SERVER_URL);
            } catch (MalformedURLException e) {
                e.printStackTrace();
                handler.sendEmptyMessage(MSG_REGISTER_WEB_SERVER_FAILURE);
            }
            Map<String, String> dataMap = new HashMap<String, String>();
            dataMap.put("regId", gcmRegId);

            StringBuilder postBody = new StringBuilder();
            Iterator iterator = dataMap.entrySet().iterator();

            while (iterator.hasNext()) {
                Entry param = (Entry) iterator.next();
                postBody.append(param.getKey()).append('=')
                        .append(param.getValue());
                if (iterator.hasNext()) {
                    postBody.append('&');
                }
            }
            String body = postBody.toString();
            byte[] bytes = body.getBytes();

            HttpURLConnection conn = null;
            try {
                conn = (HttpURLConnection) url.openConnection();
                conn.setDoOutput(true);
                conn.setUseCaches(false);
                conn.setFixedLengthStreamingMode(bytes.length);
                conn.setRequestMethod("POST");
                conn.setRequestProperty("Content-Type",
                        "application/x-www-form-urlencoded;charset=UTF-8");

                OutputStream out = conn.getOutputStream();
                out.write(bytes);
                out.close();

                int status = conn.getResponseCode();
                if (status == 200) {
                    // Request success
                    handler.sendEmptyMessage(MSG_REGISTER_WEB_SERVER_SUCCESS);
                } else {
                    throw new IOException("Request failed with error code "
                            + status);
                }
            } catch (ProtocolException pe) {
                pe.printStackTrace();
                handler.sendEmptyMessage(MSG_REGISTER_WEB_SERVER_FAILURE);
            } catch (IOException io) {
                io.printStackTrace();
                handler.sendEmptyMessage(MSG_REGISTER_WEB_SERVER_FAILURE);
            } finally {
                if (conn != null) {
                    conn.disconnect();
                }
            }

            return null;
        }
    }
}

We are done with Sample GCM Application. After registration, Go to your web server and try sending message to registered devices via GCM. You will receive push notification from GCM server.

You may also like...

37 Responses

  1. johndoe says:

    Message and Server Time are coming in as null?

  2. Nelson Díaz Nuñez says:

    and how can i unregister to the service?

    • Blair Doyle says:

      Did you every sort this out? Unregistering works in a strange way in that the client will be automatically unregistered if a GCM message is pushed to the device and the app is no longer installed.

      Problem you can run into with this tutorial is if you successfully register to GCM but fail to input the client ID into your web server.. you now have a registered device that wont push the data to the web server after you solved the problem.

      I solved that only by artificially inputting the client ID into the MySQL DB and sending a push message while the app was not on my device. Next install it worked.

    • Jatin Rane says:

      Just Uninstall it !!

  3. Ravi Sanchala says:

    Hi,
    Really great tutorial .. its working perfectly fine for me … and thanks for this tutorial
    i was wondering .. that can i send the image message also using GCM and if yes can you please guide..

    thanks in advance…
    cheers 🙂

    • Mahadev Prasad says:

      Sir, can you give some inputs how you are able to achieve? what are the changes you have done. The tutorial, straight out of the box not working. You can share the complete code files also.

      In my case the device is registered in Web server without problem. But
      the message is not delivering. There is no clear information with
      screenshots in the PHP webserver tutorial. The index.php is showing the
      number of users registered with the register IDs. But when I type
      message in the text area box and submit, there is no confirmation
      message appearing on the screen about what happened to this message.
      But, the message is not delivered to Device. I have tried all the
      changes suggested here but no success.

      Your input will help so many peoples.

  4. Lucas Soares says:

    Hi. The registration with the webservice always failed. Can anyone help me?

    • Harry Martin says:

      I would recommend you to get the services from experts mentioned here http://learnsauce.com/googlecloudmessagingtutorial/ The tutorials comes for FREE with 100% source code.

      • Mahadev Prasad says:

        I have gone there and downloaded the GCM project sources files and worked as per their instructions. But, that project is also imperfect and no use unless you have ability to de-bug the code.

        Surprisingly the said website uses the same Code given in this blog for server side and part of the code for client side applications authored by Ravi Tamada, but seems to be latest. Some of the errors mentioned here were corrected and user registration is expanded with input of User Name and Mail Id.

        The main drawback and the funny thing of the project source is, the server side coding and messaging(browser) interface is having GCM push concept(copy of the same code in this blog). Whereas, the Client side code is having Device to Device Chatting Code. The message sent from server is not delivered to devices.

        Either way, the description of the project is misguiding and I really unable to understand, why these people do not test their files thoroughly before distributing, and extend further help by answering the queries raised in the forum/comments.

    • Blair Doyle says:

      If you used the first part of this tutorial, you may encounter an issue in the register_user.php

      line 9 , the tutorial has this in the code:

      if (isset(isset($_POST[“regId”])) {

      Adjust it to read:

      if (isset($_POST[“regId”])) {

      Hope that helps!

    • Mahadev Prasad says:

      Do not forget to check the error in the ‘db_functions.php’ INSERT query it is mentioned table ‘reg_users’ in another place SELECT query it is mentioned as ‘users’. Update both with identical name.

      In my case the device is registered in Web server without problem. But the message is not delivering. There is no clear information with screenshots in the PHP webserver tutorial. The index.php is showing the number of users registered with the register IDs. But when I type message in the text area box and submit, there is no confirmation message appearing on the screen about what happened to this message. But, the message is not delivered to Device. I have tried all the changes suggested here but no success.

      I request the writer of this tutorial to give some more information on the above. Even, the writer has not corrected the identified mistakes in the tutorials. If out of 100, one or two getting success with their efforts by de-bugging the code, then there is no point in writing this type of incomplete tutorials. We have to remove everything from device, webserver and look for different tutorials. By that time, lot of time and efforts are wasted.

      • Arcenio says:

        Heya! The RegId that is saved in the database seems to turn into a random jumbled combination of characters and integers and NOT the one initialized here:

        private static final String PREF_GCM_REG_ID = “chars-3dd1e”;

        Is this supposed to be correct? or am i doing something wrong? thanks!

  5. shaymol says:

    how can I get this PREF_GCM_REG_ID

  6. Seetharaman says:

    Hi I followed this tutorial and implemented GCM in one of my prod app,device getting registered well but I am facing a serious issue that for few users of my app gcm.register(GCM_SENDER_ID) giving empty registration id almost for 2 out of every 10 users i am seeing this issue,i faced this issue with my device itself but if i uninstall and reinstall app then registration id is getting generated Please help me out to resolve this issue as my app is a prod app with daily more than 300 users coming in.

  7. Bryan Torres Vega says:

    I’m getting the “registration with web server failed” and another question guys what am I suppose to put in the PREF_GCM_REG_ID ?

  8. Nork says:

    ERES UN CRACK TIOOOOOOOOOOOO!!! GRACIAS!!

  9. Pritish Joshi says:

    I followed the Tutorial and successfully registerd with GCM?

    but the problem is how can i send push notification

    because my index.php shows that ) connected users

  10. ulimhd says:

    I managed to receive the notification on my Bluestacks emulator.

    Here’s what I did (basically I did what the other suggested in this comment section):

    1. In the register_user.php file, change the line
    if (isset(isset($_POST[“regId”])) {
    to
    if (isset($_POST[“regId”])) {

    2. in the db_functions.php file, edit the table name “users” to “reg_users”

    3. in the device_sendmsg.php file, edit the part
    $message = array(“Hello Zelda” => $message);
    to add timestamp, for example
    $message = array(“message”=>$message, “timestamp”=>”04-01-2016”;

    4. put register_user.php in the WEB_SERVER_URL part in MainActivity.java

    • ulimhd says:

      So I have found what cause the problem. It seems that my phone was really already registered with gcm, but the regId is not registered in my database. The logical thing to do is to unregister my phone from gcm. But first I should add the regId to my reg_users table manually.

      Following this link: http://stackoverflow.com/a/16279189 , to unregister your device from gcm is by uninstalling the apps and try to send message again to the device. The device regId will still exists in your database, so you could still see it when open index.php . It is said it will take 5 minutes before the device fully unregistered from gcm, but I could not confirm this.

  11. sunny sun says:

    it doesn’t work with me and give me errors

  12. sunny sun says:

    The registration process is going well but no notification is coming , could you plz help me ?

  13. rabih kahaleh says:

    hello there,
    i faced the following error
    FATAL EXCEPTION: AsyncTask #1

    java.lang.RuntimeException: An error occurred while executing doInBackground()

    at android.os.AsyncTask$3.done(AsyncTask.java:309)

    at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:354)

    at java.util.concurrent.FutureTask.setException(FutureTask.java:223)

    at java.util.concurrent.FutureTask.run(FutureTask.java:242)

    at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:234)

    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113)

    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588)

    at java.lang.Thread.run(Thread.java:818)

    Caused by: java.lang.RuntimeException: Can’t create handler inside thread that has not called Looper.prepare()

    at android.os.Handler.(Handler.java:200)

    at android.os.Handler.(Handler.java:114)

    at android.widget.Toast$TN.(Toast.java:685)

    at android.widget.Toast.(Toast.java:143)

    at android.widget.Toast.makeText(Toast.java:450)

    at android.os.AsyncTask$2.call(AsyncTask.java:295)

    at java.util.concurrent.FutureTask.run(FutureTask.java:237)

    at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:234)

    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113)

    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588)

    at java.lang.Thread.run(Thread.java:818)

  14. Andrea says:

    Hi! I also had a problem with sending notifications and I solved it!

    There is an error in gcm_sendmsg.php. Change “include_once ‘./config.php’;” with “include_once ‘./db_config.php’;”

    • Andrea says:

      sorry, i’ve made a mistake. I had changed the name of the config.php file when i create it. anyway, the tutorial works correctly for me.

  15. Jatin Rane says:

    Thanks for the tutorial !!

  16. dhika. says:

    hello sir, i have a problem, my phone is successfully registered with CGM server, but my server cant send a message to my phone, can you help me?

  1. January 30, 2015

    […] 2. Developing GCM supported Android Application […]

  2. August 3, 2016

    […] Then the token is send to the ESP8266. Check this website how to get the token from the GCM server: Android Push Notification using Google Cloud Messaging (GCM) – Part 2. In this code you can find: new WebServerRegistrationTask().execute();. This Java class is used to […]

  3. January 27, 2018

    […] The small application I used to test the functions is a slightly changed version of the application provided by Android Push Notification using Google Cloud Messaging (GCM) – Part 2 […]

Leave a Reply

Your email address will not be published. Required fields are marked *