Android C2DM server and client implementation working

9 Apr 2011 by prathvi palekar, 19 Comments »

1. We will start from server end code

a)create a database named ‘push_android’
and a table to containing 2 fields

devicetoken -  c2dm token recieved from c2dm server
deviceid - android device IMIE Number
< ?php

        $host           =       'localhost'; // most of the time
        $user           =       'databaseusername';
        $pass           =       'databasepassword';
        $database       =       'push_android';
         $connection = mysql_connect ($host, $user, $pass) or die                      ('Error connecting to mysql'.mysql_error());
               //mysql_select_db ( $database,$connection)or die                     ('Error selecting database '.mysql_error());

mysql_selectdb($database) or die ('->>Error selecting database'.mysql_error());
                if ( $_GET [ 'devicetoken' ] != ''&& $_GET['deviceid'] )
                {

                        $token =$_GET ['devicetoken'];
			$device_id = $_GET['deviceid'];
                        $result=mysql_query("SELECT * FROM devicetokens where deviceid='".$device_id."'");
                        if(mysql_num_rows($result)>0 ){
                                $sucess= 'Token Updated ';
				$query = "UPDATE `devicetokens` SET `devicetoken`=
                                                '".$token."' WHERE deviceid='".$device_id."'
      		                                 ";

                                if ( mysql_query ( $query ) )
                                {
                                        $success = 'New Device Token Updated';
                                }
                                else {
                                        die ( mysql_error () );
                                }

                        }else{
                        $query = "INSERT INTO `devicetokens` (`deviceid`,`devicetoken`)
                                                VALUES('".$device_id."','".$token."'
                                                )";

                                if ( mysql_query ( $query ) )
                                {
                                        $success = 'New Device Token added';
                                }
                                else {
                                        die ( mysql_error () );
                                }
                        }
                }
                else {
                        echo 'Please ensure that you have a title and some content for this article!';
                }

        if ( isset ( $success ) ) {
                echo $success;
        }
?>

3.Now we can write some client code (android)

before that lets reuse some code
make a checkout of a sample application by google
svn checkout http://jumpnote.googlecode.com/svn/trunk/ jumpnote-read-only

In the checked directory you can find folder named “JumpNoteAndroid” import that in eclipse.

now copy ‘com.google.android.c2dm’ as it is in your project

now go to your main android package and add the following classes

package com.example.push;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URLEncoder;

import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;

import android.app.Dialog;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.telephony.TelephonyManager;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;

import com.google.android.c2dm.C2DMBaseReceiver;
import com.google.android.c2dm.C2DMessaging;

// TODO: Auto-generated Javadoc
/**
 * Broadcast receiver that handles Android Cloud to Data Messaging (AC2DM)
 * messages, initiated by the JumpNote App Engine server and routed/delivered by
 * Google AC2DM servers. The only currently defined message is 'sync'.
 */
public class C2DMReceiver extends C2DMBaseReceiver {

	/** The Constant TAG. */
	static final String TAG = C2DMConfig.makeLogTag(C2DMReceiver.class);

	/**
	 * Instantiates a new c2 dm receiver.
	 */
	public C2DMReceiver() {
		super( C2DMConfig.C2DM_GOOGLE_ACCOUNT);
	}

	/* (non-Javadoc)
	 * @see com.google.android.c2dm.C2DMBaseReceiver#onError(android.content.Context, java.lang.String)
	 */
	@Override
	public void onError(Context context, String errorId) {
		Toast.makeText(context, "Messaging registration error: " + errorId,
				Toast.LENGTH_LONG).show();
	}

	/* (non-Javadoc)
	 * @see android.content.BroadcastReceiver#onReceive(android.content.Context, android.content.Intent)
	 */
	@Override
	public void onReceive(Context context, Intent intent) {
		super.onHandleIntentRecieved(context, intent);
	}

