First I would like to describe the need of c2dm.Basically c2dm stands for cloud to device messaging is a service provided by Google for notification of frequent updates.I describe a example which needs for c2dm. Suppose we have a e-commerce site on which we have a android mobile application which synchronize with all website work.and In this mobile application we want that when admin of website add some product or does some update then mobile app get some notification of having update and change their data accordingly.So In android we can do this by two way.
(1)one way is we can run a background thread during application run time,and checked periodically on server here there is any update or not.If it found some update then show some notification and look up for update.but there is a problem in this approach.problem is on which period we will check for update.it will spoil device battery life and busy many resources of device.So this is not feasible in my point of view.If we don't have option then we can go through this also.But fortunately there is an option for this provided by google that is called c2dm.
(2)the second way is c2dm from google lab.I want to discuss the limitation of c2dm first then I will describe in detail.the main limitation is we should check this on device only having os version greater than or equal to android os 2.2(froyo).
Now we should follow certain steps to complete our demo.
(a)Registration for c2dm: The first step is to register a valid gmail id,application package name,contact mail on http://code.google.com/android/c2dm/signup.html then you will recieve a noreply mail for confirmation of this registration.We can increase our message quota also on sending mail to c2dm team.
(b)Role of Third Party Application server: Now we need an application server having ssl certificate that mean a server which support https capability .We can write server side in any technology which your server support.but I have written my server code in php so I will provide the code for server side.this is test.php,suppose this is on site https://www.Loremipsum.com/
/**
*
* @package c2dm
* @version $Id$
* @copyright (c) 2011 lytsing.org
* Description: C2DM implementation PHP code
* refer to: http://stackoverflow.com/questions/4121508/c2dm-implementation-php-code
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
$ob=new c2dm();
$ob->getAuthToken(your registered gmail username,password of mail);
$ob->handleMultiCient();
class c2dm {
var $authString = "";
/**
* Get Google login auth token
* @see http://code.google.com/apis/accounts/docs/AuthForInstalledApps.html
*/
function getAuthToken($username,$password) {
// Initialize the curl object
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, "https://www.google.com/accounts/ClientLogin");
curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true);
$data = array(
'Email' => $username ,
'Passwd' => $password ,
'accountType' => 'HOSTED_OR_GOOGLE',
'source' => 'Company-AppName-Version',
'service' => 'ac2dm');
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt($curl, CURLOPT_POST, true);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
$response = curl_exec($curl);
curl_close($curl);
echo $response;
// Get the Auth string
preg_match("/Auth=([a-z0-9_\-]+)/i", $response, $matches);
$this->authString = $matches[1];
}
/*
*Multiple Users sending
*/
function handleMultiCient()
{
$fp=fopen("imp.txt","r");
$content=fread($fp,filesize("imp.txt"));
$arr=explode(",",$content);
array_pop($arr);
foreach($arr as $temp)
{
$this->sendMessage($temp,1);
}
}
/**
* Send HTTP POST data form
*/
function sendMessage($deviceRegistrationId, $msgType) {
$headers[] = 'Authorization: GoogleLogin auth='.$this->authString;
$data = array(
'registration_id' =$deviceRegistrationId,
'collapse_key' = 1,
'data.message' = 'Hello, c2dm developed by Ashwani' //Add message here.
);
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, "https://android.apis.google.com/c2dm/send");
curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
curl_setopt($curl, CURLOPT_HEADER, 0);
curl_setopt($curl, CURLOPT_POST, true);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
$response = curl_exec($curl);
curl_close($curl);
return $response;
}
}
?>;
Now create a second page on server for storing registration id of devices in file,we can store this in database also,but I store in file named imp.txt .I put this file name as credential.php.
$registration_id=$_REQUEST["registration_id"].',';
$fp=fopen("imp.txt","a");
fwrite($fp,$registration_id);
fclose($fp);
?>
(C)Android coding for c2dm: Now create the android project having same package name that is used for registration of c2dm.Now please write the code given below in your main activity.
package x.y.z;//your package name(For example I am using x.y.z for whole android coding)
import android.app.Activity;
import android.app.PendingIntent;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
public class Dummyc2dmActivity extends Activity {
/** Called when the activity is first created. */
String s="a@a.a"//you registered gmail id that is used in c2dm registration and php
@Override
public void onCreate(Bundle b)
{
super.onCreate(b);
setContentView(R.layout.main);
}
public void registerIt(View v)
{
Intent registrationIntent = new Intent("com.google.android.c2dm.intent.REGISTER");
registrationIntent.putExtra("app", PendingIntent.getBroadcast(this, 0, new Intent(), 0)); // boilerplate
registrationIntent.putExtra("sender",s);
startService(registrationIntent);
}
}
Now create a receiver,Here is the code
package x.y.z;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import org.apache.http.HttpResponse;
import org.apache.http.HttpVersion;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.conn.params.ConnManagerPNames;
import org.apache.http.conn.params.ConnPerRouteBean;
import org.apache.http.conn.scheme.PlainSocketFactory;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.SingleClientConnManager;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpParams;
import org.apache.http.params.HttpProtocolParams;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Vibrator;
import android.widget.Toast;
public class C2DMReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals("com.google.android.c2dm.intent.REGISTRATION")) {
String registration = intent.getStringExtra("registration_id");
if (intent.getStringExtra("error") != null) {
// handle an error for registration
} else if (intent.getStringExtra("unregistered") != null) {
// call service to handle unregistration
} else if (registration != null) {
HttpPost hg=new HttpPost(" https://www.Loremipsum.com/ credential.php?registration_id="+registration);//path of page that you created in php to store credential
SchemeRegistry schemeRegistry = new SchemeRegistry();
schemeRegistry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
schemeRegistry.register(new Scheme("https", new EasySSLSocketFactory(), 443));
HttpParams params = new BasicHttpParams();
params.setParameter(ConnManagerPNames.MAX_TOTAL_CONNECTIONS, 30);
params.setParameter(ConnManagerPNames.MAX_CONNECTIONS_PER_ROUTE, new ConnPerRouteBean(30));
params.setParameter(HttpProtocolParams.USE_EXPECT_CONTINUE, false);
HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
ClientConnectionManager cm = new SingleClientConnManager(params, schemeRegistry);
HttpClient hc = new DefaultHttpClient(cm, params);
try {
HttpResponse hr=hc.execute(hg);
InputStream is=hr.getEntity().getContent();
BufferedReader br=new BufferedReader(new InputStreamReader(is));
String s="";
while((s=br.readLine())!=null)
{
Toast.makeText(context,"registered",2000).show();
}
} catch (ClientProtocolException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// call service to handle registration
}
} else if (intent.getAction().equals("com.google.android.c2dm.intent.RECEIVE")) {
// we are just going to say a few fields already exist here, but this is based
// on what you may be sending from above in your data fields
String message=intent.getExtras().getString("message");
Vibrator vibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
vibrator.vibrate(5000);
Toast.makeText(context, message, 15000).show();
}
}
}
Now we add two utilities file for ignoring SSLpeerunverified exception in our project,the first file code is given below
import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.TrustManager;
import org.apache.http.conn.ConnectTimeoutException;
import org.apache.http.conn.scheme.LayeredSocketFactory;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
/**
* This socket factory will create ssl socket that accepts self signed
* certificate
*
* @author olamy
* @version $Id: EasySSLSocketFactory.java 765355 2009-04-15 20:59:07Z evenisse
* $
* @since 1.2.3
*/
public class EasySSLSocketFactory implements LayeredSocketFactory {
private SSLContext sslcontext = null;
private static SSLContext createEasySSLContext() throws IOException {
try {
SSLContext context = SSLContext.getInstance("TLS");
context.init(null, new TrustManager[] { new EasyX509TrustManager(
null) }, null);
return context;
} catch (Exception e) {
throw new IOException(e.getMessage());
}
}
private SSLContext getSSLContext() throws IOException {
if (this.sslcontext == null) {
this.sslcontext = createEasySSLContext();
}
return this.sslcontext;
}
/**
* @see org.apache.http.conn.scheme.SocketFactory#connectSocket(java.net.Socket,
* java.lang.String, int, java.net.InetAddress, int,
* org.apache.http.params.HttpParams)
*/
public Socket connectSocket(Socket sock, String host, int port,
InetAddress localAddress, int localPort, HttpParams params)
throws IOException, UnknownHostException, ConnectTimeoutException {
int connTimeout = HttpConnectionParams.getConnectionTimeout(params);
int soTimeout = HttpConnectionParams.getSoTimeout(params);
InetSocketAddress remoteAddress = new InetSocketAddress(host, port);
SSLSocket sslsock = (SSLSocket) ((sock != null) ? sock : createSocket());
if ((localAddress != null) || (localPort > 0)) {
// we need to bind explicitly
if (localPort < 0) {
localPort = 0; // indicates "any"
}
InetSocketAddress isa = new InetSocketAddress(localAddress,
localPort);
sslsock.bind(isa);
}
sslsock.connect(remoteAddress, connTimeout);
sslsock.setSoTimeout(soTimeout);
return sslsock;
}
/**
* @see org.apache.http.conn.scheme.SocketFactory#createSocket()
*/
public Socket createSocket() throws IOException {
return getSSLContext().getSocketFactory().createSocket();
}
/**
* @see org.apache.http.conn.scheme.SocketFactory#isSecure(java.net.Socket)
*/
public boolean isSecure(Socket socket) throws IllegalArgumentException {
return true;
}
/**
* @see org.apache.http.conn.scheme.LayeredSocketFactory#createSocket(java.net.Socket,
* java.lang.String, int, boolean)
*/
public Socket createSocket(Socket socket, String host, int port, boolean autoClose)
throws IOException, UnknownHostException {
//return getSSLContext().getSocketFactory().createSocket();
return getSSLContext().getSocketFactory().createSocket(socket, host, port, autoClose);
}
// -------------------------------------------------------------------
// javadoc in org.apache.http.conn.scheme.SocketFactory says :
// Both Object.equals() and Object.hashCode() must be overridden
// for the correct operation of some connection managers
// -------------------------------------------------------------------
public boolean equals(Object obj) {
return ((obj != null) && obj.getClass().equals(
EasySSLSocketFactory.class));
}
public int hashCode() {
return EasySSLSocketFactory.class.hashCode();
}
}
then after the second file code is now:
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;
/**
* @author olamy
* @version $Id: EasyX509TrustManager.java 765355 2009-04-15 20:59:07Z evenisse $
* @since 1.2.3
*/
public class EasyX509TrustManager
implements X509TrustManager
{
private X509TrustManager standardTrustManager = null;
/**
* Constructor for EasyX509TrustManager.
*/
public EasyX509TrustManager( KeyStore keystore )
throws NoSuchAlgorithmException, KeyStoreException
{
super();
TrustManagerFactory factory = TrustManagerFactory.getInstance( TrustManagerFactory.getDefaultAlgorithm() );
factory.init( keystore );
TrustManager[] trustmanagers = factory.getTrustManagers();
if ( trustmanagers.length == 0 )
{
throw new NoSuchAlgorithmException( "no trust manager found" );
}
this.standardTrustManager = (X509TrustManager) trustmanagers[0];
}
/**
* @see javax.net.ssl.X509TrustManager#checkClientTrusted(X509Certificate[],String authType)
*/
public void checkClientTrusted( X509Certificate[] certificates, String authType )
throws CertificateException
{
standardTrustManager.checkClientTrusted( certificates, authType );
}
/**
* @see javax.net.ssl.X509TrustManager#checkServerTrusted(X509Certificate[],String authType)
*/
public void checkServerTrusted( X509Certificate[] certificates, String authType )
throws CertificateException
{
if ( ( certificates != null ) && ( certificates.length == 1 ) )
{
certificates[0].checkValidity();
}
else
{
standardTrustManager.checkServerTrusted( certificates, authType );
}
}
/**
* @see javax.net.ssl.X509TrustManager#getAcceptedIssuers()
*/
public X509Certificate[] getAcceptedIssuers()
{
return this.standardTrustManager.getAcceptedIssuers();
}
}
Now we have androidmanifest.xml file.please if you will find any html tag like br,span,<,> then kindly omit this from file.paste this in your mainfest file.
Now write the code for main.xml that is given below.
please omit html tag specially br tag from this code and copy this into main.xml.
then run this on android device having os more than 2.2 or equal to 2.2.you can run this on emulator having AVD image 2.2 or more.For emulator and device both have already android market installed already,and both have sync with valid gmail id.then run the application on device,and click register button.Now run the main php file from server i.e. https://www.loremipsum.com/test.php and you will see a message and vibration on device and only message on emultor will appear.that's the full demo of c2dm including PHP.In Real world we will not have to send original data,only notification have to send that please cache all the data from server.then fetch the original data it will save the battery of device and optimize the use of device resources .that's all about for this blog from my side.
please comment on this blog and feel free to any query.
Thanks: