Pushing messages + Android = C2DM
Written by José Rozanec
On one of our current projects we send push notifications to Android and iOS devices. A basic “happy path” implementation is quite simple. However, we faced some challenges around proper error handling, recovery, retries, and quota handling. Here is what we learned in the process.
C2DM is a Google service that allows you to push messages from servers to mobile apps. The service is free but requires a registration process where you need to request a quota. Google asks you to estimate the total number messages per day and how many messages you will be sending at peak, via C2DM. Quota limits are soft.
The service is not designed to send lots of data via messages, but rather to notify the client that new data is available on the server. Although it gives no guarantees about delivering the messages, it does not require a running Android app to get them: Google stores them until the device gets online and receives them. This service requires devices with Android 2.2 or higher and the Market app installed.
Google provides a quick architectural overview, where they specify the key terms and concepts used to understand how C2DM works.
Below are some of terms the C2DM docs define:
- senderId: an email account registered at C2DM used to authenticate against C2DM service and push messages to it.
- authentication token: provided by C2DM to the application server when authenticating. The application server must request a new one when it expires.
- registrationId: an ID issued by C2DM to the Android application that allows it to receive messages. When the app receives a registrationId, is its responsibility to store it locally and send it to the third-party application server. The registrationId is tied to a particular application running on a particular device.
There are three actors in the process:
- C2DM - Google:
- provides a registrationId for an application installed on a specific device.
- receives a POST request from the application server with the registrationId and knows to which device to send the message. Forwards the message to the device.
- authenticates the senderId and gives him an authentication token used when POSTing messages to C2DM.
- 3rd Party Application Server (AS):
- authenticates against C2DM with senderId and password to get an authentication token.
- saves registrationId from the mobile app.
- sends messages to C2DM (via POST requests) identifying them with a registrationId.
- handles errors C2DM reports, removes the registrationId that caused failure.
- Mobile App:
- registers to C2DM asking for a registrationId.
- sends the registrationId to the application server. The mobile app should persist this id since messages will be sent to it even when the app is not running.
- receives C2DM messages from C2DM service.
Here’s a sequence diagram of the basic process. Take into consideration that it does not include application server authentication against C2DM.
Some quick tips.
- The mobile app that consumes C2DM messages fired from the server must have the same base packages declared when registering the senderId at C2DM. The app should also know the senderId from the server.
- The registrationId “lasts until the application explicitly unregisters itself, or until Google refreshes the registration ID for your application.”
- How do we handle the case Google refreshes the registrationId? When Google renews the registrationId it will fire the registration intent at your device. Upon handling the intent, your mobile app should send the new registrationId to your application server (see this thread for details).
- So, the app should persist the registrationId … Yes, should be stored for later use. Ideally, to be sure we call the registration intent just once (the first time), we should check if a registrationId is stored, and if not, fire the intent. After that, the intent handling code should update the registrationId with new registrationId values sent from Google C2DM, if we detect both registrationIds differ.
- What happens if the app gets uninstalled and does not unregister from C2DM? Will we be sending messages for a non-existent app? No. If the device receives a message and it detects that the app is not installed it’ll send an automatic unregister intent (see this thread for details). Then C2DM will return an error code when it receives POST requests for that registrationId. We should handle that error code and remove the registrationId at the application server database.
Some useful links
- Google Projects for Android: C2DM: general c2dm documentation and some code snippets as well as some sample projects.