Using GCM for Android Push Notifications with ACS

Introduction

This article is going to walk you through getting GCM push notifications working in your Android apps.

Push notifications… Those two words send chills down my back. It does not matter if you are talking iOS or Android, push notifications can be very tricky.

As you may or may not know Appcelerator is discontinuing the use of their MQTT push service at the end of this month. That means that if you don’t update your legacy android apps that are using ACS for push and they are not using GCM, they will no longer receive your notifications.

Things to note

For this tutorial I am using the following versions:
Titanium Studio build: 3.2.0.201312162209
Titanium SDK build: 3.2.0.v20131210191510
Alloy build: 1.3.0-cr
Titanium CLI build: 3.2.0-cr3

You can update your current builds here.

As I am writing this, Appcelerator is saying that 3.2.0 should be officially released soon. So please use the most up-to-date version of each SDK to make sure you get the most benefit out of this tutorial.

Also, I am making the assumption that you have all of the required SDKs and software installed and updated. If not, please check out the quick start guide.

Are you using MQTT or GCM?

So how do you know if you are using GCM or MQTT in an existing application? Since we are talking about using Appcelerator’s Cloud Services (ACS), we are going to assume for the rest of this post that you have access to your cloud console.

  1. Open up your Appcelerator cloud console.
  2. Find the app you are working on. For our example it will be “Android Push Test”.
  3. Click on “Manage ACS” then “Settings”. Appcelerator cloud console
  4. Scroll down to “Android Push Configuration”.

Android Push Configuration

Now if you see all of the spaces blank, your push notifications for Android are not setup. However, if you see your package ID, something like com.example.appname, in the first space next to “Application Package” and the next two spaces are blank, then you are using MQTT and this post is for you.

Starting from scratch

If you already have a project started then you can skip this section altogether. This is for people that want to get a project started that will receive push notifications right off the bat.

  1. Open Titanium Studio.
  2. Create new project – At the top of the screen click on File > New > Classic > Default Project then click next.
  3. Enter your project name, app id, select the latest Titanium SDK, and make sure to check the “Cloud Enable this Application” check box. Cloud Enable this Application
  4. Click Finish.

Step 1 – Editing your tiapp.xml

First we are going to add the ti.cloudpush module to your project.

In Titanium Studio double click on your tiapp.xml file from the column on the left.

tiapp.xml

In the window that opens for you, you should see a green plus button. Click the green plus button and add the ti.cloudpush module to your project.

Cloud push module

At this point make sure you save your tiapp.xml.

We will now need the code view, so click on the “tiapp.xml” tab right next to the “Overview” tab in the same window you just used to add the push module.

Now just above the “id” tag it should look something like this:

<id>com.example.androidpushtest</id>

add these lines:

    <property name="acs-push-type-development" type="string">gcm</property>
    <property name="acs-push-type-production" type="string">gcm</property>
    <property name="acs-push-type" type="string">gcm</property>

Make sure you save your tiapp.xml again, this will force your app to use GCM instead of MQTT.

Step 2 – Working with Google

If you have never been acquainted with the Google Cloud Console, here is your introduction.

If you don’t have a Google account you will need one.

Steps to setting up Google Cloud for Android Push notifications:

  1. Go to the Google Cloud Console.
  2. Click Create Project. Create Project
  3. Enter the Project name and Project ID. This can be anything you want as long as it follows Google’s naming conventions. Project Name
  4. Under the project list click on your newly created project.
  5. At the top of the page you will see your “Project Number”, make a note of this number because you will need it later. (Seriously, you will need it. So when I say you need your project number later this is what I am talking about. That number you did not take note of.)
  6. In the left hand column click on “APIs & Auth”.
  7. In the right column find “Google Cloud Messaging for Android” and turn it on. Google will ask you to accept some agreements. Once it is turned on move on to step 8.
  8. In the left hand column again click on “Credentials”.
  9. Click on “Create New Key”.
  10. Click on “Server Key”.
  11. Click on “Create” (You don’t need to enter an IP address).
  12. On the following page find the section labeled “Key for server applications”.
  13. Copy down the API key that is in the server applications section.

Now you have a project number and an API key. Make sure you copy these down because you will need them in the next section.

Step 3 – Working with Appcelerator

