Welcome to the Android Push Notification using GCM tutorial.

Introduction: Many app developers still struggle to implement Android Push Notification in their apps/games.So what is actually a push notification.Push Notification are used by developers to inform user about new messages,events or any other thing which they can see without opening their app.

In this tutorial i am going to tell you how to use GCM (Google Cloud Messaging) to send push notification on Android device.You can use this code in your android app,games made with LibGDX,Cocos2d-x with little modification.This tutorial contains PHP,MySQL & JAVA code.

Step by Step sheet

Getting project id & project number from Google developers site.

Application Code

Server side code (PHP,MySQL)

Sending push notifications

Let’s get started!

Getting project id & project number from Google developers site.

Go to this site https://developers.google.com/mobile/add?platform=android (Make sure you are logged in your google account)

Fill app name – Push Testing

Fill package name – com.developerhouse.push

Click on “continue to” button

wait for few seconds it will take some time.

click on enable Google cloud messaging

Now the project has been created we have to go on this link https://console.developers.google.com/ to edit IP address from which we can make request to send push messages & to get the API Key & Project ID

Select project from drop down on top ,note down the Project ID & Project Number

Now Click on Credentials sub menu button under API & auth

you will see something like this, note down the API Key and click on it

This is a optional step to make your push notification secure by adding the ip address of your server

add ip address & click on save button

Application Code

We have to write the code for android application which will send the device id first time so that it can be save on our server

Create a application with the same package name which we have used while setting up GCM. Add google play services library in your project

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.developerhouse.push" android:versionCode="1" android:versionName="1.0" > <uses-sdk android:minSdkVersion="10" android:targetSdkVersion="21" /> <uses-permission android:name="com.google.android.c2dm.permission.RECEIVE"/> <uses-permission android:name="android.permission.WAKE_LOCK"/> <uses-permission android:name="android.permission.VIBRATE"/> <uses-permission android:name="android.permission.INTERNET"/> <application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" > <meta-data android:name="com.google.android.gms.version" android:value="@integer/google_play_services_version" /> <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> <receiver android:name="com.google.android.gms.gcm.GcmReceiver" android:exported="true" android:permission="com.google.android.c2dm.permission.SEND"> <intent-filter> <action android:name="com.google.android.c2dm.intent.RECEIVE"/> <category android:name="com.developerhouse.push"/> </intent-filter> </receiver> <service android:name="com.developerhouse.push.MyGcmListenerService" android:exported="false" > <intent-filter> <action android:name="com.google.android.c2dm.intent.RECEIVE" /> </intent-filter> </service> <service android:name="com.developerhouse.push.MyInstanceIDListenerService" android:exported="false"> <intent-filter> <action android:name="com.google.android.gms.iid.InstanceID"/> </intent-filter> </service> <service android:name="com.developerhouse.push.RegistrationIntentService" android:exported="false"> </service> </application> </manifest>

This class is used for registering the Token in our web server .First it will get the token then it will save on our web server.

RegistrationIntentService.java

