Carma Android Integration Guide

Rev pA4.

 

About this document

This document describes how to integrate Carma with google’s push notifications for android.

Change notes:

pA1                        first version

pA2                        changed the URL and payload layout for device registration.

Changed rest URLs from ../devices to ../pushdevices

pA3                        Added send push trigger information

pA4                        updated information on received push variables.

 

 

Contents

About this document. 2

Change notes: 2

How Google Cloud Messaging (GCM) Works. 4

Integration. 5

Before you begin coding. 5

The app code. 5

Carma UI 5

Android App. 5

Google Cloud Messaging (GCM) 5

GCM Overview.. 5

Configuring the Project in Google Developers Console. 5

Configuring your Android Application. 8

Add Google Play Services. 9

Update Manifest. 9

Write the Code. 11

Carma credentials. 11

Registration. 11

Invalidation of a devicetoken. 14

Retrieving information about a contact. 14

Receive Push. 14

Load rich content. 16

Carma Account. 17

Setup App in Carma: 17

Compost Content. 18

Testing and troubleshooting. 18

 

 

 

 

 

How Google Cloud Messaging (GCM) Works

Google’s system considers 3 parties:

  • The client application
  • Google’s GCM servers
  • a 3rd party server, in this case Carma.

When a user installs an application, it must register itself to enable GCM. Once this is done, as soon as you decide to send your users a notification, a succession of actions will be triggered:

  • Carma sends the push notification to google’s GCM servers.
  • These servers relay the message to all your registered mobile applications.
  • Messages are enqueued and stored for devices that are offline.
  • As soon as a device comes back online, GCM servers relay the queued message.
  • The messages are received and presented according to the platform-specific implementation.

 

 

 

Integration

The steps for integration are as follows:

Before you begin coding

  1. The app Is registered with google and is given an appName
  2. The app is registered in carma using the appName and the google Server Key.

The app code

  1. The app requests a token from GCM
  2. The App sends this token to carma along with the appName.
  3. The tokenis stored in carma and associated with the app

Carma UI

  1. A new Campaign is created as a push
  2. The campaign is connected to the registered App.
  3. The campaign is sent to google who will forward it to the registered devices.

Android App

Before you begin you will need to have an android app that you want to send push notifications to.

This push notifications tutorial assumes that Android Studio is used as the IDE, with a target device running Android 4.0.4 or higher.

Google Cloud Messaging (GCM)

GCM is a service provided by Google that helps developers implement push notifications in their applications.  By using GCM, developers are not required to implement their own method for sending data from their server to the client applications.

GCM Overview
Your App server -> GCM -> device running your client application

Both the app server and Android client need to register with GCM and provide information to uniquely identify and authorize them.  Your Android app will need a Sender ID, and your server will need an API key, both of which can be obtained using the Google Developers Console.

Configuring the Project in Google Developers Console

If you haven’t already, create a project in the Google Developers Console.  The project number is the sender ID that you will use to register in your client application.

 

To get an API key, select APIs under APIs & Auth, and find Google Cloud Messaging for Android:

 

Follow the link for Google Cloud Messaging for Android, and click Enable API:

 

Once enabled, select Credentials under APIs & Auth, click Create New Key, and select Server Key:

Configuring your Android Application

 

The next step is to configure your application.  This involves these steps:

  • Import configuration file (which contains the sender ID)
  • Add Google Play Services
  • Update Manifest
  • Import Configuration File

As an alternative to hard coding the sender ID (project number) in your application, you can use Google Developers Console to generate a configuration file, and use the Google Services plugin for Gradle to get that information into your project.  To do so, follow these steps:

Use this link to generate and download the configuration file.  Place the file in your app folder in Android Studio (the same folder that contains your app specific build.gradle file)

Add the Google Services plugin to your project level build.gradle file:

classpath ‘com.google.gms:google-services:1.3.0-beta1’

Apply the plugin by adding this line to your app specific build.gradle file:

apply plugin: ‘com.google.gms.google-services’

Instead of the above steps, you could simply hard code the sender ID into your source code when you register the device with GCM.  This is simpler, however if your application uses other Google services, importing the configuration file may be a benefit in the long run.

Add Google Play Services

GCM requires Google Play Services, so make sure that you have the Google Play services SDK installed.  In Android Studio, open the SDK manager (Tools -> Android -> SDK Manager).  Under SDK Tools, look for Google Play services, and install if necessary.

With the SDK Tools installed, you can add a dependency to your project, for example:

compile ‘com.google.android.gms:play-services-gcm:7.5.0’

Update Manifest

Next step is to update your application’s manifest.  Your application will need certain permissions:

  • permission.INTERNET
  • permission.WAKE_LOCK
  • google.android.c2dm.permission.RECEIVE
  • applicationPackage + .permission.C2D_MESSAGE

The last permission may look a little funny.  This is a special permission that is specific to your app, which you define in your manifest.  If your package name is com.something.app, you would define this permission as follows:

    android:name=“com.something.app.permission.C2D_MESSAGE”
android:protectionLevel=“signature” />

Then declare that you use this permission like this:

<uses-permission android:name=“com.something.app.permission.C2D_MESSAGE” />

 

 

Next, you’ll need to declare a receiver and two services:

A GcmReceiver, with permission com.google.android.c2dm.permission.SEND.  You do not need to write and code for this, it is provided by Google

A Service that extends GcmListenerService.  This is a class that you write that will override onMessageReceived, which handles incoming messages

A Service that extends InstanceIDListenerService.  This is a class that you write that will override onTokenRefresh, which is called when your device’s GCM registration needs to renewed

The relevant portions of the manifest would look something like this:

<uses-permission android:name=“android.permission.INTERNET” />
<uses-permission android:name=“android.permission.WAKE_LOCK” />
<uses-permission android:name=“com.google.android.c2dm.permission.RECEIVE” /> <permission
android:name=“com.something.app.permission.C2D_MESSAGE”
android:protectionLevel=“signature” />

<uses-permission android:name=“com.something.app.permission.C2D_MESSAGE” />  <receiver
android:name=“com.google.android.gms.gcm.GcmReceiver”
android:exported=“true”
android:permission=“com.google.android.c2dm.permission.SEND”>
<intent-filter>
<action android:name=“com.google.android.c2dm.intent.RECEIVE” />
<action android:name=“com.google.android.c2dm.intent.REGISTRATION” />
<category android:name=“com.something.app” />
</intent-filter>
</receiver><service
android:name=“.MyGcmListenerService”
android:exported=“false”>
<intent-filter>
<action android:name=“com.google.android.c2dm.intent.RECEIVE” />
</intent-filter>
</service>
<service
android:name=“.MyInstanceIDListenerService”
android:exported=“false”>
<intent-filter>
<action android:name=“com.google.android.gms.iid.InstanceID” />
</intent-filter>
</service>

 

 

 

 

Write the Code

Carma credentials

In order to interact with Carma you need four pieces if information.

  1. The URL of the server where your account is.
  2. A customerId
  3. username
  4. Password

You can request this information from your account manager or by sending an email to support@compost.se

Registration

We can now begin coding.  The first thing we need to do is register with GCM to get a registration token and provide that to our server.  This token uniquely identifies an Android device, and our server will use it to send messages to that specific device.  The code to register is straightforward:

InstanceID instanceID = InstanceID.getInstance(this);
String token = instanceID.getToken(getString(R.string.gcm_defaultSenderId),
GoogleCloudMessaging.INSTANCE_ID_SCOPE, null);

This token needs to be registered in Carma along with the appId and an originalid of you choosing. The originalid is an identifier or the user in you system. It could be an email address or a primary key of the user in your database. If you do not have an originalid for the current user in your app, you may use the token as originalId.

This is done by issuing a PUT request to:

https:///rest/<customerid>/apps//pushdevices

with a json payload containing at the minimum:

  • deviceToken
  • originalId

NOTE! Even if they are the same both values must be provided.

A minimal version of the payload would look like this:

{

“originalId”: “abcabc123123”,

“deviceInfo”: [{“devicetoken”: “abc123abc123kmlkmlkml”}]

}

 

 

 

 

In this payload you can also add other information about the user that should be transferred to Carma. Below is the full list of available properties.

{

“listId”: 1000000005,

“country”: null,

“originalId”: “abcabc123123”,

“firstName”: “lars”,

“lastName”: “hansson”,

“middleName”: null,

“emailAddress”: “lars@compost.se”,

“title”: null,

“dateOfBirth”: null,

“city”: null,

“zipcode”: null,

“sex”: null,

“mobileNumber”: null,

“optOutDate”: null,

“dateOfInvalidation”: null,

“optOutMobileDate”: null,

“active”: true,

“properties”: {

“food”: “meat”,

“drink”: “tea”

}

,

“deviceInfo”: [

{

“devicetoken”: “abc123abc123kmlkmlkml”,

“manufacturer”: “apple”,

“model”: “iphone 6”,

“osVersion”: “9.2”,

“country”: “Sweden”,

“dateOfInvalidation”: null,

“invalidationType”: 0

}

]

}

