Android Development #7: Google Cloud Messaging (GCM) Push Messaging

First posted on 09/07/2014

Basic GCM Architecture

Basically, the prerequisites to make push messaging works are,

  1. Google Cloud Messaging API (Cloud)
  2. Application Server (Server)
  3. Android App (Client)

Fundamental Steps

Quick overview on the steps to implement GCM into your app

  1. Register to Google Cloud Messaging API
    • Create new project
    • Acquire Project ID and API Key
  2. Create our own server (in PHP)
    • Must have registration_id field
  3. Create our own Android app client
    • Install Google Play Services SDK

REGISTER TO GOOGLE CLOUD MESSAGING API

Procedure on how to register our project to Google API

Click for image

CREATE OUR SERVER (IN PHP)

  1. Create Database
    • Create a new db called GCMDemo
    • Run query
CREATE TABLE  'GCMDemo'.'tblRegistration' (
 'id' INT( 10 ) NOT NULL AUTO_INCREMENT PRIMARY KEY ,
 'registration_id' TEXT NOT NULL
 ) ENGINE = INNODB;
  1. Put these scripts into your server
    • index.php
      You'll have a page where you can send message to devices registered in your server. Click here for connection.php for this project. Make sure to change YOUR_KEY_HERE to your API auth key.
	<html>
	<head>
	  <title>GCM Demo application</title>
	</head>
	<body>
	<?php
	  include("connection.php");

	  /*  it sends the message to the application and echo back the response from the GCM server. */


	  if(isset($_POST['submit'])){ 
	 
	    $registration_ids = array();
	    $query = "SELECT * FROM `users`";
	    $result = $mysqli->query($query) or die ($mysqli->error.__LINE__);

	    // GOING THROUGH THE DATA
	    if($result->num_rows > 0) {
	      while($row = $result->fetch_assoc()) {
	        array_push($registration_ids, $row['registration_id']);
	      }
	    } else {  
	      echo 'NO RESULTS';  
	    }
	 
	    // Set POST variables
	    $url = 'https://android.googleapis.com/gcm/send';
	   
	    $message = array(
	      "Notice" => $_POST['message'],
	      "notification_id" => "42",
	      );
	    $fields = array(
	        'registration_ids' => $registration_ids,
	        'data' => $message,
	    );

	    print_r($fields);
	   
	    $headers = array(
	         // Insert your GCM auth key here
	        'Authorization: key=YOUR_KEY_HERE',
	        'Content-Type: application/json'
	    );

	    // Open connection
	    $ch = curl_init();
	   
	    // Set the url, number of POST vars, POST data
	    curl_setopt($ch, CURLOPT_URL, $url);
	   
	    curl_setopt($ch, CURLOPT_POST, true);
	    curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
	    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
	   
	    // Disabling SSL Certificate support temporarly
	    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
	   
	    curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($fields));
	   
	    // Execute post
	    $result = curl_exec($ch);
	    if ($result === FALSE) {
	        die('Curl failed: ' . curl_error($ch));
	    }
	   
	    // Close connection
	    curl_close($ch);
	    mysqli_close($mysqli);
	    echo $result;
	  }
	?>

	<form method="post" action="index.php">
	  <label>Insert Message: </label><input type="text" name="message" /> 
	  <input type="submit" name="submit" value="Send" />
	</form>
	</body>
	</html>
  • register.php
    Devices will call this API to register their ID to the database.
<?php

	/* it receives the registration id and stores it in the database.*/

	 include("connection.php");

	 $regId = $_GET['regId'];
	  
	 $query = $mysqli->query("INSERT INTO users (registration_id) VALUES ('$regId')");

	 if($query){
	     print 'Success! ID of last inserted record is : ' .$mysqli->insert_id .'<br />';
	 }else{
	     die('Error : ('. $mysqli->errno .') '. $mysqli->error);
	 }

	 // CLOSE CONNECTION
	 mysqli_close($mysqli);