Here we will be working in the Appcelerator Cloud Console. Using the keys we just got from Google, we can put those into the ACS console to get everything talking.

  1. Open up your Appcelerator Cloud Console where your apps are listed.
  2. Find the app you are working on, for our example it will be “Android Push Test”.
  3. Click on “Manage ACS” right under the app name. Appcelerator cloud console
  4. Once the new page opens click on the “Settings” tab.
  5. Under the Android Push Configuration section, enter the information we got from Google in the previous section. Android Push Configuration
  6. In the field labeled “Google Cloud Messaging (GCM) API Key:” put the API key we got from Google in the previous section of this tutorial.
  7. In the field labeled “Google Cloud Messaging (GCM) Sender ID:” put the project number we got from Google in the previous section of this tutorial. Project Number = Sender ID.
  8. Click “Save Android Push Configuration Changes”.

Step 4 – Adding the Code

The code below is taken directly from the example code provided by Appcelerator in the CloudPush module.

ti.cloudpush-android-3.2.0.zip

var win = Ti.UI.createWindow({
    layout: 'vertical',
    backgroundColor: 'white'
});

var CloudPush = require('ti.cloudpush');
CloudPush.addEventListener('callback', function (evt) {
    alert(evt.payload);
});
CloudPush.addEventListener('trayClickLaunchedApp', function (evt) {
    Ti.API.info('Tray Click Launched App (app was not running)');
});
CloudPush.addEventListener('trayClickFocusedApp', function (evt) {
    Ti.API.info('Tray Click Focused App (app was already running)');
});

/*
 * Create a label to show Push type
 */
var pushTypeLabel = Ti.UI.createLabel({
    top: '10dp', width: '320dp', height: '25dp',
    textAlign: 'center', font: { fontSize:14}, color: 'black',
    text: 'Push Type: ' + CloudPush.pushType
});
win.add(pushTypeLabel);

/*
 * Create a label to show device token on screen
 */
var deviceTokenLabel = Ti.UI.createLabel({
    top: '10dp', width: '320dp', height: (CloudPush.pushType=='gcm'?'150dp':'40dp'),
    font: { fontSize:14}, color: 'black',
    text: 'Device Token'
});
win.add(deviceTokenLabel);

CloudPush.retrieveDeviceToken({
    success: deviceTokenSuccess,
    error: deviceTokenError
});

function deviceTokenSuccess(e) {
    Ti.API.info('Device Token: ' + e.deviceToken);
    deviceTokenLabel.text = 'Device Token:' + e.deviceToken;
    enablePush.enabled = true;
}

function deviceTokenError(e) {
    alert('Failed to register for push! ' + e.error);
    deviceTokenLabel.text = 'Failed to get device token.';
}

/*
 Push can be enabled or disabled.
 */
var enablePush = Ti.UI.createButton({
    top: '10dp', width: '320dp', height: '40dp',
    enabled: false
});
enablePush.addEventListener('click', function () {
    enablePush.title = CloudPush.enabled ? 'Disabling...' : 'Enabling...';
    CloudPush.enabled = !CloudPush.enabled;
    // NOTE: Push.enabled takes a moment to update after you change its value.
    setTimeout(syncButtons, 500);
});
win.add(enablePush);

/*
 Whether or not to show a tray notification.
 */
var showTrayNotification = Ti.UI.createButton({
    top: '10dp', width: '320dp', height: '40dp'
});
showTrayNotification.addEventListener('click', function () {
    CloudPush.showTrayNotification = !CloudPush.showTrayNotification;
    syncButtons();
});
win.add(showTrayNotification);

/*
 Whether or not clicking a tray notification focuses the app.
 */
var showAppOnTrayClick = Ti.UI.createButton({
    top: '10dp', width: '320dp', height: '40dp'
});
showAppOnTrayClick.addEventListener('click', function () {
    CloudPush.showAppOnTrayClick = !CloudPush.showAppOnTrayClick;
    syncButtons();
});
win.add(showAppOnTrayClick);

/*
 Whether or not tray notifications are shown when the app is in the foreground.
 */
var showTrayNotificationsWhenFocused = Ti.UI.createButton({
    top: '10dp', width: '320dp', height: '40dp'
});
showTrayNotificationsWhenFocused.addEventListener('click', function () {
    CloudPush.showTrayNotificationsWhenFocused = !CloudPush.showTrayNotificationsWhenFocused;
    syncButtons();
});
win.add(showTrayNotificationsWhenFocused);

/*
 Whether or not receiving a push immediately brings the application to the foreground.
 */