The resource uses Basic Auth for authentication and need you to set the Content-Type and Accept headers to “application/json”

The same struct is used to return info on the device, but it is then appended with all devices that is connected to the contact.

The resource uses Basic Auth for authentication and need you to set the Content-Type and Accept headers to “application/json”

The following code can be used for the registration:

private void registerDeviceAndProfile(CarmaUserProfile profile) {
HttpClient client = new DefaultHttpClient();
JSONObject parent = new JSONObject();
JSONArray deviceInfo = new JSONArray();
JSONObject token = new JSONObject();
try {
token.put(“devicetoken”, profile.getToken());
deviceInfo.put(token);
parent.put(“deviceInfo”,deviceInfo);
parent.put(“originalId”, profile.getOriginalId());
parent.put(“emailAddress”,profile.getEmail());
parent.put(“mobileNumber”,profile.getMobile());
} catch (JSONException e) {
e.printStackTrace();
}
final String url = Constants.server + “/rest/” +new Integer(Constants.customerId).toString() + “/apps/”+packageName+“/pushdevices”;
StringEntity se;
try {
se = new StringEntity( parent.toString(),“UTF8”);
se.setContentType(new BasicHeader(HTTP.CONTENT_TYPE, “application/json”));
se.setContentEncoding(“UTF8”);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
return;
}
HttpPut post = new HttpPut(url);
post.setEntity(se);
post.setHeader(“Accept”, “application/json”);
post.setHeader(“Content-Type”, “application/json”);
String base = username + “:” + password;
byte[] data = base.getBytes();
String authString = Base64.encodeToString(data,Base64.DEFAULT);

post.setHeader(“Authorization”,authString);
try {
final HttpResponse response = client.execute(post);
StatusLine line = response.getStatusLine();
final int code = line.getStatusCode();
StringBuilder sb = new StringBuilder();
try {
BufferedReader reader =
new BufferedReader(new InputStreamReader(response.getEntity().getContent()), 65728);
String cline = null;
while ((cline = reader.readLine()) != null) {
sb.append(cline);
}
}
catch (IOException e) { e.printStackTrace(); }
catch (Exception e) { e.printStackTrace(); }
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {

}
}

Invalidation of a devicetoken.

If you want to remove a registration of a devicetoken for an OriginalId you can issue a request to

This is done by issuing a PUT request to:

https:///rest/<customerid>/apps//pushdevices/invalidation

with a json payload containing at the minimum:

  • deviceToken
  • originalId,

{

“deviceInfo”:[{“devicetoken”: “abc123abc123kmlkmlkml_2”}],

“originalId”:”abcabc123123″

}

 

NOTE! Even if the originalId and devicetoken are the same, both values must be provided.

 

Retrieving information about a contact

If you want to retrieve the information connected to a contact you can issu a GET request to

https:///rest/<customerid>/apps//pushdevices/

You will receive the same struct as when you register a device.  It will contain a list of all devices registered on the originalId. If you have imported information by other means i.e, via scheduledimport on the list, this data will also retrieved.

Receive Push

A compost push message contains the following fields:

  • alert – intended to be the line shown next to the icon in the notification
  • info     – intended to be the line shown under the first in the notification
  • url – the url pointing to the actual rich content of the push
  • pushreadurl – call this URL to mark the push as read in Carma.
  • source – will always by “carma”. This should be used to distinguish between push messages that comes from other systems than carma. A game for example might have high-score system in place that will notify a player
  • any other custom name/value pair that you have supplied in the carma UI för the push.

It’s important to remember that it’s up to the application developer to decide how these fields should be used.

Our Android client is now registered with GCM, and our server can begin sending messages to devices running our client using the provided API Server key and GCM registration token.  Messages for our Android application are received by the GcmReceiver that we declared in our Manifest.  This class is provided by Google, so we don’t need to write any code for it.  When a message is received from our app server, the GcmReceiver will start our GcmListenerService.  This is where we write code to process the messages.  Here is a basic example that displays the message as a notification:

public void onMessageReceived(String from, Bundle data) {

String info = data.getString(“info”);
String alert = data.getString(“alert”);

/**The rich media content of the push is never sent as, there are size limitations on a push message. You retrieve it by issuing a GET message on the custom field URL that is a part of every carma Push message.*/    String url = data.getString(“url”);

Log.d(TAG, “From: ” + from);
Log.d(TAG, “Message: ” + message);
Log.d(TAG, “Rich Content URL: ” + url);

    /**
* Production applications would usually process the message here.
* Eg: – Syncing with server.
*     – Store message in local database.
*     – Update UI.
*/

/**
* In some cases it may be useful to show a notification indicating to the user
* that a message was received.
*/
sendNotification(alert,info,url);
}

 

Load rich content

By looking for the extra parameter url when starting the main activity you can retrieve the link to rich content. The code below starts an activity AddWebView with the url as a parameter when a push is received.

protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Bundle extras = getIntent().getExtras();
if ( extras != null) {
String url = extras.getString(“url”);
if (url != null) {
Intent i = new Intent(getBaseContext(), AddWebView.class);
i.putExtra(“url”, url);
startActivity(i);
}
}

 

Below is the code for an AddWebView activity that shows the rich content in a new WebView

/**
* An example full-screen activity that shows and hides the system UI (i.e.
* status bar and navigation/system bar) with user interaction.
*/
public class AddWebView extends Activity {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

//        this.requestWindowFeature(Window.FEATURE_NO_TITLE);
//Remove notification bar
setContentView(R.layout.activity_add_web_view);
Bundle extras = getIntent().getExtras();
String url = extras.getString(“url”);
WebView view = (WebView) findViewById(R.id.add_webview);
WebSettings webSettings = view.getSettings();
webSettings.setJavaScriptEnabled(true);
webSettings.setDomStorageEnabled(true);
webSettings.setSupportMultipleWindows(true);
view.setWebViewClient(new WebViewClient() {
public boolean shouldOverrideUrlLoading(WebView view, String url) {
// do your handling codes here, which url is the requested url
// probably you need to open that url rather than redirect:
view.loadUrl(url);
return false; // then it is not handled by default action
}
});
view.loadUrl(url);
}

}

 