	/* (non-Javadoc)
	 * @see com.google.android.c2dm.C2DMBaseReceiver#onMessage(android.content.Context, android.content.Intent)
	 */
	@Override
	protected void onMessage(Context context, Intent intent) {
		String message = intent.getExtras().getString("message");
		String strTitle = intent.getExtras().getString("title");
		if (message != null) {
			//write code to do something with your msg
		}
	}

	/* (non-Javadoc)
	 * @see com.google.android.c2dm.C2DMBaseReceiver#onRegistered(android.content.Context, java.lang.String)
	 */
	@Override
	public void onRegistered(Context context, String registrationId)
			throws IOException {
		// TODO
		super.onRegistered(context, registrationId);

		Log.e(TAG, ">>>>id recieved" + registrationId);
		TelephonyManager telephonyManager = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE);

		Log.e(TAG, ">>>>device unique id " + telephonyManager.getDeviceId());
		// send to server
		BufferedReader in = null;
		try {
            HttpClient client = new DefaultHttpClient();
            HttpGet request = new HttpGet();
            try {
				request.setURI(new URI("{your server url}/register_token.php?deviceid="+URLEncoder.encode(telephonyManager.getDeviceId())+"&devicetoken="+URLEncoder.encode(registrationId).toString()));
			} catch (URISyntaxException e) {
				e.printStackTrace();
			}
            HttpResponse response = client.execute(request);
            in = new BufferedReader
            (new InputStreamReader(response.getEntity().getContent()));
            StringBuffer sb = new StringBuffer("");
            String line = "";
            String NL = System.getProperty("line.separator");
            while ((line = in.readLine()) != null) {
                sb.append(line + NL);
            }
            in.close();
            String page = sb.toString();
            System.out.println(page);
            } finally {
            if (in != null) {
                try {
                    in.close();
                    } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

	}

	/* (non-Javadoc)
	 * @see com.google.android.c2dm.C2DMBaseReceiver#onUnregistered(android.content.Context)
	 */
	@Override
	public void onUnregistered(Context context) {
		super.onUnregistered(context);

	}

	/**
	 * Register or unregister based on phone sync settings. Called on each
	 * performSync by the SyncAdapter.
	 *
	 * @param context the context
	 * @param autoSyncDesired the auto sync desired
	 */
	public static void refreshAppC2DMRegistrationState(Context context,
			boolean register) {
		// Determine if there are any auto-syncable accounts. If there are, make
		// sure we are
		// registered with the C2DM servers. If not, unregister the application.

		if (Build.VERSION.SDK_INT < 8) {
			return;
		} else {

			if (register) {
				C2DMessaging.register(context, C2DMConfig.C2DM_GOOGLE_ACCOUNT);
			} else {
				C2DMessaging.unregister(context);
			}

		}
	}
}

Now the class where you put your configuration C2DMConfig.java

/*
 * Copyright 2010 Google Inc.
 *
 * 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.
 */

package com.example.push;

/**
 * Configuration settings for the Android client.
 */
public class C2DMConfig {