var focusAppOnPush = Ti.UI.createButton({
    top: '10dp', width: '320dp', height: '40dp'
});
focusAppOnPush.addEventListener('click', function () {
    CloudPush.focusAppOnPush = !CloudPush.focusAppOnPush;
    syncButtons();
});
win.add(focusAppOnPush);

/*
 Trigger callbacks together or one by one when multiple push notifications come.
 */
var singleCallback = Ti.UI.createButton({
    top: '10dp', width: '320dp', height: '40dp'
});
singleCallback.addEventListener('click', function () {
    CloudPush.singleCallback = !CloudPush.singleCallback;
    syncButtons();
});
win.add(singleCallback);

function syncButtons() {
    enablePush.title = CloudPush.enabled ? 'Push Enabled' : 'Push Disabled';
    showAppOnTrayClick.title = CloudPush.showAppOnTrayClick ? 'Tray Click Shows App' : 'Tray Click Does Nothing';
    showTrayNotification.title = CloudPush.showTrayNotification ? 'Show in Tray' : 'Do Not Show in Tray';
    focusAppOnPush.title = CloudPush.focusAppOnPush ? 'Push Focuses App' : 'Push Doesn\'t Focus App';
    showTrayNotificationsWhenFocused.title = CloudPush.showTrayNotificationsWhenFocused ? 'Show Trays when Focused' : 'Hide Trays when Focused';
    singleCallback.title = CloudPush.singleCallback ? 'Callbacks trigger one by one' : 'Callbacks trigger together';
}

syncButtons();
win.open();

Copy and paste this code into your apps app.js file.

Step 5 – Compile

Whether you use Titanium Studio or Titanium CLI this is the point where you compile your app and run it on your Android device. To find out if everything is working correctly, this is a good time to check out your logs in the ACS Console.

Step 6 – Test

To find your apps ACS push console, find your app in the ACS Console, then click on “Manage ACS” right under the app name. Once the new page opens, click on the “Push Notifications” tab. You should then see a section that says something like “You currently have 0 iOS clients, 1 Android clients subscribed to push notifications.”

Push

Once you have a subscribed Android device, you can test it by typing a message into the “Alert” field on the same page, then clicking the “Send Push Notification” button.

Your turn

Now it’s your turn to get your push notifications updated and ready for GCM.

If you have completed this tutorial and you are still not getting a push notification on your Android device please let me know what I missed.

Good luck!

Josh Jensen is the technical director and a partner at ROAR. ROAR.pro is a leading mobile app company that helps nonprofits realize their potential in the mobile space. Josh has personally developed and launched hundreds of apps and overseen the development and deployment of all of ROAR's systems.


