Thursday 29 March 2012

C2dm Android Push Notification


Looking at all possible solution for C2dm Android Push Notification on various communities ,i would like to contribute best approach which i have been successfully able to implement .
1. I have used Titanium 1.7.5 and 1.8.0.1 earlier ,which don't work and give various errors,which are due to deprecated methods and absence of libraries used in C2dm,i would suggest either to add those libraries in you project by creating a lib folder ,else directly use 1.8.2(best SDK version) and create an empty lib folder.So execute command below in ur MAC Terminal,an alias will be created for ur SDK. alias titanium="Library/Application\ Support/Titanium/mobilesdk/osx/1.8.2/titanium.py". You can check if it is created by using following Command, cd Titanium This will give you Appcelerator Titanium Copyright (c) 2010-2011 by Appcelerator, Inc.
commands:
create - create a project run - run an existing project emulator - start the emulator (android) docgen - generate html docs for a module (android) fastdev - management for the Android fastdev server help - get help
2.Now create a module from your project,by using common below, (Your_root)$ titanium create --platform=android --type=module --name=c2dmmod --id=com.Yourcompany.c2dmmod --android=Documents/android-sdk-mac_x86.
3.Once your module is created in your root directory,u need to change build.properties based on path your machine uses,my machine uses following
titanium.platform=/Users/Yourpath/Library/Application Support/Titanium/mobilesdk/osx/1.8.2/android android.platform=/Users/Yourpath/Documents/android-sdk-mac_x86/platforms/android-8 google.apis=/Users/Yourpath/Documents/android-sdk-mac_x86/add-ons/addon-google_apis-google_inc_-8 android.ndk=/Users/Yourpath/Documents/android-ndk-r7b
Make sure to have ndk,addon-google_apis-google_inc_-8 on ur machine and give respective paths.
4.Download https://github.com/Kuraturpa/titanium-c2dm ,we just need src folder from here replace Source folder of your module with src folder of newly downloaded project from link above.
5.Now we are set with Module which has your build properties(as per your machine),src replaced,wince they have find law and google code which help us execute c2dm.
6.We have to build ant for newly created module,add an empty folder called lib in your module if it doesn't exists.
7.Now before running ant command get into your module directory ,in our case we have created a c2dm module called c2dmmod, so my terminal would look something like (Your_root)-Mac-mini-6:c2dmmod Yourroot$ ant
just get into module's directory and run ant.
8.Once you run ant if every thing is perfect you will get a message saying Build Successful message .Now you will find a new folder called dist(Distribution) has been created in to your module project,with a jar and a zip file of your project(This zip is what we are going to use in our Titanium Project).
9.Now get back into your project where you want to use C2dm and do following
a. Add zip of your Module project to this Titanium Project at Root level,at the same level as tiapp.xml. In our case for module create zip file will be com.findlaw.c2dmmod-android-0.1.zip.
b. In your tiapp.xml add,following
<android xmlns:android="http://schemas.android.com/apk/res/android">
        <manifest>
            <permission
                android:name="Your_Appid.permission.C2D_MESSAGE" android:protectionLevel="signature"/>
            <uses-permission android:name="com.yourcompany.newbuildc2dm.permission.C2D_MESSAGE"/>
            <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"/>
            <uses-permission android:name="android.permission.GET_ACCOUNTS"/>
            <uses-permission android:name="android.permission.USE_CREDENTIALS"/>
            <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
            <application>
                <service android:name="com.findlaw.c2dm.C2DMReceiver"/>
                <receiver
                    android:name="com.google.android.c2dm.C2DMBroadcastReceiver" android:permission="com.google.android.c2dm.permission.SEND">
                    <intent-filter>
                        <action android:name="com.google.android.c2dm.intent.RECEIVE"/>
                        <category android:name="Your_Appid"/>
                    </intent-filter>
                    <intent-filter>
                        <action android:name="android.intent.action.BOOT_COMPLETED"/>
                        <category android:name="android.intent.category.HOME"/>
                    </intent-filter>
                    <intent-filter>
                        <action android:name="com.google.android.c2dm.intent.REGISTRATION"/>
                        <category android:name="Your_Appid"/>
                    </intent-filter>
                </receiver>
            </application>
        </manifest>
    </android>
    <modules>
        <module platform="android" version="0.1">Your Module id</module>
    </modules>


