Ads

Monday, October 7, 2013

ACS Push Notification using GCM

Titanium CloudPush module supports two protocols for send push notifications to Android devices.
  1. GCM (Google Cloud Messaging) 
    From Ti SDK 3.1.2 onwards, GCM is the default method to send push notifications. GCM supports devices that run Android 2.2 and later, and requires that the Google Play Store application be installed. For pre-4.0 devices, the user is required to set up their Google account. 

    If you have an existing application that uses the MQTT protocol, you either need to transition your application to use GCM or set the acs-push-type key in the tiapp.xml file to mqtt. This will be explain in detail at end of this tutorial.

  2. MQTT (MQ Telemetry Transport) 
    It is lightweight messaging protocol, designed for constrained devices and low-bandwidth, high-latency or unreliable networks. It consumes less battery. MQTT does not have any specific device requirements.
Here I am going to explain ACS Push Notification using GCM and migrating existing MQTT protocol application to GCM.

We can achieve GCM Push Notification in 6 easy steps
  1. Setting up Google Cloud Messaging
  2. Push Configuration in ACS Console
  3. CloudPush Module Implementation
  4. Retrieve Device Token
  5. Cloud User Login
  6. Subscribe a Channel
1.  Setting up Google Cloud Messaging

Following information taken from here.

To use GCM, you need to create a Google API project to obtain a Google API key and GCM sender ID. For instructions on creating and obtaining these items, see Android Developer: Getting Started with GCM and follow the directions in "Creating a Google API Project", "Enabling the GCM Service" and "Obtaining an API Key".

When creating a new server key, you are asked for a list of IP addresses to accept requests from. Do not enter any information in the textbox and click Create to accept all IP addresses.

Now you will have Google Cloud Messaging (GCM) API Key and GCM sender ID. We are going to used these two values in Step 2.

For detailed instructions, see the "Push Notification" section of ACS: Android SDK.


Google Cloud Messaging Console

2. Push Configuration in ACS Console

Go to https://my.appcelerator.com/apps, then go to My Apps -> Manage ACS -> DEVELOPMENT -> Settings/Android Push Configuration and enter your Google API key in the Google Cloud Messaging (GCM) API Key textbox and GCM sender ID in the Google Cloud Messaging (GCM) Sender ID textbox. (which we got from Step 1) 

Android Push Configuration
Note: If you are using MQTT, just enter application package alone.

3. CloudPush Module Implementation
  • Add CloudPush module into your application.
  • To use push notifications, in the tiapp.xml file, you need to specify push type (either gcm or mqtt). 
CloudPush module
4. Retrieve Device Token

Call the retrieveDeviceToken method before setting the enabled property to true to enable the device to receive push notifications. You must call retrieveDeviceToken before any other CloudPush API call or else the device will not receive push notifications. So below code must be top of any other CloudPush API call.

var CloudPush = require('ti.cloudpush');
CloudPush.retrieveDeviceToken({
    success: function deviceTokenSuccess(e) {
        Ti.API.info('Device Token: ' + e.deviceToken);
    },
    error: function deviceTokenError(e) {
        alert('Failed to register for push! ' + e.error);
    }
});

5. Cloud User Login

Before subscribe for Push Notification, cloud user should logg in.  So create a test user in Appcelerator Cloud Console My Apps -> Manage ACS ->  DEVELOPMENT ->  Users
and login with credential. Use below code for cloud user login

Cloud.Users.login({
    login: 'push123',
    password: 'push123'
}, function (e) {
    if (e.success) {
        alert("login success");
    } else {
        alert('Error: ' + ((e.error & amp; & amp; e.message) || JSON.stringify(e)));
    }
});    

6. Subscribe a Channel

Add following code for channel subscription
 
Cloud.PushNotifications.subscribe({
    channel: 'alert', //'alert' is channel name
    device_token: deviceToken,
    type: 'gcm' //here i am using gcm, it is recommended one
}, function (e) {
    if (e.success) {
        alert('Subscribed for Push Notification!');
    } else {
        alert('Subscribe error:' + ((e.error & amp; & amp; e.message) || JSON.stringify(e)));
    }
});

Using MQTT with ACS