	/**
	 * Enabling this is will turn on sync UI icons that notify the user of
	 * pending and active sync status. This is useful for debugging, but
	 * generally not recommended for real applications, as sync on Android is
	 * intended to be unobtrusive. Users can get the same sync status info by
	 * going to Settings > Accounts & Sync.
	 */
	public static final boolean ENABLE_SYNC_UI = true;
	public static final String C2DM_GOOGLE_ACCOUNT = "{your-google-c2dm account}";
	@SuppressWarnings("unchecked")
	public static String makeLogTag(Class cls) {
		String tag = "PushDemo_" + cls.getSimpleName();
		return (tag.length() > 23) ? tag.substring(0, 23) : tag;
	}

}

We are near to the finish
go to AndroidManifest.xml

< ?xml version="1.0" encoding="utf-8"?>

    

    
        
            
                
                
            
        
		
            
            
                
                
            
            
            
                
                
            
        
    


    
	
	
	
	

My default package is “com.example.push” keep in mind to change this accordingly in android manifest

Till here i recieved push notification devicetoken from android C2DM server and on recieve i sent it to the server to store the device token (this completes registration on 3rd party server).

Now remaining stuff is to send a notification to the register devices from the 3rd party server.

here is that php server side code file:send_notification.php

< ?php
        $host           =       'localhost';
        $user           =       '{your-db-username}';
        $pass           =       '{your-db-passwd}';
        $database       =       'push_android';
        $username ="your-google-c2dm-email-id";
	$password = "{your-google-c2dm-acc-passwd}";
	$source="My-Server-Event-Alerter"; //anything that says about ur app
	$service="ac2dm";
        $connection = mysql_connect ($host, $user, $pass) or die                      ('Error connecting to mysql'.mysql_error());
               //mysql_select_db ( $database,$connection)or die                     ('Error selecting database '.mysql_error());

			mysql_selectdb($database) or die ('->>Error selecting database'.mysql_error());
                if ( $_GET [ 'message' ] != '' )
                {
                        $message =$_GET ['message'];
                        echo 'Message sent to server '.$message;

			$post_params = array ( "Email" => $username, "Passwd" => $password, "accountType"=>"GOOGLE", "source" => $source, "service"=>$service ); 

			$first = true;
			$data_msg = "";

			foreach ($post_params as $key => $value) {
			if ($first)
			  $first = false;
			else
			  $data_msg .= "&";

			$data_msg .= urlencode($key) ."=". urlencode($value);
			}

			$x = curl_init("https://www.google.com/accounts/ClientLogin"); 

			curl_setopt($x, CURLOPT_HEADER, 1);
			curl_setopt($x, CURLOPT_POST, 1);
			curl_setopt($x, CURLOPT_POSTFIELDS, $data_msg);
			curl_setopt($x, CURLOPT_RETURNTRANSFER, 1);
			$response = curl_exec($x);
			curl_close($x); 

			echo $response;

			$pos = strpos($response, "Auth=");
			$authKey = trim(substr($response, 5+$pos));

			$result=mysql_query("SELECT * FROM devicetokens");
                        if(mysql_num_rows($result)>0 ){
                                $sucess= 'Message sent to '.mysql_num_rows($result).' devices';
                                $row = mysql_fetch_assoc ( $result );

                                do {
                                        $deviceToken = $row['devicetoken'];
                                        echo 'Device Token:'.$deviceToken . '';
										$data = array(
										'registration_id' => $deviceToken,
										'collapse_key' => 'ck_' . 'col_key',
										'data.message' => $message,
										'data.title' =>'Requestec Push Demo');

										//$data = (is_array($data)) ? http_build_query($data) : $data; 

										$ch = curl_init();

										curl_setopt($ch, CURLOPT_URL, "https://android.apis.google.com/c2dm/send");
										echo 'Content-Length:'.strlen($data);
										$headers = array('Authorization: GoogleLogin auth=' . $authKey/*,'Content-Length:'.strlen($data)*/);
										if($headers){
											curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
										}
										curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
										curl_setopt($ch, CURLOPT_POST, true);
										curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
										curl_setopt($ch, CURLOPT_POSTFIELDS, $data);

										$messagedata = curl_exec($ch);
										echo $messagedata;
										curl_close($ch);
					}while($row = mysql_fetch_assoc ( $result ));
				}
			}
?>

Push Notification

< ?=$sucess;?>

type http://{your-server-url}/send_notification.php in your browser.

there are some extra echo statements put to debug – remove it in production environment

Do post your reply ..
Here is the project PushDemo.zip
Enjoy

Tags: , , , , ,

19 Comments

  1. david says:

    can you please upload your full project.
    thank you,

  2. Varun Dublish says:

    Hey Prathvi,
    Nice Article. But I have my doubts about few things.
    I have just started working on Java , though have expertise in PHP.
    Even following the steps are causing errors in Java Manifest and other files.
    So might be helpful if you provide us with the source code as well.

    Thanks again ,
    Varun

  3. oscar says:

    hi Prathvi
    i have some problem .it’s about send_notification.php
    i don’t know why
    access “https://www.google.com/accounts/ClientLogin”
    the response and the authkey is nothing
    but i use curl not php curl
    will appear the authkey

    is it my php sever problem ? but already extend php curl

    plz help

    • oscar says:

      i change below code can work now

      $ch = curl_init();
      curl_setopt($ch, CURLOPT_URL, “https://www.google.com/accounts/ClientLogin”);
      $post_fields = “accountType=” . urlencode(‘HOSTED_OR_GOOGLE’)
      . “&Email=” . urlencode($username)
      . “&Passwd=” . urlencode($password)
      . “&source=” . urlencode($source)
      . “&service=” . urlencode($service);
      curl_setopt($ch, CURLOPT_HEADER, true);
      curl_setopt($ch, CURLOPT_POST, true);
      curl_setopt($ch, CURLOPT_POSTFIELDS, $post_fields);
      curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
      curl_setopt($ch, CURLOPT_FRESH_CONNECT, true);
      curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
      curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
      // for debugging the request
      //curl_setopt($ch, CURLINFO_HEADER_OUT, true); // for debugging

      $response = curl_exec($ch);

  4. Sonia says:

    Please tell me in which java file you extend activity because to get launch app activity class need to be extended.

  5. Sonia says:

    please reply me as soon as possible.. thanx nice tutorial..

  6. stardust says:

    Hi,

    I get 2 errors :

    I get this error in Eclipse from AndroidManifest.xml

    [2011-07-21 04:03:05 - com.android.ide.eclipse.adt.internal.project.AndroidManifestHelper] Parser exception for /home/sputnick/workspace/Notifier/AndroidManifest.xml: Element type “uses” must be followed by either attribute specifications, “>” or “/>”.
    [2011-07-21 04:03:05 - Notifier] Error in an XML file: aborting build.

    http://pastie.org/2246205

    And this one in the code : http://ompldr.org/vOWs4eQ

    Any hint ?






    • should be




      And for @Override error go to Project>Properties and change “Java compiler” Compiler compliance level to 1.5

      Hope it helps

      • Alex S says:

        Where do you actually call the registration or should that automatically occur? Can you please post the full project or at least your PushDemoActivity.java file to see what is in your OnCreate()?

  7. jamesw says:

    /* (non-Javadoc)
    * @see android.content.BroadcastReceiver#onReceive(android.content.Context, android.content.Intent)
    */
    @Override
    public void onReceive(Context context, Intent intent) {
    super.onHandleIntentRecieved(context, intent);
    }

    causes errors as neither the onReceive nor the onHandleIntentReceived methods exist in C2DMBaseReceiver

    Not entirely sure what the solution to this should be. any guidance appreciated and thanks for a great post

  8. Sumant says:

    Hi,

    It seems to be a nice article, thanks for that but i want to implement push notification in my android application.

    So can u upload full running project so that i can get some information.

    Once again Thanks

  9. Mike says:

    Your code snippets incorrectly format copied data, each line copied starts with ‘#’ or the line number, depending on whether copied by keyboard command or snippet tool.

    On top of that, the java code doesn’t work.

    Is there no way for you to share the project files?

  10. assaf says:

    same here – errors on onReceive and onHandleIntentReceived.
    Ant advice?
    cheers

  11. Sonia says:

    I have implement same code but still I am not receiving notification on device.

    The response which I am getting through send_notifiation.php is-

    id=0:1317191270928916%1716893036225a49

    Please help me

    Sonia

Leave a Reply

Follow Me!

Follow Me! Follow Me! Follow Me! Follow Me!