com.findlaw.c2dmmod in module being your module name.
c. Register for c2dm at http://code.google.com/android/c2dm/signup.html.
D. From downloaded example of https://github.com/Kuraturpa/titanium-c2dm,you can use same app.js file in your Titanium project,replace var senderId = 'Your registered Gmail id'; var c2dm = require('Your module name);
e. Change Class name and package name based on your project settings className: 'Your_Appid.YourActivity_name' (Your Activity name can be found at YourProject/Build/Android/Gen/Your module/Activity.java(Activity name would be based on your project id,just pick name of file with name as activity,don't copy .java just name is enough). packageName: 'Your App_id'(Can be seem in tiapp.xml).
10.Once you run this project as per steps above you will receive a Device id from Google,which we will use in our Server Call.This need to be passed to server 11.Once your done this ,we need to execute php service from Server end,following is code which you will need to execute,

<?php /* * * $username - your gmail email address you white listed with the c2dm service * $password - password for above gmail account. */
function googleAuthenticate($username, $password, $source="Company-AppName-Version", $service="ac2dm") {
@session_start(); 

if( isset($_SESSION['google_auth_id']) &amp;&amp; $_SESSION['google_auth_id'] != null)     
    return $_SESSION['google_auth_id'];  



// get an authorization token 

$ch = curl_init(); 

if(!$ch){ 

    return ''; 
} 




curl_setopt($ch, CURLOPT_URL, &quot;https://www.google.com/accounts/ClientLogin&quot;); 

$post_fields = &quot;accountType=&quot; . urlencode('HOSTED_OR_GOOGLE') 
    . &quot;&amp;Email=&quot; . urlencode($username) 
    . &quot;&amp;Passwd=&quot; . urlencode($password) 
    . &quot;&amp;source=&quot; . urlencode($source) 
    . &quot;&amp;service=&quot; . 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 the request 

$response = curl_exec($ch); 


//echo $response;   


//var_dump(curl_getinfo($ch)); //for debugging the request 
//var_dump($response); 

curl_close($ch); 

if (strpos($response, '200 OK') === false) { 

    echo &quot;200 Not Ok&quot;;
    return ''; 
} 

// find the auth code 
preg_match(&quot;/(Auth=)([\w|-]+)/&quot;, $response, $matches); 

if (!$matches[2]) { 
    echo &quot;No Match&quot;;
    return ''; 
} 

$_SESSION['google_auth_id'] = $matches[2]; 

 return $matches[2]; 

 //return true;
}
/* * * $authCode - the authcode returned when you ran the googleAuthenticate function * $deviceRegistrationId - registrationID returned by the device receiving the message * $$msgType - can be anything i.e. 'chat message' * $messageText - text to be sent */
function sendMessageToPhone($authCode, $deviceRegistrationId, $msgType, $messageText) {
    $headers = array('Authorization: GoogleLogin auth=' . $authCode); 
    $data = array( 
        'registration_id' =&gt; $deviceRegistrationId, 
        'collapse_key' =&gt; $msgType, 
        'data.message' =&gt; $messageText //TODO Add more params with just simple data instead            
    ); 

    $ch = curl_init(); 

    curl_setopt($ch, CURLOPT_URL, &quot;https://android.apis.google.com/c2dm/send&quot;); 

    if ($headers) 
        curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); 
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); 
    curl_setopt($ch, CURLOPT_POST, true); 
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); 
    curl_setopt($ch, CURLOPT_POSTFIELDS, $data); 


    $response = curl_exec($ch); 

    curl_close($ch); 

    echo $response; 

    //var_dump($response);
}
$msgType = 'chat message111'; $message = 'Friend Request111!';
$regID='Your Device regestration ID';
$auth = googleAuthenticate("Your Registered Email Id","Yourmessage","Your Titanium project's App ID"); sendMessageToPhone($auth, $regID, $msgType, $message);
  ?>

12.Once you run this from server you will get Notification on your device ,which while have message as sent,this will redirect you to your app when clicked.
13.I have checked all possible solutions,and finally been able to get Notifications following steps above. I would suggest to use 1.8.2 SDK,1.8.0.1 has many bugs hence i would't advice you that.
14.Thanks all communities which have inspired me to write this and given me a strong urge to share what we receive.

26 comments:

  1. Thanks for such a great guide; however when I run the first command (creating the project) I get the following:

    pc229139:~ administrator$ titanium create --platform=android --type=module --name=c2dmcumobile --id=edu.cedarville.cd2cumobile --android=/Users/administrator/android-sdks/
    [ERROR] Couldn't find the Google APIs r8 add-on directory
    Aborting

    ReplyDelete
  2. hey my friend i cant find this directory
    Library/Application\ Support/Titanium/mobilesdk/osx/1.8.2/titanium.py
    since i searched on titanium.py and i didn't find it :S

    Note: i'm working on mac

    ReplyDelete
    Replies
    1. It shoudl be there, inf act inside any of the sdks. You could repeat this procedure with the 2.0.1GA2 and obtain the same results. (I had to do this in order to use the module with the new Ti 2.0 SDK)

      Delete
  3. @Abraham in case of "Couldn't find the Google APIs r8 add-on directory",u have to download that in ur android folders

    ReplyDelete
    Replies
    1. Actually; I had the Google API SDK already, however I had to rename the folder to whatever Titanium was looking for.

      Delete
  4. @ramzi,dude its the lastest version of titanium u hav to download that API

    ReplyDelete
  5. I can build the module and require it, but I get this error: Object #C2dmmod has no method 'registerC2dm'.

    I've looked at the C2dmModule.java file and registerC2dm is defined as public void registerC2dm(String senderId, HashMap options), so everything should work fine.

    It looks like my module isn't aware of this source code. Do you have any idea what's going on?

    ReplyDelete
  6. That method should be in this project please check https://github.com/Kuraturpa/titanium-c2dm,download that

    ReplyDelete
  7. This comment has been removed by the author.

    ReplyDelete
  8. Ok, I got it to work by making sure my module name is exactly "com.findlaw.c2dm". The problem was I called my module something else.

    So now I'm getting permission problems:

    Permission Denial: receiving Intent { act=com.google.android.c2dm.intent.REGISTRATION cat=[com.mytest.myproject] (has extras) } to com.mytest.myproject requires com.mytest.myproject.permission.C2D_MESSAGE due to sender com.google.android.gsf (uid 10023)

    But I'm sure I'll figure that by Googling around. Thanks for a very detailed and helpful post! :)

    ReplyDelete
  9. Figured out the permission problem. If anyone is having the same issue, please note that in the manifest example above (tiapp.xml), this line:

    com.sagarsoft.newbuildc2dm.permission.C2D_MESSAGE

    should really be:

    Your_Appid.permission.C2D_MESSAGE

    Perhaps obvious, but I managed to overlook it nevertheless.

    ReplyDelete
  10. Great work by my buddy bushan :)

    ReplyDelete
  11. First of all thanks for this guide. I was able to implement a c2dm modul. The registration was successful and i could receive Push Notifications, but only when the app was running. When the app is closed, it not works.
    On both engines i can see in ddms that the module receives the messege.

    On V8 the logcat stops with:
    "Runtime disposed, cannot call function."

    And on Rhino the module is able to start the Callback Funktion in the app and breaks on creating Intent with:
    "Activity is null or already finishing, skipping dialog."

    Have somebody an idea what's wrong?

    ReplyDelete
  12. @Alex I think you have to create a android service that will run even your app is closed. Write your Logic in that service so that the service takes care of your app's push notification when your app is closed.

    ReplyDelete
    Replies
    1. Thanks for your answer, but it not solves the problem. With background service it shows the same behavior.

      Delete
  13. can any one tell me how to pass my registration iD to the server. I know its a lame question- new to it

    ReplyDelete
    Replies
    1. There is an example in the Appcelerator Wiki:
      https://wiki.appcelerator.org/display/guides/Working+with+JSON+Data

      Delete
  14. Thanks for the post Bhushan...I have a problem when i am replacing src folder..it gives me error that no register method found.when i am creating module first time then it's working fine.

    so if possible then can you please share the code ??

    ReplyDelete
  15. @Sarfaraz,Make sure you are using https://github.com/Kuraturpa/titanium-c2dm ,since this download gives you method called "c2dm.register",which is present in its app.js file,i think u r missing that js file

    ReplyDelete
  16. Hi which path to give in the --android="" in the create command. Because my android SDK is in the path /users/myname/.eclipse and whatever path I gave in --android field it shaows like no android sdk-8 even though I am having it in the same path.

    ReplyDelete
  17. Hi Niv,please chk point number 3 above

    ReplyDelete
  18. that point only I am not understanding. Can I create the module anywhere in the root directory?
    If so I tried to give the path /users/myuser
    but it shows the same error as I mentioned above

    ReplyDelete
  19. my path in terminal is like this Niv-MacBook:~ awsuser006$ titanium create --platform=android --type=module --name=c2dmmod --id=com.Yourcompany.c2dmmod --android=Users/awsuser006
    and its showing exception like no android sdk-8.
    But I am having it in Niv-MacBook:~ awsuser006$ cd .eclipse/platforms/android-8. Please reply me where should I create it.

    ReplyDelete
  20. Looks like its unable to find ur Android,i would suggest you to download sdk at above mentioned path and try using it.Keep the existing eclipse related android same place,but download new at a common place say above mentioned path.

    ReplyDelete
  21. Nice post with great details. I really appreciate your job. desktop notification software

    ReplyDelete
  22. Thanks hope it helped you :)

    ReplyDelete