Using MQTT with ACS similar to above one, but few steps has slighter difference. Please follow below things
  1. Step 1(Setting up Google Cloud Messaging) not necessary 
  2. In Step 2, just enter application package in text box. No need to enter GCM API Key and GCM sender ID
  3. In Step 3, use acs push type as mqtt instead of gcm
  4. In Step 6, use type as 'android' instead of 'gcm'
Cool.., You have completed Android Push Notification setup(Here is the whole sample app). This is time for testing, run the application in android device and click the button "Android Cloud Push Notification". You will get 3 alerts continuously.

Then go to My Apps -> Manage ACS -> DEVELOPMENT -> Push Notifications, here you can see "1 Android clients subscribed to push notifications"


Push Notifications Subscription
How to customize ACS Push notification?
Here you can use use your custom sounds and icons.

Icon
custom icons must be placed in below directory
app_root/platform/android/res/drawable/myicon.png 

Here "myicon.png" is custom icon, specified in the push message without the filename extension. For example: in icon text box enter the file name without extension(myicon)

Sound
Custom sound must be placed in below directory
app_root/platform/android/assets/sound/beep.wav 

Here "beep.wav" is custom sound, specified in the push message with the filename extension. For example: in custom sound text box you have to enter sound filename with extension(beep.wav). Here is the screens of custom notification

ACS Push Notification Screenshot
Source code:
 
Here you can download the complete working project from my Github ACS Android Push Notification with GCM

Note: 
  1. AppC strongly recommend you to use and migrate to GCM.
  2. java.lang.ExceptionInInitializerError at com.appcelerator.cloud.push.CCPushService.registerGCMServiceBackground(CCPushService.java:482) - If you encountered this error in Android 2.3, you have to use ti.cloudpush 2.3.3. You can download here.

