27 May 2010

Android Cloud To Device Messaging

[This post is by Wei Huang, who helped implement this feature. — Tim Bray]

In the just-launched Android 2.2, we’ve added a new service to help developers send data from servers to their applications on Android phones. Android Cloud to Device Messaging (C2DM) makes it easier for mobile applications to sync data with servers.

Most of the useful applications on your mobile phone use the Internet to keep users connected. Traditionally, many apps use polling to fetch data periodically. POP mail clients, for example, connect to the server every 15 minutes or so. Polling is fairly easy to implement, and works well in many situations. It’s tricky, though, to select the frequency: Poll too often, you may not see any new data, and create unnecessary stress on the server and network. Poll too rarely and the data on the device may become stale. Polling is especially problematic on mobile devices, because it consumes precious network bandwidth and battery life.

Having the server push messages to the client asynchronously may be a superior choice for getting the latest data to your applications, resulting in fresher data and more efficient use of the network and your battery. However, it’s also tricky to implement a good push solution, and it isn’t free as there is some overhead in maintaining the required connection. On a mobile device like an Android phone, implementing applications to receive these messages is tricky; you have to worry about patchy network coverage and zombie connections created when the wireless carrier’s routers time out connections that are idle for too long.

Many of the Google applications on Android already use push to keep their data fresh, for example Gmail, Contacts, and Calendar. Starting with Android 2.2, C2DM allows third-party developers to use the same service the Google apps do.

Here are a few basic things to know about C2DM:

  • It requires Android 2.2; C2DM uses Google services which are present on any device running the Android Market.

  • It uses existing connections for Google services. This requires the users to sign into their Google account on Android.

  • It allows 3rd party servers to send lightweight data messages to their apps. The C2DM service is not designed for pushing a lot of user content; rather it should be used like a “tickle”, to tell the app that there is new data on the server, so the app can fetch it.

  • An application doesn’t need to be running to receive data messages. The system will wake up the app via an Intent broadcast when the the data message arrives, so long as the app is set up with the proper Intent Receiver and permissions.

  • No user interface is required for receiving the data messages. The app can post a notification (or display other UI) if it desires.

It’s easy to use the C2DM API. Here is how it works:

  • To enable C2DM, an application on the device registers with Google and get a registration ID, and sends the ID to its server.

  • When the server needs to push a message to the app on the device, it posts the message via HTTP to Google’s C2DM servers.

  • The C2DM servers route the message to the device, and an Intent broadcast is sent to the app.

  • The app is woken up to process the message in its Intent Receiver.

  • The app can unregister with C2DM when the user no longer wants messages to be pushed to it.

That’s about it! All you need is a server that knows to talk HTTP, and an Android app that knows how to use the Intent APIs. Below are some code samples:

// Use the Intent API to get a registration ID
// Registration ID is compartmentalized per app/device
Intent regIntent = new Intent(
        "com.google.android.c2dm.intent.REGISTER");
// Identify your app
regIntent.putExtra("app",
        PendingIntent.getBroadcast(this /* your activity */, 
            0, new Intent(), 0);
// Identify role account server will use to send
regIntent.putExtra("sender", emailOfSender);
// Start the registration process
startService(regIntent);

The registration ID will be delivered back to your app via an intent broadcast with the Intent Action com.google.android.c2dm.intent.REGISTRATION. Here is a code sample to receive the registration ID.

// Registration ID received via an Intent
public void onReceive(Context context, Intent intent) {
  String action = intent.getAction();
  if (“com.google.android.c2dm.intent.REGISTRATION”.equals(action)) {
    handleRegistration(context, intent);
  }
}

public void handleRegistration(Context context, Intent intent) {
  String id = intent.getExtra(“registration_id”);
  if ((intent.getExtra(“error”) != null) {
    // Registration failed.  Try again later, with backoff.
  } else if (id != null) {
    // Send the registration ID to the app’s server.
    // Be sure to do this in a separate thread.
  }
}

On the server side, your server needs to get a ClientLogin Auth token in order to talk to the C2DM servers. When it wants to push a message to the device, it can send an authenticated http POST with:

  • Authorization: GoogleLogin auth=<auth token>

  • URL encoded parameters including the registration id, the data key/value pairs, a “collapse key” used for overriding old messages with the same key on the Google C2DM servers, and a few other optional params.

When you use the C2DM service, you no longer need to worry about dealing with flaky mobile data connections, or when the user isn’t connected to the internet (i.e. Airplane mode). C2DM keeps the messages in the server store, and delivers them when the device comes back online. Basically, you can leave all the hard work of designing a robust push service to Google. Your application can take advantage of push infrastructure we’ve already built and tested, and stay more connected to the internet. Best of all, you won’t ruin the users’ battery life.

Information about how to build C2DM enabled applications on Android is online at the code lab, and more will be coming as we approach general release.