package com.developerhouse.push; import android.app.IntentService; import android.content.Intent; import android.content.SharedPreferences; import android.os.AsyncTask; import android.preference.PreferenceManager; import android.support.v4.content.LocalBroadcastManager; import android.util.Log; import com.google.android.gms.gcm.GoogleCloudMessaging; import com.google.android.gms.iid.InstanceID; import java.io.IOException; import java.io.InputStream; 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 RegistrationIntentService extends IntentService { private static final String TAG = "RegServicePush"; public RegistrationIntentService() { super(TAG); } @Override protected void onHandleIntent(Intent intent) { try { InstanceID instanceID = InstanceID.getInstance(this); String token = instanceID.getToken(Constants.GCM_SENDER_ID, GoogleCloudMessaging.INSTANCE_ID_SCOPE, null); // TODO: Implement this method to send any registration to your app's servers. sendRegistrationToServer(token); } catch (Exception e) { Log.d(TAG, "Failed to complete token refresh", e); } // Notify UI that registration has completed, so the progress indicator can be hidden. } private void sendRegistrationToServer(String token) {MainActivity.newRegID=token; WebServerRegistrationTask webServer=new WebServerRegistrationTask(); webServer.execute(); } public class WebServerRegistrationTask extends AsyncTask<Void, Void, Void> { @Override protected Void doInBackground(Void... params) { SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(RegistrationIntentService.this); URL url = null; try { url = new URL(Constants.WEB_SERVER_URL); } catch (MalformedURLException e) { e.printStackTrace(); sharedPreferences.edit().putString(Constants.PREF_GCM_REG_ID, "").apply(); } Map<String, String> dataMap = new HashMap<String, String>(); dataMap.put("regID", MainActivity.newRegID); StringBuilder postBody = new StringBuilder(); Iterator<Map.Entry<String, String>> iterator = dataMap.entrySet().iterator(); while (iterator.hasNext()) { Entry<String,String> param = (Entry<String,String>) 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(); String response=""; InputStream is = null; try { is = conn.getInputStream(); int ch; StringBuffer sb = new StringBuffer(); while ((ch = is.read()) != -1) { sb.append((char) ch); } response=sb.toString(); } catch (IOException e) { throw e; } finally { if (is != null) { is.close(); } } int status = conn.getResponseCode(); if (status == 200) { if(response.equals("1")){ sharedPreferences.edit().putString(Constants.PREF_GCM_REG_ID, MainActivity.newRegID).apply(); Intent registrationComplete = new Intent(Constants.SERVER_SUCCESS); LocalBroadcastManager.getInstance(RegistrationIntentService.this).sendBroadcast(registrationComplete); } } else { throw new IOException("Request failed with error code " + status); } } catch (ProtocolException pe) { pe.printStackTrace(); sharedPreferences.edit().putString(Constants.PREF_GCM_REG_ID, "").apply(); } catch (IOException io) { io.printStackTrace(); sharedPreferences.edit().putString(Constants.PREF_GCM_REG_ID, "").apply(); } finally { if (conn != null) { conn.disconnect(); } } return null; } } }

MyInstanceIDListenerService.java

package com.developerhouse.push; import android.content.Intent; import com.google.android.gms.iid.InstanceIDListenerService; public class MyInstanceIDListenerService extends InstanceIDListenerService { @Override public void onTokenRefresh() { Intent intent = new Intent(this, RegistrationIntentService.class); startService(intent); } }

MyGcmListenerService.java

package com.developerhouse.push; import com.google.android.gms.gcm.GcmListenerService; import android.app.NotificationManager; import android.app.PendingIntent; import android.content.Context; import android.content.Intent; import android.media.RingtoneManager; import android.net.Uri; import android.os.Bundle; import android.support.v4.app.NotificationCompat; public class MyGcmListenerService extends GcmListenerService { public static final int MESSAGE_NOTIFICATION_ID = 435345; private NotificationManager mNotificationManager; @Override public void onMessageReceived(String from, Bundle data) { String message = data.getString("message"); createNotification( message); } // Creates notification based on title and body received private void createNotification( String body) { mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); Uri sound = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION); long[] pattern = {500}; 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("Push Notification Test").setVibrate(pattern) .setStyle(new NotificationCompat.BigTextStyle().bigText(body)) .setContentText(body) .setAutoCancel(true).setSound(sound); mBuilder.setContentIntent(contentIntent); mNotificationManager.notify(MESSAGE_NOTIFICATION_ID, mBuilder.build()); } }

Line 20 : MESSAGE_NOTIFICATION_ID is used to make notification same for example if you send another notification and user have not read the old one it will replace the old one

Line 24 : Method which will receive the content from GCM

Line 34 : Sound for notification

Line 35 : Vibration Pattern

Line 37 : Intent which will run on click of notification you can open link to browser or you can open the activity

Constants.java

package com.developerhouse.push; public class Constants { public static String PREF_GCM_REG_ID = "PREF_GCM_REG_ID"; public static String GCM_SENDER_ID = "339415449819"; public static String WEB_SERVER_URL = "http://192.168.1.103/push/reg.php"; public static final String SERVER_SUCCESS="server_success"; }

GCM_SENDER_ID = Project ID

WEB_SERVER_URL = URL to register user unique id

MainActivity.java

package com.developerhouse.push; import com.google.android.gms.common.ConnectionResult; import com.google.android.gms.common.GooglePlayServicesUtil; import android.app.Activity; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.SharedPreferences; import android.os.Bundle; import android.preference.PreferenceManager; import android.support.v4.content.LocalBroadcastManager; import android.util.Log; import android.widget.Toast; public class MainActivity extends Activity { private static final String TAG = "MainActivity"; public static String newRegID=""; private BroadcastReceiver mRegistrationBroadcastReceiver; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mRegistrationBroadcastReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context); String sentToken = sharedPreferences .getString(Constants.PREF_GCM_REG_ID, ""); System.out.println("SERVER_SUCCESS") ; if (sentToken.equals("")) { Toast.makeText(MainActivity.this, "Failed to save on server", Toast.LENGTH_SHORT).show(); } else { Toast.makeText(MainActivity.this, "Succesfully saved on server", Toast.LENGTH_SHORT).show(); } } }; if (checkPlayServices()) { Intent intent = new Intent(this, RegistrationIntentService.class); startService(intent); } } @Override protected void onResume() { super.onResume(); LocalBroadcastManager.getInstance(this).registerReceiver(mRegistrationBroadcastReceiver, new IntentFilter(Constants.SERVER_SUCCESS)); } @Override protected void onPause() { LocalBroadcastManager.getInstance(this).unregisterReceiver(mRegistrationBroadcastReceiver); super.onPause(); } private boolean checkPlayServices() { int resultCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable(this); if (resultCode != ConnectionResult.SUCCESS) { if (GooglePlayServicesUtil.isUserRecoverableError(resultCode)) { GooglePlayServicesUtil.getErrorDialog(resultCode, this, 9000).show(); } else { Log.i(TAG, "This device is not supported."); finish(); } return false; } return true; } }</pre> <pre>