26 comments:

  1. I've tried to use it and end up with the same error mentioned here:
    http://developer.appcelerator.com/question/157164/acs-saying-invalidregistration-on-test-pushes-to-android-devices
    keys are set up and I filled out all pages

    ReplyDelete
  2. @peter20081 make sure your cloudpush module version. If you are using Android 2.3, you have to use ti.cloudpush-android-2.3.3

    ReplyDelete
  3. I'm using Android 4.3 (Nexus 4) and using the latest ti.cloudpush (should be 2.3.3, its the next number in the module list). In the debug it says that login and subscribe is done with success. And I'm getting "success" when sending a push from the device. But when I look inside the cloud.appcelerator.com Push log I only see "HTTP Status Code: 401". Very strange. Even when I try to send a push from the cloud webpage it doesn't work

    ReplyDelete
  4. valuable link


    http://docs.appcelerator.com/titanium/3.0/#!/guide/Appcelerator_Cloud_Services

    ReplyDelete
  5. I have the same problem. How can i fix?

    ReplyDelete
  6. Did all the configuration as above. ti.cloudpush updated to 2.3.3. Still gives error : ERROR = INVALID_SENDER. Is there anything we need to add to android manifest? Plz help.

    ReplyDelete
  7. also the log contains this.

    com.appcelerator.cloud.push.CCPushService -

    GCM RegistrationId not found. Need to make request to generate.


    Not sure what I am missing here. Plz Help.

    ReplyDelete
  8. I have the same problem. Impossible to retrieve the device Token on an Android 2.3. I havnt find any solution yet. If somebody could help us :). Thanks

    ReplyDelete
  9. Hi,

    Thanks for this all information i try this way and it working for me via development. In part of Development it work but not able to send notification in Production part.How to send that all notification via Production ?

    Way working : My Apps -> Manage ACS -> DEVELOPMENT -> Push Notifications

    Way NOT working : My Apps -> Manage ACS -> PRODUCTION -> Push Notifications

    Thanks,
    Dharmik

    ReplyDelete
  10. Thanks for such a wonderful tutorial. But what if i want to send notification through my portal can i still approach the above procedure if yes can anyone pls guide me how to do that??

    ReplyDelete
  11. I have problem to get this working.

    App successfully log in and subscribe notifications channel but It doesn't receive any message.

    I think problem is in Android Push Configuration in appcelerator settings. It's not clearly said how to set this with new google console. I spent lot of time changing configurations with almost two results:

    "No sending logs found for this push notification. Push notification logs of requests will be visible here when push notifications are sent to subscribers of this app."

    OR

    Send Status: Fail
    Error message: MismatchSenderId

    ReplyDelete
  12. I have a similar problem, but my results are:
    Send Status: Over Due
    Error message: Unknown

    User are suscribed but, I don't know if the Api key is the right key. I used the dev_keystore to get the SHA1

    ReplyDelete
  13. Hello!

    First thank you very much about this!

    I have the users registered and suscribed correctly, but when I send a notification via ACS or using notify(), the notification does not arrive.

    On push logs, here is the result:
    Send Status: Over Due
    Error message: Unknown

    User are suscribed but, I don't know if the Api key is the right key. I used the dev_keystore to get the SHA1

    If anyone can helps... thank you very much!

    ReplyDelete
  14. I'm also having this problem. Any solution yet? :(

    ReplyDelete
  15. Try to create the key using "server key" instead "android key". It worked for me!

    ReplyDelete
  16. hey...i tried your example above...i am on titanium 3.1.3.GA
    retrieveDeviceToken works fine and subscribing to the channel also works fine however when i use titanium ACS to send a push notification the application crashes with the following error:

    [ERROR][TiApplication( 511)] (main) [24563,57902] Sending event: exception on thread: main msg:java.lang.NoSuchMethodError: org.appcelerator.titanium.TiApplication.isCurrentActivityInForeground; Titanium 3.1.3,2013/09/18 12:01,222f4d1

    [ERROR][TiApplication( 511)] java.lang.NoSuchMethodError: org.appcelerator.titanium.TiApplication.isCurrentActivityInForeground

    [ERROR][TiApplication( 511)] at ti.cloudpush.CloudpushModuleGeneric.receivePayload(CloudpushModuleGeneric.java:81)

    [ERROR][TiApplication( 511)] at ti.cloudpush.GCMReceiver.onReceive(GCMReceiver.java:26)

    [ERROR][TiApplication( 511)] at android.app.ActivityThread.handleReceiver(ActivityThread.java:2419)

    [ERROR][TiApplication( 511)] at android.app.ActivityThread.access$1700(ActivityThread.java:135)

    [ERROR][TiApplication( 511)] at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1272)

    [ERROR][TiApplication( 511)] at android.os.Handler.dispatchMessage(Handler.java:102)

    [ERROR][TiApplication( 511)] at android.os.Looper.loop(Looper.java:136)

    [ERROR][TiApplication( 511)] at android.app.ActivityThread.main(ActivityThread.java:5017)

    [ERROR][TiApplication( 511)] at java.lang.reflect.Method.invokeNative(Native Method)

    [ERROR][TiApplication( 511)] at java.lang.reflect.Method.invoke(Method.java:515)

    [ERROR][TiApplication( 511)] at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:779)

    [ERROR][TiApplication( 511)] at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:595)

    [ERROR][TiApplication( 511)] at dalvik.system.NativeStart.main(Native Method)

    [ERROR][AndroidRuntime( 511)] FATAL EXCEPTION: main

    [ERROR][AndroidRuntime( 511)] Process: com.fouadkada.pushnotification, PID: 511

    [ERROR][AndroidRuntime( 511)] java.lang.NoSuchMethodError: org.appcelerator.titanium.TiApplication.isCurrentActivityInForeground

    [ERROR][AndroidRuntime( 511)] at ti.cloudpush.CloudpushModuleGeneric.receivePayload(CloudpushModuleGeneric.java:81)

    [ERROR][AndroidRuntime( 511)] at ti.cloudpush.GCMReceiver.onReceive(GCMReceiver.java:26)

    [ERROR][AndroidRuntime( 511)] at android.app.ActivityThread.handleReceiver(ActivityThread.java:2419)

    [ERROR][AndroidRuntime( 511)] at android.app.ActivityThread.access$1700(ActivityThread.java:135)

    [ERROR][AndroidRuntime( 511)] at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1272)

    [ERROR][AndroidRuntime( 511)] at android.os.Handler.dispatchMessage(Handler.java:102)

    [ERROR][AndroidRuntime( 511)] at android.os.Looper.loop(Looper.java:136)

    [ERROR][AndroidRuntime( 511)] at android.app.ActivityThread.main(ActivityThread.java:5017)

    [ERROR][AndroidRuntime( 511)] at java.lang.reflect.Method.invokeNative(Native Method)

    [ERROR][AndroidRuntime( 511)] at java.lang.reflect.Method.invoke(Method.java:515)

    [ERROR][AndroidRuntime( 511)] at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:779)

    [ERROR][AndroidRuntime( 511)] at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:595)

    [ERROR][AndroidRuntime( 511)] at dalvik.system.NativeStart.main(Native Method)

    has anyone faced this problem before?

    ReplyDelete
  17. Emiliano TortorelliFebruary 14, 2014 at 8:59 PM

    Hi, I have every thing working OK, but there is something I need to do, and I don't know if it is possible...


    I need to send a push to device, but without any kind of alert, notifications or sound. That way I can give an order to the App, and the user never knows about it.


    I manage to send a push without text, sound and icon... but it always shows a notification in the status bar...


    Any one knows how to do something like this?

    ReplyDelete
  18. I had the same issue. Try deleting your app, then run it again. I had all the correct keys and configuration, yet ran into the same error.

    ReplyDelete
  19. Hi all, I know that is not really in this forum, but I need your feedback:

    I'm using the REST API for titanium and try sending notifications sent from a Java process with the following code:

    URL url = null;
    HttpURLConnection uc = null;
    String idSession=null;

    String URL_ACS = "https://api.cloud.appcelerator.com/v1/";

    String ruta=URL_ACS+"push_notification/notify.json?key="+API_KEY+"";

    url=new URL(ruta);
    uc = (HttpURLConnection) url.openConnection();
    uc.setDoInput(true);
    uc.setDoOutput(true);
    uc.setRequestProperty("Content-Type", "application/json");
    uc.setRequestProperty("Accept", "application/json");
    uc.setRequestProperty("Cookie","_session_id="+session_id);

    JSONObject cred = new JSONObject();
    JSONObject push = new JSONObject();
    JSONObject chan = new JSONObject();

    cred.put("alert","Preparacion Pruebas Estres");
    cred.put("title","Pruebas");
    cred.put("icon","icon_notifi");
    cred.put("vibrate",true);
    cred.put("sound","default");
    push.put("payload",cred);
    push.put("channel","all");
    chan.put("push_notification", push);

    OutputStreamWriter wr= new OutputStreamWriter(uc.getOutputStream());
    wr.write(push.toString());

    if (uc.getResponseCode() != 200) {
    throw new Exception(uc.getResponseMessage());
    }
    InputStream is = uc.getInputStream();
    BufferedReader rd = new BufferedReader(
    new InputStreamReader(is));
    StringBuilder sb = new StringBuilder();
    String line;
    while ((line = rd.readLine()) != null) {
    sb.append(line);
    }
    rd.close();
    uc.disconnect();

    But it returns the following error:

    Unprocessable Entity

    The JSON format is:

    {"payload":{"icon":"icon_notifi","title":"Test","sound":"default","alert":"Test Alert","vibrate":true},"channel":"all"}

    ReplyDelete
  20. "At Google Apis console I used the "Key for Android apps" not the server key "
    How I config ? Thanks

    ReplyDelete
  21. i found it but still doesn't receive any message.

    ReplyDelete
  22. oh thanks, i try it on another phone it's oke , thank u so much :D

    ReplyDelete
  23. Arley Andrada MariaJune 24, 2014 at 8:11 AM

    I just released a Push Notification module for Android and iOS, with direct connection to APN (Apple) and GCM (Google), without to require ACS, UrbanAirship or any push broker contract or fee; Receive unlimited free push notifications in your apps..

    [buy PushClient at Appcelerator Marketplace](https://marketplace.appcelerator.com/apps/10615)

    ReplyDelete
  24. great tutorial as always...cheers!!

    ReplyDelete
  25. 3 days of bashing my head against the wall and this did it! Now to find my sanity and will to continue..

    ReplyDelete
  26. Custom Sound is not working. I tried both bells8 and bells8.wav and i am using the latest version of cloudpush. Please, help!!

    ReplyDelete