Android Push Notifications using Google Cloud Messaging (GCM), PHP and MySQL
As per google’s documentation “Google Cloud Messaging for Android (GCM) is a service that helps developers send data from servers to their Android applications on Android devices”. Using this service you can send data to your application whenever new data is available instead of making requests to server in timely fashion. Integrating GCM in your android application enhances user experience and saves lot of battery power.
Overview of Google Cloud Messaging, PHP and MySQL
In this tutorial i used PHP as server side programming language and MySQL as server side database. I installed WAMP server to install php, mysql, apache for me. If you are new to connecting PHP, MySQL to android application, i suggest you go through this tutorial
How to connect Android with PHP, MySQL
How to connect Android with PHP, MySQL
You can go through the official documentation if you want to know more about GCM.
The following diagram is illustrating the overview of the tutorial and the purpose of each entity involved in this tutorial.
GCM WORKING FLOW |
Registering with Google Cloud Messaging
1. Goto Google APIs Console page and create a new project.
(If you haven’t created already otherwise it will take you to dashboard)
CREATE YOUR PROJECT ID. |
2. After creating project you can see the project id in the url.
Note down the project id which will be used as SENDER ID in android project.
(Example: in #project:460866929976 after semicolon 460866929976 is the sender id)
3. After that click on Services on the left panel and turn on Google Cloud Messaging for Android.
4. Once you are done, click on API Access and note down the API Key.
1. Open phpmyadmin panel by going to http://localhost/phpmyadmin
and create a database called gcm.
(if your localhost is running on port number add port number to url)
2. After creating the database, select the database and execute following query in SQL tab to creategcm_users table.
CREATE TABLE IF NOT EXISTS `gcm_users` ( `id` int (11) NOT NULL AUTO_INCREMENT, `gcm_regid` text, ` name ` varchar (50) NOT NULL , `email` varchar (255) NOT NULL , `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP , PRIMARY KEY (`id`) )
config.php
<?php
/**
* Database config variables
*/
define("DB_HOST", "localhost");
define("DB_USER", "root");
define("DB_PASSWORD", "");
define("DB_DATABASE", "gcm");
/*
* Google API Key
*/
define("GOOGLE_API_KEY", "AIzaSyAPIa9gan92h7h_BA8spxqxoBGTVIGCI54"); // Place your Google API Key
?>
3. Create another file called db_connect.php This file handles database connections,
mainly opens and closes connection.
db_connect.php
<?php
require_once 'config.php';
class DB_Connect{
public $result;
public $rowC;
// constructor
function __construct() {
}
// destructor
function __destruct() {
// $this->close();
}
// Connecting to database
public function connect(){
// connecting to mysql
$con = mysql_connect(DB_HOST, DB_USER, DB_PASSWORD);
// selecting database
mysql_select_db(DB_DATABASE, $con);
// return database handler
return $con;
}
public function insert_query($q){
$val = mysql_query($q);
return $val;
}
public function select_query($q){
$this->result = mysql_query($q);
$this->rowC = mysql_num_rows($this->result);
return $this->result;
}
public function fetch_data(){
return mysql_fetch_assoc($this->result);
}
// Closing database connection
public function close() {
mysql_close();
}
}
?>
4. Create a new file named db_functions.php This file contains function to perform database CRUD operations. But i wrote function for creating user only.
db_functions.php
<?php
class DB_Functions {
private $db;
//put your code here
// constructor
function __construct() {
include_once './db_connect.php';
// connecting to database
$this->db = new DB_Connect();
$this->db->connect();
}
// destructor
function __destruct() {
}
/**
* Storing new user
* returns user details
*/
public function storeUser($name, $email, $gcm_regid) {
// insert user into database
$result = mysql_query("INSERT INTO gcm_users(name, email, gcm_regid, created_at) VALUES('$name', '$email', '$gcm_regid', NOW())");
// check for successful store
if ($result) {
// get user details
$id = mysql_insert_id(); // last inserted id
$result = mysql_query("SELECT * FROM gcm_users WHERE id = $id") or die(mysql_error());
// return user details
if (mysql_num_rows($result) > 0) {
return mysql_fetch_array($result);
} else {
return false;
}
} else {
return false;
}
}
/**
* Get user by email and password
*/
public function getUserByEmail($email) {
$result = mysql_query("SELECT * FROM gcm_users WHERE email = '$email' LIMIT 1");
return $result;
}
/**
* Getting all users
*/
public function getAllUsers() {
$result = mysql_query("select * FROM gcm_users");
return $result;
}
/**
* Check user is existed or not
*/
public function isUserExisted($email) {
$result = mysql_query("SELECT email from gcm_users WHERE email = '$email'");
$no_of_rows = mysql_num_rows($result);
if ($no_of_rows > 0) {
// user existed
return true;
} else {
// user not existed
return false;
}
}
}
?> 5. Create another file named GCM.php This file used to send push notification requests to GCM server. GCM.php
<?php/* * To change this template, choose Tools | Templates * and open the template in the editor. */ /** * Description of GCM * * @author Ravi Tamada */ class GCM { //put your code here // constructor function __construct() { } /** * Sending Push Notification */ public function send_notification($registatoin_ids, $message) { // include config include_once './config.php'; // Set POST variables $url = 'https://android.googleapis.com/gcm/send'; $fields = array( 'registration_ids' => $registatoin_ids, 'data' => $message, ); $headers = array( 'Authorization: key=' . GOOGLE_API_KEY, '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); echo $result; } } ?> 6. Create a new file called register.php This file receives requests from android device and stores the user in the database. register.php <?php // response json $json = array(); /** * Registering a user device * Store reg id in users table */ if (isset($_POST["name"]) && isset($_POST["email"]) && isset($_POST["regId"])) { $name = $_POST["name"]; $email = $_POST["email"]; $gcm_regid = $_POST["regId"]; // GCM Registration ID // Store user details in db include_once './db_functions.php'; include_once './GCM.php'; $db = new DB_Functions(); $gcm = new GCM(); $res = $db->storeUser($name, $email, $gcm_regid); $registatoin_ids = array($gcm_regid); $message = array("product" => "shirt"); $result = $gcm->send_notification($registatoin_ids, $message); echo $result; } else { // user details missing } ?> 7. Create another file called send_message.php This file used to send pushnotification to android device by making a request to GCM server. send_message.php <?php /* * To change this template, choose Tools | Templates * and open the template in the editor. */ if (isset($_GET["regId"]) && isset($_GET["message"])) { $regId = $_GET["regId"]; $message = $_GET["message"]; include_once './GCM.php'; include_once './db_connect.php'; $gcm = new GCM(); $result = new DB_Connect; $result->connect(); $result->insert_query("INSERT INTO store (`id`,`msg`, `date`) VALUES (null, '$message', NOW())"); $registatoin_ids = $regId; $message = array("price" => $message); $result = $gcm->send_notification($registatoin_ids, $message); echo $result; } ?>
8. Finally create a file called index.php and paste the following code.
The following code will create a simple admin panel to list all the user devices and
provides a panel to send push notification to individual devices.
index.php
<!--
To change this template, choose Tools | Templates
and open the template in the editor.
-->
<!DOCTYPE html>
<html>
<head>
<title></title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js"></script>
<script type="text/javascript">
$(document).ready(function(){
});
function sendToAll(){
var data = $("#sendtoall").serialize();
console.log(data);
$("#sendtoall").unbind('submit');
$.ajax({
url: "send_message.php",
type: 'GET',
data: data,
beforeSend: function() {
},
success: function(data, textStatus, xhr) {
$('.txt_message').val("");
},
error: function(xhr, textStatus, errorThrown) {
}
});
return false;
}
</script>
<style type="text/css">
.container{
width: 950px;
margin: 0 auto;
padding: 0;
}
h1{
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
font-size: 24px;
color: #777;
}
div.clear{
clear: both;
}
ul.devices{
margin: 0;
padding: 0;
}
ul.devices li{
float: left;
list-style: none;
border: 1px solid #dedede;
padding: 10px;
margin: 0 15px 25px 0;
border-radius: 3px;
-webkit-box-shadow: 0 1px 5px rgba(0, 0, 0, 0.35);
-moz-box-shadow: 0 1px 5px rgba(0, 0, 0, 0.35);
box-shadow: 0 1px 5px rgba(0, 0, 0, 0.35);
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
color: #555;
}
ul.devices li label, ul.devices li span{
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
font-size: 12px;
font-style: normal;
font-variant: normal;
font-weight: bold;
color: #393939;
display: block;
float: left;
}
ul.devices li label{
height: 25px;
width: 50px;
}
ul.devices li textarea{
float: left;
resize: none;
}
ul.devices li .send_btn{
background: -webkit-gradient(linear, 0% 0%, 0% 100%, from(#0096FF), to(#005DFF));
background: -webkit-linear-gradient(0% 0%, 0% 100%, from(#0096FF), to(#005DFF));
background: -moz-linear-gradient(center top, #0096FF, #005DFF);
background: linear-gradient(#0096FF, #005DFF);
text-shadow: 0 1px 0 rgba(0, 0, 0, 0.3);
border-radius: 3px;
color: #fff;
}
</style>
</head>
<body>
<?php
include_once 'db_functions.php';
$db = new DB_Functions();
$users = $db->getAllUsers();
if ($users != false)
$no_of_users = mysql_num_rows($users);
else
$no_of_users = 0;
?>
<div class="container">
<h1>No of Devices Registered: <?php echo $no_of_users; ?></h1>
<hr/>
<ul class="devices">
<?php
if ($no_of_users > 0) {
?>
<li>
<form id="sendtoall" action="index.php" method="post" onsubmit="return sendToAll()">
<div class="send_container">
<textarea rows="3" name="message" cols="25" class="txt_message" placeholder="Type message here"></textarea>
<?php
while ($row = mysql_fetch_array($users)) {
?>
<input type="hidden" name="regId[]" value="<?php echo $row["gcm_regid"] ?>"/>
<?php
}
?>
<input type="submit" name="sendbtn" class="send_btn" value="Send To All" onclick=""/>
</div>
</form>
</li>
<?php
} else { ?>
<li>
No Users Registered Yet!
</li>
<?php }
?>
</ul>
</div>
<div class="clear"></div>
</body>
</html>
Installing helper libraries and setting up the Emulator
Before start writing android code we need to install the helper libraries and make required changes to the emulator.
1. Goto your android SDK folder and open SDK Manager and install Google Cloud Messaging for Android Library under Extras section. (If you don’t see Google Cloud Messaging for Android Library update your SDK manager to latest version)
2. After installing the library it will create gcm.jar file in yourAndoird_SDK_Folder\extras\google\gcm\gcm-client\dist. Later you need to add this .jar file to your android project.
3. Now open your AVD Manager and create a new Google API emulator and start the emulator. (Note: To test gcm application in emulator you need to test it on Google API device only)
4. After launching emulator press Menu button goto Settings. Select Accounts & Sync. And then press Add Account button and add a Google account. Creating Android Project
1. Create a new android project and fill the required details. While creating project select minimum SDK version API 8 to support wider range of devices.
2. After creating new project open AndroidManifest.xml file and do the following changes. The following permission are required to make your project support gcm.
INTERNET – To make your app use internet services
ACCESS_NETWORK_STATE – To access network state (used to detect internet status) GET_ACCOUNTS – Required as GCM needs google account WAKE_LOCK – Needed if your app need to wake your device when it sleeps VIBRATE – Needed if your support vibration when receiving notification Also add some broadcast receivers as mentioned below.
In the following code replace all com.androidhive.pushnotifications with your android package name.
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.androidhive.pushnotifications"
android:versionCode="1"
android:versionName="1.0" >
<!-- GCM requires Android SDK version 2.2 (API level 8) or above. -->
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="16" />
<!-- GCM connects to Internet Services. -->
<uses-permission android:name="android.permission.INTERNET" />
<!-- 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. -->
<permission
android:name="com.androidhive.pushnotifications.permission.C2D_MESSAGE"
android:protectionLevel="signature" />
<uses-permission android:name="com.androidhive.pushnotifications.permission.C2D_MESSAGE" />
<!-- This app has permission to register and receive data message. -->
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
<!-- Network State Permissions to detect Internet status -->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<!-- Permission to vibrate -->
<uses-permission android:name="android.permission.VIBRATE" />
<!-- Main activity. -->
<application
android:icon="@drawable/anythingitsolution"
android:label="@string/app_name" >
<!-- Register Activity -->
<activity
android:name=".RegisterActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<!-- Main Activity -->
<activity
android:name=".MainActivity"
android:configChanges="orientation|keyboardHidden"
android:label="@string/app_name" >
</activity>
<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.androidhive.pushnotifications" />
</intent-filter>
</receiver>
<service android:name=".GCMIntentService" />
</application>
</manifest>
3. Open your strings.xml file under res -> values folder and paste following strings. (If you don’t have strings.xml file, create a new one)
strings.xml
<resources>
<string name="app_name">JOB Portal</string>
<string name="hello_world">Hello world!</string>
<string name="menu_settings">Settings</string>
<string name="title_activity_main">Push Notifications</string>
<string name="error_config">Please set the %1$s constant and recompile the app.</string>
<string name="already_registered">Device is already registered on server.</string>
<string name="gcm_registered">From GCM: device successfully registered!</string>
<string name="gcm_unregistered">From GCM: device successfully unregistered!</string>
<string name="gcm_message">From GCM: you got message!</string>
<string name="gcm_error">From GCM: error (%1$s).</string>
<string name="gcm_recoverable_error">From GCM: recoverable error (%1$s).</string>
<string name="gcm_deleted">From GCM: server deleted %1$d pending messages!</string>
<string name="server_registering">Trying (attempt %1$d/%2$d) to register device on Demo Server.</string>
<string name="server_registered">From Demo Server: successfully added device!</string>
<string name="server_unregistered">From Demo Server: successfully removed device!</string>
<string name="server_register_error">Could not register device on Demo Server after %1$d attempts.</string>
<string name="server_unregister_error">Could not unregister device on Demo Server (%1$s).</string>
<string name="options_register">Register</string>
<string name="options_unregister">Unregister</string>
<string name="options_clear">Clear</string>
<string name="options_exit">Exit</string>
</resources>
4. Create a new class named AlertDialogManager.java and paste the following code. This class used to show alert dialog in your application.
AlertDialogManager.java
package com.androidhive.pushnotifications;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
public class AlertDialogManager {
/**
* Function to display simple Alert Dialog
* @param context - application context
* @param title - alert dialog title
* @param message - alert message
* @param status - success/failure (used to set icon)
* - pass null if you don't want icon
* */
public void showAlertDialog(Context context, String title, String message,
Boolean status) {
AlertDialog alertDialog = new AlertDialog.Builder(context).create();
// Setting Dialog Title
alertDialog.setTitle(title);
// Setting Dialog Message
alertDialog.setMessage(message);
if(status != null)
// Setting alert dialog icon
alertDialog.setIcon((status) ? R.drawable.success : R.drawable.fail);
// Setting OK Button
alertDialog.setButton("OK", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
}
});
// Showing Alert Message
alertDialog.show();
}
}
5. Create another class named ConnectionDetector.java This class used to detect internet connection status.
ConnectionDetector.java
package com.androidhive.pushnotifications;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
public class ConnectionDetector {
private Context _context;
public ConnectionDetector(Context context){
this._context = context;
}
/**
* Checking for all possible internet providers
* **/
public boolean isConnectingToInternet(){
ConnectivityManager connectivity = (ConnectivityManager) _context.getSystemService(Context.CONNECTIVITY_SERVICE);
if (connectivity != null)
{
NetworkInfo[] info = connectivity.getAllNetworkInfo();
if (info != null)
for (int i = 0; i < info.length; i++)
if (info[i].getState() == NetworkInfo.State.CONNECTED)
{
return true;
}
}
return false;
}
}
6. Create class file called CommonUtilities.java and type the following code. This class contains the GCM configuration and our server registration url.
SERVER_URL – Your server user registration url
SENDER_ID – Google project id
CommonUtilities.java
package com.androidhive.pushnotifications;
import android.content.Context;
import android.content.Intent;
public final class CommonUtilities {
// give your server registration url here
//static final String SERVER_URL = "http://www.alphainfoways.com/demos/gcm/register.php";
static final String SERVER_URL = "http://10.0.2.2/gcm_server_php/register.php";
//static final String get = "http://10.0.2.2/gcm_server_php/insert.php";
// Google project id
static final String SENDER_ID = "1024910760619";
/**
* Tag used on log messages.
*/
static final String TAG = "AndroidHive GCM";
static final String DISPLAY_MESSAGE_ACTION =
"com.androidhive.pushnotifications.DISPLAY_MESSAGE";
static final String EXTRA_MESSAGE = "message";
/**
* Notifies UI to display a message.
* <p>
* This method is defined in the common helper because it's used both by
* the UI and the background service.
*
* @param context application's context.
* @param message message to be displayed.
*/
static void displayMessage(Context context, String message) {
Intent intent = new Intent(DISPLAY_MESSAGE_ACTION);
intent.putExtra(EXTRA_MESSAGE, message);
context.sendBroadcast(intent);
}
}
7. Create a new class called ServerUtilities.java with following content. This class has following funtions
ServerUtilities.java
package com.androidhive.pushnotifications;
import static com.androidhive.pushnotifications.CommonUtilities.SERVER_URL;
import static com.androidhive.pushnotifications.CommonUtilities.TAG;
import static com.androidhive.pushnotifications.CommonUtilities.displayMessage;
import java.io.IOException;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Random;
import android.content.Context;
import android.util.Log;
import com.google.android.gcm.GCMRegistrar;
public final class ServerUtilities {
private static final int MAX_ATTEMPTS = 5;
private static final int BACKOFF_MILLI_SECONDS = 2000;
private static final Random random = new Random();
/**
* Register this account/device pair within the server.
*
*/
static void register(final Context context, String name, String email, final String regId) {
Log.i(TAG, "registering device (regId = " + regId + ")");
String serverUrl = SERVER_URL;
Map<String, String> params = new HashMap<String, String>();
params.put("regId", regId);
params.put("name", name);
params.put("email", email);
long backoff = BACKOFF_MILLI_SECONDS + random.nextInt(1000);
// Once GCM returns a registration id, we need to register on our server
// As the server might be down, we will retry it a couple
// times.
for (int i = 1; i <= MAX_ATTEMPTS; i++) {
Log.d(TAG, "Attempt #" + i + " to register");
try {
displayMessage(context, context.getString(
R.string.server_registering, i, MAX_ATTEMPTS));
post(serverUrl, params);
GCMRegistrar.setRegisteredOnServer(context, true);
String message = context.getString(R.string.server_registered);
CommonUtilities.displayMessage(context, message);
return;
} catch (IOException e) {
// Here we are simplifying and retrying on any error; in a real
// application, it should retry only on unrecoverable errors
// (like HTTP error code 503).
Log.e(TAG, "Failed to register on attempt " + i + ":" + e);
if (i == MAX_ATTEMPTS) {
break;
}
try {
Log.d(TAG, "Sleeping for " + backoff + " ms before retry");
Thread.sleep(backoff);
} catch (InterruptedException e1) {
// Activity finished before we complete - exit.
Log.d(TAG, "Thread interrupted: abort remaining retries!");
Thread.currentThread().interrupt();
return;
}
// increase backoff exponentially
backoff *= 2;
}
}
String message = context.getString(R.string.server_register_error,
MAX_ATTEMPTS);
//CommonUtilities.displayMessage(context, message);
displayMessage(context, message);
}
/**
* Unregister this account/device pair within the server.
*/
static void unregister(final Context context, final String regId) {
Log.i(TAG, "unregistering device (regId = " + regId + ")");
String serverUrl = SERVER_URL + "/unregister";
Map<String, String> params = new HashMap<String, String>();
params.put("regId", regId);
try {
post(serverUrl, params);
GCMRegistrar.setRegisteredOnServer(context, false);
String message = context.getString(R.string.server_unregistered);
//CommonUtilities.displayMessage(context, message);
displayMessage(context, message);
} catch (IOException e) {
// At this point the device is unregistered from GCM, but still
// registered in the server.
// We could try to unregister again, but it is not necessary:
// if the server tries to send a message to the device, it will get
// a "NotRegistered" error message and should unregister the device.
String message = context.getString(R.string.server_unregister_error,
e.getMessage());
//CommonUtilities.displayMessage(context, message);
displayMessage(context, message);
}
}
/**
* Issue a POST request to the server.
*
* @param endpoint POST address.
* @param params request parameters.
*
* @throws IOException propagated from POST.
*/
private static void post(String endpoint, Map<String, String> params)
throws IOException {
URL url;
try {
url = new URL(endpoint);
} catch (MalformedURLException e) {
throw new IllegalArgumentException("invalid url: " + endpoint);
}
StringBuilder bodyBuilder = new StringBuilder();
Iterator<Entry<String, String>> iterator = params.entrySet().iterator();
// constructs the POST body using the parameters
while (iterator.hasNext()) {
Entry<String, String> param = iterator.next();
bodyBuilder.append(param.getKey()).append('=')
.append(param.getValue());
if (iterator.hasNext()) {
bodyBuilder.append('&');
}
}
String body = bodyBuilder.toString();
Log.v(TAG, "Posting '" + body + "' to " + url);
byte[] bytes = body.getBytes();
HttpURLConnection conn = null;
try {
Log.e("URL", "> " + url);
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");
// post the request
OutputStream out = conn.getOutputStream();
out.write(bytes);
out.close();
// handle the response
int status = conn.getResponseCode();
if (status != 200) {
throw new IOException("Post failed with error code " + status);
}
} finally {
if (conn != null) {
conn.disconnect();
}
}
}
}
8. Add a new class file called GCMIntentService.java This class handles all GCM related services.
GCMIntentService.java
public class GCMIntentService extends GCMBaseIntentService {
private static final String TAG = "GCMIntentService";
public GCMIntentService() {
super(SENDER_ID);
}
/**
* Method called on device registered
**/
@Override
protected void onRegistered(Context context, String registrationId) {
Log.i(TAG, "Device registered: regId = " + registrationId);
displayMessage(context, "Your device registred with GCM");
Log.d("NAME", MainActivity.name);
ServerUtilities.register(context, MainActivity.name, MainActivity.email, registrationId);
}
/**
* Method called on device un registred
* */
@Override
protected void onUnregistered(Context context, String registrationId) {
Log.i(TAG, "Device unregistered");
displayMessage(context, getString(R.string.gcm_unregistered));
ServerUtilities.unregister(context, registrationId);
}
/**
* Method called on Receiving a new message
* */
@Override
protected void onMessage(Context context, Intent intent) {
String message = intent.getExtras().getString("price");
displayMessage(context, message);
// notifies user
generateNotification(context, message);
//cv = new ContentValues();
// cv.put("MSG", message);
//db.insert("STUDENT", null, cv);
}
/**
* Method called on receiving a deleted message
* */
@Override
protected void onDeletedMessages(Context context, int total) {
Log.i(TAG, "Received deleted messages notification");
String message = getString(R.string.gcm_deleted, total);
displayMessage(context, message);
// notifies user
generateNotification(context, message);
}
/**
* Method called on Error
* */
@Override
public void onError(Context context, String errorId) {
Log.i(TAG, "Received error: " + errorId);
displayMessage(context, getString(R.string.gcm_error, errorId));
}
@Override
protected boolean onRecoverableError(Context context, String errorId) {
// log message
Log.i(TAG, "Received recoverable error: " + errorId);
displayMessage(context, getString(R.string.gcm_recoverable_error,
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);
// set intent so it does not start a new activity
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;
// Play default notification sound
notification.defaults |= Notification.DEFAULT_SOUND;
//notification.sound = Uri.parse("android.resource://" + context.getPackageName() + "your_sound_file_name.mp3");
// Vibrate if vibrate is enabled
notification.defaults |= Notification.DEFAULT_VIBRATE;
notificationManager.notify(0, notification);
}
}
9. Here i am adding a registration screen where user can register using their details. To make this tutorial simple i am asking only name and email only. Once user registration is done the user details will be sent to our server where the user details will be stored in mysql database.
Create a new xml file called activity_register.xml under res -> layout folder and paste the following code.
activity_register.xml
<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:orientation="vertical" >
<TextView android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Full Name:"
android:layout_marginLeft="10dip"
android:layout_marginRight="10dip"
android:layout_marginTop="20dip"/>
<EditText android:id="@+id/txtName"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_margin="10dip"
android:layout_marginBottom="20dip"/>
<TextView android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Email:"
android:layout_marginLeft="10dip"
android:layout_marginRight="10dip"/>
<EditText android:id="@+id/txtEmail"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_margin="10dip"
android:layout_marginBottom="20dip"/>
<Button android:id="@+id/btnRegister"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Register"
android:layout_margin="10dip"/>
</LinearLayout>
10. Create a new class called RegisterActivity.java This class will be used to handler user registration.
In the following code first internet status and gcm configuration is checked and once user presses the registration button user details will be send to MainActivity.java from there they will send to our server.
RegisterActivity.java
package com.androidhive.pushnotifications;
import static com.androidhive.pushnotifications.CommonUtilities.SENDER_ID;
import static com.androidhive.pushnotifications.CommonUtilities.SERVER_URL;
import android.app.Activity;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
public class RegisterActivity extends Activity {
// alert dialog manager
AlertDialogManager alert = new AlertDialogManager();
// Internet detector
ConnectionDetector cd;
String s1,s2;
// UI elements
EditText txtName;
EditText txtEmail;
// Register button
Button btnRegister;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_register);
SharedPreferences sp = getSharedPreferences("my", 0);
s1 = sp.getString("name", "");
s2 = sp.getString("email", "");
//e.commit();
if(s1.length()>0 && s2.length()>0){
Intent i = new Intent(this,MainActivity.class);
startActivity(i);
finish();
}
cd = new ConnectionDetector(getApplicationContext());
// Check if Internet present
if (!cd.isConnectingToInternet()) {
// Internet Connection is not present
alert.showAlertDialog(RegisterActivity.this,
"Internet Connection Error",
"Please connect to working Internet connection", false);
// stop executing code by return
return;
}
// Check if GCM configuration is set
if (SERVER_URL == null || SENDER_ID == null || SERVER_URL.length() == 0
|| SENDER_ID.length() == 0) {
// GCM sernder id / server url is missing
alert.showAlertDialog(RegisterActivity.this, "Configuration Error!",
"Please set your Server URL and GCM Sender ID", false);
// stop executing code by return
return;
}
txtName = (EditText) findViewById(R.id.txtName);
txtEmail = (EditText) findViewById(R.id.txtEmail);
btnRegister = (Button) findViewById(R.id.btnRegister);
/*
* Click event on Register button
* */
btnRegister.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View arg0) {
// Read EditText dat
String name = txtName.getText().toString();
String email = txtEmail.getText().toString();
// Check if user filled the form
if(name.trim().length() > 0 && email.trim().length() > 0){
// Launch Main Activity
SharedPreferences sp = getSharedPreferences("my", 0);
SharedPreferences.Editor e = sp.edit();
e.putString("name", name);
e.putString("email", email);
e.commit();
Intent i = new Intent(getApplicationContext(), MainActivity.class);
// Registering user on our server
// Sending registraiton details to MainActivity
i.putExtra("name", name);
i.putExtra("email", email);
startActivity(i);
finish();
}else{
// user doen't filled that data
// ask him to fill the form
alert.showAlertDialog(RegisterActivity.this, "Registration Error!", "Please enter your details", false);
}
}
});
}
}
11. Now open your main activity file (In my case MainActivity.java) and type the following code.
In the following code I am receiving name, email sent from RegisterActivity and storing them in static variables.
Then i am checking whether this device has gcm registration id, if not i am registering it on gcm by callingGCMRegistrar.register(this, SENDER_ID) method
private final BroadcastReceiver mHandleMessageReceiver = new BroadcastReceiver() method will be called when device gets a new push notification message. For now i am displaying the message on the screen. You might need to take appropriate action on the message depending upon your app requirement. (Example: Storing it in SQLite database)
MainActivity.java
import static com.androidhive.pushnotifications.CommonUtilities.DISPLAY_MESSAGE_ACTION;
import static com.androidhive.pushnotifications.CommonUtilities.EXTRA_MESSAGE;
import static com.androidhive.pushnotifications.CommonUtilities.SENDER_ID;
import static com.androidhive.pushnotifications.CommonUtilities.SERVER_URL;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;
import java.util.Map.Entry;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import android.R;
import android.R.string;
import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.app.Activity;
import android.app.ListActivity;
import android.app.ProgressDialog;
import android.content.BroadcastReceiver;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.StrictMode;
import android.util.Config;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.ListAdapter;
import android.widget.ListView;
import android.widget.SimpleAdapter;
import android.widget.SimpleCursorAdapter;
import android.widget.TextView;
import android.widget.Toast;
import com.androidhive.pushnotifications.R.id;
import com.google.android.gcm.GCMRegistrar;
@SuppressLint("NewApi")
@TargetApi(Build.VERSION_CODES.GINGERBREAD)
public class MainActivity extends ListActivity {
// label to display gcm messages
TextView lblMessage,t,t1;
StrictMode.ThreadPolicy policy;
Timer time;
int counter=0;
ProgressDialog pd;
ListView lv;
InputStream is;
String result;
//Button b;
String get = "http://10.0.2.2/gcm_server_php/abc.php";
//String get = "http://www.alphainfoways.com/demos/gcm/abc.php";
//String get = "http://www.alphainfoways.com/demos/gcm/abc.php";
String s;
String msg = "msg";
SimpleAdapter a;
JSONArray ja;
String table = "store";
ArrayList<HashMap<String, String>> h = new ArrayList<HashMap<String,String>>();
//JsonParse jsonParse = new JsonParse();
JSONParser jsonParser = new JSONParser();
// Asyntask
AsyncTask<Void, Void, Void> mRegisterTask;
AlertDialogManager alert = new AlertDialogManager();
ConnectionDetector cd;
public static String name;
public static String email;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(com.androidhive.pushnotifications.R.layout.activity_main);
policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
// lv = (ListView)findViewById(R.id.listView1);
cd = new ConnectionDetector(getApplicationContext());
new getdata().execute();
// Check if Internet present
if (!cd.isConnectingToInternet()) {
// Internet Connection is not present
alert.showAlertDialog(MainActivity.this,
"Internet Connection Error",
"Please connect to working Internet connection", false);
// stop executing code by return
return;
}
// Getting name, email from intent
Intent i = getIntent();
name = i.getStringExtra("name");
email = i.getStringExtra("email");
// 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);
lblMessage = (TextView) findViewById(com.androidhive.pushnotifications.R.id.lblMessage);
registerReceiver(mHandleMessageReceiver, new IntentFilter(
DISPLAY_MESSAGE_ACTION));
// Get GCM registration id
final String regId = GCMRegistrar.getRegistrationId(this);
// Check if regid already presents
if (regId.equals("")) {
// Registration is not present, register now with GCM
GCMRegistrar.register(this, SENDER_ID);
} else {
// Device is already registered on GCM
if (GCMRegistrar.isRegisteredOnServer(this)) {
// Skips registration.
Toast.makeText(getApplicationContext(),
"Already registered with GCM", Toast.LENGTH_LONG)
.show();
} else {
// Try to register again, but not in the UI thread.
// It's also necessary to cancel the thread onDestroy(),
// hence the use of AsyncTask instead of a raw thread.
final Context context = this;
mRegisterTask = new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... params) {
// Register on our server
// On server creates a new user
ServerUtilities.register(context, name, email, regId);
return null;
}
@Override
protected void onPostExecute(Void result) {
mRegisterTask = null;
}
};
mRegisterTask.execute(null, null, null);
}
}
}
/**
* Receiving push messages
* */
private final BroadcastReceiver mHandleMessageReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String newMessage = intent.getExtras().getString(EXTRA_MESSAGE);
// Waking up mobile if it is sleeping
// List<NameValuePair> params = new ArrayList<NameValuePair>();
//params.add(new BasicNameValuePair("message", newMessage));
//jsonObject = jsonParser.makeHttpRequest(get, "POST", params);
WakeLocker.acquire(getApplicationContext());
/**
* Take appropriate action on this message depending upon your app
* requirement For now i am just displaying it on the screen
* */
// if(newMessage != null){
// Intent browserIntent = new Intent(Intent.ACTION_VIEW,
// Uri.parse(newMessage));
// startActivity(browserIntent);
// Intent browserIntent = new Intent(Intent.ACTION_VIEW,
// Uri.parse(newMessage));
// startActivity(browserIntent);
// }
// Showing received message\
//lblMessage.setText(newMessage);
//lblMessage.append(newMessage + "\n");
Log.e("msg:-", EXTRA_MESSAGE);
Toast.makeText(getApplicationContext(),
"New Message: " + newMessage, Toast.LENGTH_LONG).show();
// cv = new ContentValues();
//cv.put("MSG", newMessage);
//db.insert("STUDENT", null, cv);
inserttoServer(newMessage);
//keHttpRequest(get, "POST", params);
// Releasing wake lock
WakeLocker.release();
}
private void inserttoServer(String a) {
// TODO Auto-generated method stub
ArrayList<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>();
BasicNameValuePair b1 = new BasicNameValuePair("msg", a);
nameValuePairs.add(b1);
HttpClient httpclient = new DefaultHttpClient();
HttpPost httppost = new HttpPost("http://10.0.2.2/get/insert.php");
try {
//An entity composed of a list of url-encoded pairs. This is typically useful while sending an HTTP POST request.
httppost.setEntity(new UrlEncodedFormEntity(nameValuePairs));
httpclient.execute(httppost);
}
catch (Exception e)
{
e.printStackTrace();
}
}
};
@Override
protected void onDestroy() {
if (mRegisterTask != null) {
mRegisterTask.cancel(true);
}
try {
unregisterReceiver(mHandleMessageReceiver);
GCMRegistrar.onDestroy(this);
} catch (Exception e) {
Log.e("UnRegister Receiver Error", "> " + e.getMessage());
}
super.onDestroy();
}
public class getdata extends AsyncTask<Void, Void, Void>{
@Override
protected Void doInBackground(Void... params) {
// TODO Auto-generated method stub
try {
// defaultHttpClient
DefaultHttpClient httpClient = new DefaultHttpClient();
HttpGet httpGet = new HttpGet(get);
HttpResponse httpResponse = httpClient.execute(httpGet);
HttpEntity httpEntity = httpResponse.getEntity();
is = httpEntity.getContent();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
try {
BufferedReader reader = new BufferedReader(new InputStreamReader(
is, "iso-8859-1"), 8);
StringBuilder sb = new StringBuilder();
String line = null;
while ((line = reader.readLine()) != null) {
sb.append(line + "\n");
}
Log.e("TAG", "sb.toString() >>>>>"+sb.toString());
is.close();
result = sb.toString();
} catch (Exception e) {
Log.e("Buffer Error", "Error converting result " + e.toString());
}
try {
JSONArray ja = new JSONArray(result);
for(int i = 0;i<ja.length();i++){
HashMap<String, String> map = new HashMap<String, String>();
JSONObject jo = ja.getJSONObject(i);
String m = jo.getString("msg");
String he = jo.getString("head");
String fo = jo.getString("foot");
String d = jo.getString("date");
map.put("M", m);
map.put("H", he);
map.put("F", fo);
map.put("D", d);
h.add(map);
}
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
@Override
protected void onPostExecute(Void result) {
// TODO Auto-generated method stub
pd.dismiss();
ListAdapter adp = new SimpleAdapter(MainActivity.this, h, com.androidhive.pushnotifications.R.layout.text, new String[]{"M","H","F","D"},new int[]{com.androidhive.pushnotifications.R.id.lblMessage,com.androidhive.pushnotifications.R.id.textView1,com.androidhive.pushnotifications.R.id.textView2,com.androidhive.pushnotifications.R.id.textView3});
setListAdapter(adp);
super.onPostExecute(result);
}
@Override
protected void onPreExecute() {
// TODO Auto-generated method stub
pd = new ProgressDialog(MainActivity.this);
pd.setMessage("wait.....");
pd.show();
super.onPreExecute();
}
}
}
Waking up device on receiving new notification
You can also wake the device on receiving new notification if the device is sleeping. Add the following permission in your AndroidManifest.xml file
WakeLocker.java
public abstract class WakeLocker {
private static PowerManager.WakeLock wakeLock;
public static void acquire(Context context) {
if (wakeLock != null) wakeLock.release();
PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
wakeLock = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK |
PowerManager.ACQUIRE_CAUSES_WAKEUP |
PowerManager.ON_AFTER_RELEASE, "WakeLock");
wakeLock.acquire();
}
public static void release() {
if (wakeLock != null) wakeLock.release(); wakeLock = null;
}
}
SO, FINISH APPLICATION AND ANY QUERY SO, PLEASE EMAIL ME OTHERWISE CONTACT ME....
|
No comments :
Post a Comment