Server side code (PHP,MySQL)

In Server side we have to create a 4 PHP scripts for inserting the registration id & sending push notification.I am not going to explain basic steps to create PHP Script and MySQL DB for that you can check this link

https://developerhouse.com/blog/2015/08/tutorial-1-connect-android-with-php-mysql/

I am not focusing on design of the admin panel or anything related to it because our main focus will be on coding and getting your work done by adding Login Page(some of readers will be using it in their apps so it can be misuse)

Also i am not saving the username and pass in MySQL DB there is no need for it at this moment it’s just for learning purpose so that android developer can easily get push notification implemented without needing any PHP developer for php code.

Create Database named push

Table named registration

These are the structure of these tables

Name Type Length/Values A I (Auto Increment) id INT Yes gcm_regid VARCHAR 300 No (By Default) created_at timestamp No (By Default)

PHP Files

connect.php // Change this for settings of MySQL DB

login.php // To login into admin panel

reg.php // For saving registration ID’s

send.php // For sending the push notification

connect.php

It’s used for changing login page username,password & also for changing mysql details.

<?php define("apiKey","AIzaXXXXXXXXXXXXXXXXXXXXXXXX");//Fill the key which we got from Developer Console $user="admin"; $pass="password"; $host="localhost"; $db_user_name="root"; $db_password=""; $db_name="push"; $con = new PDO('mysql:host='.$host.';dbname='.$db_name.';charset=utf8', $db_user_name, $db_password); $con->setAttribute(PDO::ATTR_EMULATE_PREPARES, false); ?>

login.php

It’s used for login into Android Push Notification panel so that no one can access it without username and password .You can change the username & password in connect.php file

<?php session_start(); if (isset($_POST['submit'])) { if (empty($_POST['username']) || empty($_POST['password'])) { echo "Login is invalid"; } else { $username=$_POST['username']; $password=$_POST['password']; include_once "connect.php"; if ($username==$user & $password==$pass) { $_SESSION['login_user']=$user; header("location: send.php"); exit(); } else { echo "Login is invalid"; } } } if(isset($_SESSION['login_user'])){ header("location: send.php"); } ?> <!DOCTYPE html> <html> <head> <title>Admin Panel Login: Developer House</title> </head> <body> <div id="main"> <h1>Admin Panel Login Push Notification</h1> <div id="login"> <h2>Login Form</h2> <form action="" method="post"> <label>Username :</label> <input id="name" name="username" placeholder="username" type="text"> <label>Password :</label> <input id="password" name="password" placeholder="**********" type="password"> <input name="submit" type="submit" value=" Login "> </form> </div> </div> </body> </html>