Send transactional trigger

Instead of using the campaign functionality you may also send push messages using Carma’s trigger functionality.

This is done by issuing a PUT request to:

https:///rest/<customerid>/apps//pushdevices/invalidation

with a json payload containing at the minimum:

  • deviceToken
  • originalId,

{

“deviceInfo”:[{“devicetoken”: “abc123abc123kmlkmlkml_2”}],

“originalId”:”abcabc123123″

}

 

NOTE! Even if the originalId and devicetoken are the same, both values must be provided.

If you are storing you contacts on a list other the the apps default list you must also add its id to the payload, i.e.

{

“deviceInfo”:[{“devicetoken”: “abc123abc123kmlkmlkml_2”}],

“originalId”:”abcabc123123″

“listId”:12345

}

 

Carma Account

TO send a push you will need an account in Carma, where you will have received the following information:

  • Username
  • Password
  • Server URL

Setup App in Carma:

 

Click on Account Setting in the left hand menu and then choose Push Apps under Manage

Click Create new and you will see the following dialog where you enter the information

To register your app in carma you will need the name of you app, following the code above that would be

com.something.app

and the API Server key you retrieved from the google developer console

 

 

 

Click Create and you are ready to start sending Push requests to you users.

The Rich content of the Campaign will be available to the push by calling the URL that is received in the url field in the notification.

Compost Content

The content of a push message is not sent in the push itself, but is located at server side where the url in message is pointing. Content is usually a page of html that is generated for the particular device, user by a template of the server side. It could however be XML or other text-based formats as defined by template.

The most common way to handle content is to simply open an webview and pointing it to the url, making it display the page. The developer could however choose to handle it in different ways. Examples would be opening the device browser instead by an intent, downloading the content and parsing it to extract information that is used in the application somehow or passing it to another application.

If you don’t want to fetch the rich content you can mark the push as opened in carma by issuing  a GET request to the pushreadurl.

 

 

 

Testing and troubleshooting

Once you have done integration, perform the following tests.

  • Install the application on a new device
  • Notice that the number of recipients increases for each time you do this. If not, check that the id’s you supply are correct. Check also that the appid you gave when registering the application is the same as the package given in the top of your manifest.
  • If the list does grow, test a simple push while the application is running. If a notification does not show up after a few minutes, make sure that you have given the correct api-key when registering the app in Carma.
  • Once the above works correct, verify that the notifications show up when sending a push even though the application is not running.