?>

CREATE OUR ANDROID APP

  1. Download Google Play Services from Android SDK Manager
  2. Create new project called 'GCMDemo'
    • Add this dependency into build.gradle
    dependencies {
        compile 'com.google.android.gms:play-services:4.4.+'
        }
    
    • MainActivity
      Registers user to our server
	import android.os.AsyncTask;
	import android.os.Bundle;
	import android.support.v7.app.ActionBarActivity;
	import android.util.Log;
	import android.view.View;
	import android.widget.Button;
	import android.widget.TextView;

	import com.google.android.gms.gcm.GoogleCloudMessaging;

	import java.io.IOException;

	public class MainActivity extends ActionBarActivity implements View.OnClickListener{

	    private static final String TAG = MainActivity.class.getSimpleName();

	    Button btnRegId;
	    TextView tvRegId;
	    GoogleCloudMessaging gcm;
	    String regid;
	    String PROJECT_NUMBER = "INSERT PROJECT NUMBER HERE";

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

	        btnRegId = (Button) findViewById(R.id.register);
	        tvRegId = (TextView) findViewById(R.id.regid);

	        btnRegId.setOnClickListener(this);
	    }

	    @Override
	    public void onClick(View v) {
	        getRegId();
	    }

	    public void getRegId(){
	        new AsyncTask<Void, Void, String>() {
	            @Override
	            protected String doInBackground(Void... params) {
	                String msg;
	                try {
	                    if (gcm == null) {
	                        gcm = GoogleCloudMessaging.getInstance(getApplicationContext());
	                    }
	                    regid = gcm.register(PROJECT_NUMBER);
	                    msg = "Device registered, registration ID=" + regid;
	                    Log.i("GCM", msg);

	                    // Store Device ID to Server
	                    storeToServer();

	                } catch (IOException ex) {
	                    msg = "Error :" + ex.getMessage();

	                }
	                return msg;
	            }

	            /** 
	             * Method to call register.php API
	             */
	            private void storeToServer() {
	                URI url = null;

	                try {
	                    url = new URI("http://local.server.com/register.php?regId=" + regid);
	                } catch (URISyntaxException e) {
	                    e.printStackTrace();
	                }

	                HttpClient httpClient = new DefaultHttpClient();
	                HttpGet request = new HttpGet();
	                request.setURI(url);

	                try {
	                    httpClient.execute(request);
	                    Log.d(TAG, "post request");
	                } catch (ClientProtocolException e) {
	                    e.printStackTrace();
	                } catch (IOException e) {
	                    e.printStackTrace();
	                }
	            }

	            @Override
	            protected void onPostExecute(String msg) {
	                tvRegId.setText(msg);
	            }
	        }.execute(null, null, null);
	    }
	}
  • GcmBroadcastReceiver.java
	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 {
	    public GcmBroadcastReceiver() {
	    }

	    @Override
	    public void onReceive(Context context, Intent intent) {

	        ComponentName comp = new ComponentName(context.getPackageName(),
	                GcmIntentService.class.getName());
	        startWakefulService(context, (intent.setComponent(comp)));
	        setResultCode(Activity.RESULT_OK);

	    }
	}
  • GcmIntentService.java
	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.os.SystemClock;
	import android.support.v4.app.NotificationCompat;
	import android.util.Log;

	import com.google.android.gms.gcm.GoogleCloudMessaging;

	/**
	 * Created by piracyde25 on 6/13/2014.
	 */
	public class GcmIntentService extends IntentService {

	    public static final int NOTIFICATION_ID = 1;
	    private static final String TAG = GcmIntentService.class.getSimpleName();
	    private NotificationManager mNotificationManager;
	    NotificationCompat.Builder builder;

	    public GcmIntentService() {
	        super(TAG);
	    }

	    @Override
	    protected void onHandleIntent(Intent intent) {

	        Bundle extras = intent.getExtras();
	        // We're passing two data here, notification_id and Notice
	        String merchant_id = extras.getString("notification_id");
	        String notice = extras.getString("Notice");
	        GoogleCloudMessaging gcm = GoogleCloudMessaging.getInstance(this);

	        // The getMessageType() intent parameter must be the intent you received
	        // in your BroadcastReceiver.
	        String messageType = gcm.getMessageType(intent);

	        if (!extras.isEmpty()) { // has effect of unparcelling Bundle
	            /*
	             * Filter messages based on message type. Since it is likely that GCM
	             * will be extended in the future with new message types, just ignore
	             * any message types you're not interested in, or that you don't
	             * recognize.
	             */
	            if (GoogleCloudMessaging.MESSAGE_TYPE_SEND_ERROR.equals(messageType)) {
	                sendNotification("Send error: " + extras.toString(), "");
	            } else if (GoogleCloudMessaging.MESSAGE_TYPE_DELETED.equals(messageType)) {
	                sendNotification("Deleted messages on server: " + extras.toString(), "");
	                // if it is a regular GCM message, do some work
	            } else if (GoogleCloudMessaging.MESSAGE_TYPE_MESSAGE.equals(messageType)) {
	                // pos notification of received message
	                sendNotification(extras.getString("Notice"), merchant_id);
	                Log.i(TAG, "Received: " + extras.toString());
	            }

	            // release the wake lock provided by the wakefulbroadcastreceiver
	            GcmBroadcastReceiver.completeWakefulIntent(intent);
	        }
	    }

	    private void sendNotification(String msg, String merchant_id) {
	        mNotificationManager = (NotificationManager) this.getSystemService(Context.NOTIFICATION_SERVICE);

	        String notify = merchant_id + msg;

	        // PendingIntent: Where to go when user clicks the notification
	        PendingIntent contentIntent = PendingIntent.getActivity(this, 0,
	                new Intent(this, MainActivity.class), 0);

	        // Modify how notification will look like
	        NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this)
	                .setContentTitle("GCMDemo")
	                .setSmallIcon(R.drawable.ic_launcher)
	                .setStyle(new NotificationCompat.BigTextStyle()
	                        .bigText(notify))
	                .setContentText(notify);

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

	    }
	}
  1. Edit AndroidManifest.xml to have permissions and stuff.
	<?xml version="1.0" encoding="utf-8"?>
	<manifest xmlns:android="http://schemas.android.com/apk/res/android"
	    package="demo.gcmdemo.app" >

	    <uses-permission android:name="android.permission.INTERNET" />
	    <uses-permission android:name="android.permission.GET_ACCOUNTS" />
	    <uses-permission android:name="android.permission.WAKE_LOCK" />

	    <permission
	        android:name="demo.gcmdemo.app.permission.C2D_MESSAGE"
	        android:protectionLevel="signature" />

	    <uses-permission android:name="demo.gcmdemo.app.permission.C2D_MESSAGE" />
	    <uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
	    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
	    <uses-permission android:name="android.permission.VIBRATE" />

	    <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>

	        <meta-data
	            android:name="com.google.android.gms.version"
	            android:value="@integer/google_play_services_version" />

	        <receiver
	            android:name=".GcmBroadcastReceiver"
	            android:permission="com.google.android.c2dm.permission.SEND" >
	            <intent-filter>
	                <action android:name="com.google.android.c2dm.intent.RECEIVE" />

	                <category android:name="demo.gcmdemo.app" />
	            </intent-filter>
	        </receiver>

	        <service android:name=".GcmIntentService" />
	    </application>

	</manifest>

TRY PUSHING SOME MESSAGES

  1. Compile & run your Android app
  2. Hit register button to register to our server
  3. Start index.php
  4. Enter some message and hit send
  5. Wait for notification to your device

Or if there are error in registering the device id, just copy from logcat and put it on your database manually

Show Comments

Get the latest posts delivered right to your inbox.