reg.php

This is the file which will be requested through Android platform via HTTP Request.

<?php include_once "connect.php"; function storeUser($con,$gcm_regid) { $stmt = $con->prepare("INSERT INTO registration(gcm_regid, created_at) VALUES(:field, NOW())"); $stmt->execute(array(':field' => $gcm_regid)); $id = $con->lastInsertId(); $result = $con->query("SELECT * FROM registration WHERE id = $id"); if ($result->rowCount() > 0) { return true; } else { return false; } } function getSame($con,$gcm_regid) { $result =$con->query("SELECT * FROM registration WHERE gcm_regid=\"".$gcm_regid."\""); if ($result->rowCount()>0) { return true; } else { return false; } } if (isset($_POST["regID"])) { $gcm_regid = $_POST["regID"]; if(!getSame($con,$gcm_regid)){ storeUser($con,$gcm_regid); echo "1"; }else{echo "0";} } else { echo "0"; }?>

send.php

This file is used for sending the push notification of our choice to the all users in group.

<?php session_start(); include_once 'connect.php'; function send_notification($con,$registatoin_ids, $message) { $url = 'https://android.googleapis.com/gcm/send'; $fields = array( 'data' =>array("message" => $message), 'registration_ids' => $registatoin_ids ); $headers = array( 'Authorization: key=' . apiKey, '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); if ($result === FALSE) { die('Curl failed: ' . curl_error($ch)); } curl_close($ch); echo $result; } if(isset($_SESSION['login_user'])){ if(isset($_POST["submit"]) && isset($_POST["message"])) { $num=$con->query("SELECT gcm_regid from registration")->rowCount(); $current_num=0; $message=$_POST["message"]; for($i=0;$i<$num/1000;$i++){ $query=$con->query("SELECT gcm_regid from registration LIMIT $current_num,1000"); foreach($query as $data) { $row[]=$data["gcm_regid"]; } $pushStatus = send_notification($con,$row, $message); $current_num+=1000; } }else if(isset($_POST["logout"])){ if(session_destroy()) // Destroying All Sessions { header("Location: login.php"); // Redirecting To Home Page } } ?> <?php ?><!DOCTYPE html> <html> <head> <title>Send Push Notification : Developer House</title> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> </head> <body> <?php $result = $con->query("SELECT * FROM registration"); if ($result != false) $no_of_users =$result->rowCount(); else $no_of_users = 0; ?> <div > <h1>No of Devices Registered: <?php echo $no_of_users; ?></h1> <hr/> <?php if ($no_of_users > 0) { ?> <form method="POST" action=""> <textarea rows="3" name="message" cols="25" placeholder="Type message here"></textarea> <button type="submit" name="submit" value="Submit">Submit</button> <button type="submit" name="logout" value="Submit">Logout</button> </div> </form> <?php } else { ?> <li> No Users Registered! </li> <?php } }?> </div> </body> </html>

Sending push notifications

Now if you have followed the tutorial this step will work for you.

So steps are

Open Android Costants.java file & replace GCM_SENDER_ID variable value to the project number from project console ,WEB_SERVER_URL value to the one with your server url and file path for example if you have uploaded in wamp www then check IP of your computer it should be like this http://192.168.1.103/reg.php or if you have used a Linux Hosting and uploaded in public_html your main domain is developerhouse.com then it will be https://developerhouse.com/reg.php Open connect.php change apiKey value to the one we got from project console Api & auth -> Credentials Compile & Run the android application . Don’t worry if it does not show anything because we have not made it for this purpose . It will show Toast Registered with web server if everything works well Now check PHPMyAdmin it will have a new value in registration table Now to send the Push Notification go to this url http://192.168.1.103/login.php .Fill username & password.You will be redirected to the http://192.168.1.103/send.php file it will show no. of registered user & a textarea with two buttons Press submit & check notification. Finish

Code Download Click here (Dropbox)

Few Notes