Comments

  • Thet Paing

    Hi,

    Thanks for your tutorial.
    I got error message from app.

    “Failed to register for push! Failed wrong GCM senderID. Getting GCM SenderId failed. Max retry time reaches.”

    Thanks

  • Timoa

    Hi Josh,

    I tested registration of Android device and iOS device but no device is show on Appcelerator dashboard…

    I got device token, type (GCM), success callback, use 3.2.0.GA…

    On iOS7 and iOS6, I renew push registration (remove app => reboot device => change date in future => reboot => install app and it show alert for activation of notification) but no device is registred online (dev / prod). I don’t understand why…

    Thank you for your help (bug on ACS, SDK 3.2.0.GA, etc.).

    Damien

  • Josh Jensen Post author

    Hi, I am glad you found the tutorial helpful.

    Many times this happens because you are using a development build and you placed the sender id and key in the production section of the ACS console. Make sure to check that you entered the information correctly for your development build instead of production.

    You can switch from production to development by going to your apps ACS console and you will see 2 buttons once that says production and one that says development.

    I hope that helps.

  • Josh Jensen Post author

    Hi Damien,

    Let me make sure I understand correctly.

    You are not seeing any registered devices in ACS at all?

    I have 2 suggestions:
    1. If you are seeing Android devices registering and not iOS that is because the code I provided above does not register iOS devices. It only provides the code for Android. Registering iOS devices is a different process. I am sure you know that I just want to make sure.
    2. If you are sure that all your code is setup correctly you may want to check to make sure your ACS keys are correct. Your devices may be registering with one of your other apps accidentally. I know I have done this before.

    If I have misunderstood your question please let me know.

  • Josh Jensen Post author

    You can also try one other thing.

    Try replacing the deviceTokenSuccess function with this gist and see if that works.

    https://gist.github.com/joshjensen/8229433

  • Timoa

    Thank you Josh!

    I’m not only use Push notification with ACS but also Event, Place and Custom Object and I think it’s the right API key but I’m going to reset iOS / Android devices registration and restart with a new test project to validate configuration on ACS (iOS certificate, Google API Key).

    I’m also going to test your Gist code :)

  • kutomer

    Thx the gist works for me :)

  • Ben

    I am using the code block from the bottom of your post. When I click on the “enablePush” button, it says “Enabling…”; but then just reverts back to “Push Disabled” and doesn’t enable the CloudPush.

    How do I fix this?

    Cheers,
    Ben

  • deeps

    Hi,
    I got error message from app.

    “Failed to register for push! Failed wrong GCM senderID. Getting GCM SenderId failed. Max retry time reaches.”

    Note: I placed the sender id and key in the Development section of the ACS console.

    Plz help..

    Thanks,

  • ashish

    good posts but questions is I’m using wordpress plugin with ACS (http://wordpress.org/plugins/mobile-push-notifications/)
    So what should be code change that is required ?
    please tell me
    thanks a lot

  • Janos Csizmas

    Hi!

    I want to send notification automatically? It is possible? How?

    Thanks

  • George

    Great Article. I’ve followed it to the letter.

    I am receiving the device token:
    deviceTokenSuccess event: APA91bEIy48H3PDWijQkvz-SqtNo-XXXXXXXXXXXXXXXXXXXXXXXXXXXX (183 characters), and I do see it being registered in the Subscribed Devices Console of ACS.

    Though when I Subscribe to a Channel, ACS returns an error: “Missing Fields. Required device_token and channel”. I am sure the channel exists as it is hardcoded.

  • Damien Laureaux

    I just lost to subscribe to a channel on ACS.

    It work for me now :) Thx!

  • DieSkim

    Hi, I have written a Titanium Android Module for JPUSH – A Chinese Push Service provider – its working and tested and works really well – visit my site for more details – http://kiteplans.info/2014/04/05/module-appcelerator-titanium-alloy-jpush-push-notification-module-android-china-push-non-gcm/

  • hichemm

    hi george
    thnx for this tutoriel but i have the follwing error failed to register for push google play service is not ready Error:service_missing

  • Josh Jensen Post author

    It sounds like you are testing on a device that might not have Google play services installed. Are you using Genymotion, a simulator, or an actual device.

  • Josh Jensen Post author

    If you are still having issues with this please let me know.

  • Sumana

    Hi,

    Thanks for the article. Its a great help for new titanium developers like me !!
    I am facing an weird scenario, the callback event is not getting called when the application is running in the background (app is minimised ).
    Anyway I can trigger the callback event ?

    Thanks,
    Sumana

  • Josh Jensen Post author

    Hi Sumana, could you tell me what OS you are having this issue with?

    If it is iOS the user has to directly slide or tap your push notification for the callback to be triggered when the app is in the background. In one of my own applications I wrote a small server side script that would read a list of recent push notifications and compare that against what the app had saved. If they were different I would display the push notification in the app as an alert dialog when it was opened the next time. It is a bit of a work around but it makes sure messages are delivered even if the user does not interact with the push notification.

  • Sumana

    Hello Josh,

    Thanks for the quick reply :)
    I am working on android OS.
    I get the notification in my tray/status bar , when i click on the notification the app opens up. When the app is running in foreground or if the app is killed I am getting the desired results.
    The issue is only when the app is in background , I do receive the notification and on touch the application opens , but the callback functions is not triggered where I am doing some processing of the received notification.

    Regards,
    Sumana

  • Sumana

    Hello josh,

    The setting information:
    titanium SDK build: 3.2.2GA
    android:targetSdkVersion=”19″

    Device for testing : Nexus 5
    Android version in device : 4.4.2
    Regards,
    Sumana

  • Josh Jensen Post author

    Thanks for the additional info Sumana. I am sorry that I don’t have any more information for you. I did some digging around to see if I could find anything. I would definitely give the Q&A forum a try. I am sure someone there has had a similar issue and can help you with it.

  • Muqeet

    Hi,

    I’m getting this error when retrieving device token.

    [INFO] : ALERT: (KrollRuntimeThread) [1332,1332] Failed to register for push notifications! Google Play Services is not ready. Error:SERVICE_VERSION_UPDATE_REQUIRED

    Any clue how to fix that?

    Titanium SDK 3.2.2

  • Josh Jensen Post author

    It sounds like you are using a testing device that does not have the Google Play services SDK. Are you using an Emulator like Geny Motion or a kindle fire?

  • Muqeet

    Hey Jensen,

    My bad, I did not setup my account on google play app. So when I did that it worked fine. BTW I had to include some permissions in my custom AndroidManifest to get things working.

    Now problem is that I can see the device subscribed in ACS. But when I send a notification from there I dont get anything on my phone. Familiar?

  • Muqeet

    Do I have to implement any receiver or something, or is that code enough to receive a notification?

    CloudPush.addEventListener(‘callback’, function (evt) {
    alert(evt.payload);
    });
    CloudPush.addEventListener(‘trayClickLaunchedApp’, function (evt) {
    Ti.API.info(‘Tray Click Launched App (app was not running)’);
    });
    CloudPush.addEventListener(‘trayClickFocusedApp’, function (evt) {
    Ti.API.info(‘Tray Click Focused App (app was already running)’);
    });

    Coz if its, I’m out of luck.

  • Josh Jensen Post author

    I am glad getting Google play installed worked for you. As far as the event handler, I have my callback listener inside my on success function.

    https://gist.github.com/joshjensen/90d0cb4edadb92ef57bb

    The Gist above is working in production now. Hopefully it will help.

    -Josh

  • Djamel

    Can we use gcm without acs ?

    I we use ACS (as i see, we are obliged to use acs properties in tiapp.xml) . are we limted with the number of push we can send (if we use third parti..) ?

  • Yogesh Mittal

    For some reason, I am getting 2 push notification, one empty and the other with the actual content. I am not sure, where am I handling them in a wrong way.

  • Arley Andrada Maria

    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)

  • Krish

    Hi Josh,
    Thank you for the wonderful tutorial.

    Regret to say though that im unable to get it to work. On receipt of the push notification, the app crashes.

    Request you to please help me with this.

    Logs listed below –

    E/TiApplication(9474): (main) [27233,59667] Sending event: exception on thread: main msg:java.lang.NoSuchMethodError: org.appcelerator.titanium.TiApplication.isCurrentActivityInForeground; Titanium 3.1.0,2013/04/15 18:46,57634ef

    E/TiApplication(9474): java.lang.NoSuchMethodError: org.appcelerator.titanium.TiApplication.isCurrentActivityInForeground

    E/TiApplication(9474): at ti.cloudpush.CloudpushModuleGeneric.receivePayload(CloudpushModuleGeneric.java:81)

    E/TiApplication(9474): at ti.cloudpush.GCMReceiver.onReceive(GCMReceiver.java:26) E/TiApplication(9474): at android.app.ActivityThread.handleReceiver(ActivityThread.java:2280)

    E/TiApplication(9474): at android.app.ActivityThread.access$1600(ActivityThread.java:143) E/TiApplication(9474): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1317)

    E/TiApplication(9474): at android.os.Handler.dispatchMessage(Handler.java:99)

    E/TiApplication(9474): at android.os.Looper.loop(Looper.java:137)

    E/TiApplication(9474): at android.app.ActivityThread.main(ActivityThread.java:4950)

    E/TiApplication(9474): at java.lang.reflect.Method.invokeNative(Native Method)

    E/TiApplication(9474): at java.lang.reflect.Method.invoke(Method.java:511)

    E/TiApplication(9474): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1004)

    E/TiApplication(9474): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:771) E/TiApplication(9474): at dalvik.system.NativeStart.main(Native Method)

  • Aparna

    Thanku for the post.It helped me alot.

  • Anushu

    When I’m adding ti.cloudpush module, I’m unable to compile my application. Im getting Application Installer abnormal process termination error.
    I have tested in SDK version 3.2.2, 3.2.3.
    Which version is supported for ti.cloudpush module? Please help me out.

  • omi surya

    Hi , I have follwed your tutorial , i got the device token id and also subscribed, i am facing two problems,

    1) only the development section in ACS console Shows 1 android device subscribed, nothing is shown in Production console it says 0 android device subscribed

    2) when i send GCM notification from the Development console it shows up in log as successfully send, but donot receive it on the device,(i have verified the device token both are same with the one registered with acs)

  • JAYESH

    VERY GOOD ONE …. REALLY LIKE

  • Vinicius Oliveira

    I have just a problem with ti.cloudpush
    Works when app is open or in background on android.

    But when is app is closed, and I tap in notification, the app open
    but the callback don’t execute.