Concept of Google Cloud Messaging / Cloud 2 Device Messaging.
By
H.M.Pranav Kumar,
The Google cloud messaging is the concept introduced with the purpose of,
1) Asynchronous messaging from the application server.
2) To avoid polling of the client to save the battery power.
3) To make handling and routing of messages to different devices easier.
GCM / C2DM is a concept in which three parties are involved. The parties are,
1) Application server.
2) Google cloud server.
3) Android app / Client.
Application Server:
Application server is the business server in which the actual logic and the data is stored and to which the client interacts for the new data and requests for data and other processing needs.
Google cloud server is based on cloud and it enables the GCM. It contains all the API needed for the application server to interact with it and for the client registration. This stores the references of the devices and it takes care of the routing and security of the data.
This can be any kind of app that obtains the data from the server in the real time. The examples like whatsapp, hike, weather reporting apps etc.,
1) The client devices are mobiles or tablets that are low powered. So in order to optimize the power consumption, the apps should not be polled to the server frequently for new data. This drawback introduced the concept of pushing the new data from the server using the GCM /C2DM.
2) It’s hard for the application server for noting down all the device ids and the references that are related to the mobile device. Here in this case the google cloud server keeps track off the devices and hence it’s not the work of the application server.
3) No need for the app to continuously listen for the new data from the application server. When available the availability is conveyed through the GCM and then the app awakens to communicate with the application server.
4) Routing of data to the various devices are also taken care by the GCM / C2DM.
Steps for working in GCM by a developer:
a) Application Server Side:
1) Set up the post request from the application server to get authentication token from the GCM.
URL: https://www.google.com/accounts/ClientLogin
DATA: builder.append("Email=").append(email);
builder.append("&Passwd=").append(password);
builder.append("&accountType=GOOGLE");
builder.append("&source=MyLittleExample");
builder.append("&service=ac2dm");
Header Type: con.setRequestMethod("POST");
con.setRequestProperty("Content-Type",
"application/x-www-form-urlencoded");
con.setRequestProperty("Content-Length", Integer.toString(data.length));
2) Set the post request as given below to send the message.
URL: https://android.clients.google.com/c2dm/send
DATA: StringBuilder postDataBuilder = new StringBuilder();
postDataBuilder.append(PARAM_REGISTRATION_ID).append("=")
.append(registrationId);
postDataBuilder.append("&").append(PARAM_COLLAPSE_KEY).append("=")
.append("0");
postDataBuilder.append("&").append("data.payload").append("=")
.append(URLEncoder.encode(message, UTF8));
Header Type: conn.setRequestMethod("POST");
conn.setRequestProperty("Content-Type","application/x-www-form-urlencoded;charset=UTF-8");
conn.setRequestProperty("Content-Length",
Integer.toString(postData.length));
conn.setRequestProperty("Authorization","GoogleLogin auth="+ auth_token);
i. NOTE: Create the database to store the registration id of the devices that
communicate with application server.
b) Client Side:
1) Fire the intent “com.google.android.c2dm.intent.REGISTER” from the code for registration.
2) Create the broadcast receiver for accepting the receiving intent from the service upon
successful completion with action “com.google.android.c2dm.intent.REGISTRATION”.
3) Get the registration id (TAG Name: “registration_id”) from intent and device id from
device and send to application server.
4) Create the broadcast receiver for accepting the messages from the GCM server with the
action string “com.google.android.c2dm.intent.RECEIVE”.
5) Data can be fetched from the receiving intent using the tag name “Payload”.
6) Create the Notification manager instance and notify the message to the notification bar
with or without the pending intent.
7) Register the receivers in the android manifest.
8) Implement the permission to use the internet.
9) Create the application level custom permission with signature level authentication to allow
only the apps of same signature to access or to read the push notification.
Phases Involved in the GCM:
1) Application server Registration:
The application server sends the post request to the GCM server for all needs like
registration, sending the data etc. The application server sends the following details in the post
request as shown in the code below to get the authentication token.
public static String getToken(String email, String password)
throws IOException {
// create the post data
// Requires a field with the email and the password
StringBuilder builder = new StringBuilder();
builder.append("Email=").append(email);
builder.append("&Passwd=").append(password);
builder.append("&accountType=GOOGLE");
builder.append("&source=MyLittleExample");
builder.append("&service=ac2dm");
// Setup the Http Post
byte[] data = builder.toString().getBytes();
URL url = new URL("https://www.google.com/accounts/ClientLogin");
HttpURLConnection con = (HttpURLConnection) url.openConnection();
con.setUseCaches(false);
con.setDoOutput(true);
con.setRequestMethod("POST");
con.setRequestProperty("Content-Type",
"application/x-www-form-urlencoded");
con.setRequestProperty("Content-Length", Integer.toString(data.length));
// Issue the HTTP POST request
OutputStream output = con.getOutputStream();
output.write(data);
output.close();
// read the response
BufferedReader reader = new BufferedReader(new
InputStreamReader(con.getInputStream()));
String line = null;
String auth_key = null;
while ((line = reader.readLine()) != null) {
if (line.startsWith("Auth=")) {
auth_key = line.substring(5);
}
}
// Finally get the authentication token
// To something useful with it
return auth_key;
}
The above code can be implemented in any sever side scripting languages.
2) Registering the client with GCM.
Next step is to register the client for the GCM. For registering, we need to fire the
“com.google.android.c2dm.intent.REGISTER”, which in turn trigger a service that will
communicate with the GCM. Along with the intent the following data should be sent.
intent.putExtra("app",PendingIntent.getBroadcast(this, 0, new
Intent(), 0));
intent.putExtra("sender", "youruser@gmail.com");
startService(intent);
The complete code can be seen as below,
public void register(View view) {
Intent intent = new
Intent("com.google.android.c2dm.intent.REGISTER");
intent.putExtra("app",PendingIntent.getBroadcast(this, 0, new
Intent(), 0));
intent.putExtra("sender",
"youruser@gmail.com");startService(intent);
}
NOTE: The email sent should be same as that of the email that is used on the application server
side for obtaining the authentication token.
After registering with the GCM successfully by the service that is running, it returns the
intent with the registration id. To receive that intent, we need to create the Broadcast receiver that
listens to “com.google.android.c2dm.intent.REGISTRATION”.
public class C2DMRegistrationReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
Log.w("C2DM", "Registration Receiver called");
if ("com.google.android.c2dm.intent.REGISTRATION".equals(action)) {
Log.w("C2DM", "Received registration ID");
final String registrationId = intent
.getStringExtra("registration_id");
String error = intent.getStringExtra("error");
Log.d("C2DM", "dmControl: registrationId = " + registrationId
+ ", error = " + error);
// TODO Send this to my application server } }}
3) Acknowledging the application server with registration id:
Once the registration id is obtained from the GCM, we need to send registration id and the
device id to the application server and it is stored in the devices list of the database in the server.
public void sendRegistrationIdToServer(String deviceId, String
registrationId) {
Log.d("C2DM", "Sending registration ID to my application server");
HttpClient client = new DefaultHttpClient();
HttpPost post = new HttpPost("http://your_url/register");
try {
List<NameValuePair> nameValuePairs = new
ArrayList<NameValuePair>(1);
// Get the deviceID
nameValuePairs.add(new BasicNameValuePair("deviceid", deviceId));
nameValuePairs.add(new BasicNameValuePair("registrationid",
registrationId));
post.setEntity(new UrlEncodedFormEntity(nameValuePairs));
HttpResponse response = client.execute(post);
BufferedReader rd =
new BufferedReader(new
InputStreamReader(response.getEntity().getContent()));
String line = "";
while ((line = rd.readLine()) != null) {
Log.e("HttpResponse", line);
}
} catch (IOException e) {
e.printStackTrace(); }}
4) Registering the receiver for message on client side.
Similar to the registration receiver, we need one more receiver for receiving the messages pushed from the GCM. So create a broadcast receiver and register it for “com.google.android.c2dm.intent.RECEIVE”. Once the message is received the service creates the
intent of the above action string with the data or message in it with the tag name “Payload”.
import android.content.Context;
import android.content.Intent;
import android.util.Log;
public class C2DMMessageReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
Log.w("C2DM", "Message Receiver called");
if ("com.google.android.c2dm.intent.RECEIVE".equals(action)) {
Log.w("C2DM", "Received message");
final String payload = intent.getStringExtra("payload");
Log.d("C2DM", "dmControl: payload = " + payload);
// Send this to my application server
}
}
}
5) Sending the message from server:
Now we can see that the application server is ready to communicate with the GCM and the GCM is ready to communicate it to the device and the device is also ready to receive it. Now code the logic to implement the “Post” request to the following url with the following data to send the message.
URL: https://android.clients.google.com/c2dm/send
Post data: Registration id, collapse key, data or payload(Message)
Example is as shown below,
public class SendMessage {
private final static String AUTH = "authentication";
private static final String UPDATE_CLIENT_AUTH = "Update-Client-Auth";
public static final String PARAM_REGISTRATION_ID = "registration_id";
public static final String PARAM_DELAY_WHILE_IDLE = "delay_while_idle";
public static final String PARAM_COLLAPSE_KEY = "collapse_key";
private static final String UTF8 = "UTF-8";
public static int sendMessage(String auth_token, String registrationId,
String message) throws IOException {
StringBuilder postDataBuilder = new StringBuilder();
postDataBuilder.append(PARAM_REGISTRATION_ID).append("=")
.append(registrationId);
postDataBuilder.append("&").append(PARAM_COLLAPSE_KEY).append("=")
.append("0");
postDataBuilder.append("&").append("data.payload").append("=")
.append(URLEncoder.encode(message, UTF8));
byte[] postData = postDataBuilder.toString().getBytes(UTF8);
// Hit the dm URL.
URL url = new URL("https://android.clients.google.com/c2dm/send");
HttpsURLConnection
.setDefaultHostnameVerifier(new CustomizedHostnameVerifier());
HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
conn.setDoOutput(true);
conn.setUseCaches(false);
conn.setRequestMethod("POST");
conn.setRequestProperty("Content-Type",
"application/x-www-form-urlencoded;charset=UTF-8");
conn.setRequestProperty("Content-Length",
Integer.toString(postData.length));
conn.setRequestProperty("Authorization", "GoogleLogin auth="
+ auth_token);
OutputStream out = conn.getOutputStream();
out.write(postData);
out.close();
int responseCode = conn.getResponseCode();
return responseCode;
}
private static class CustomizedHostnameVerifier implements HostnameVerifier {
public boolean verify(String hostname, SSLSession session) {
return true;
}
}}
The GCM sends the data that is received from the application server to the device once the device is online. If the device is in offline the data will be saved in an asynchronous queue and once connected to the device it sends them.
Comments
Post a Comment