How to implement Push Notifications: Android
This tutorial is for getting started with Android Cloud to Device Messaging (C2DM) on Android. In the iOS world this is known as “push notifications”.
There are many good resources out there for getting started, but all of them, I felt, were lacking in one way or another, which is why I decided to put together this tutorial of my own. A lot of my code and structure is borrowed from other posts that are referenced in the links at the end.
On the iPhone, notifications are easy to implement and include, since iPhone OS 3. However, it’s a little more complex on Android. Additionally, the Google provided “Android Cloud to Device Messaging” is only built into its OS starting from Android 2.2. That said, C2DM is not designed to just send simple messages, they can include any kind of payload and are used for all kinds of updates, not just text alerts:
“Android Cloud to Device Messaging (C2DM) is a service that helps developers send data from servers to their applications on Android devices. The service provides a simple, lightweight mechanism that servers can use to tell mobile applications to contact the server directly, to fetch updated application or user data. The C2DM service handles all aspects of queueing of messages and delivery to the target application running on the target device.”
What if we want to support Android 1.6+? Fact: 1.6 and 2.1 make up 56.8% of deployed versions. We can’t just ignore over half of the Android population. We need an alternative to C2DM.
C2DM Alternatives
- Polling. The application itself will periodically poll your servers to check for new messages. You will need to implement everything from queuing messages to writing the polling code. Alerts are no good if they are delayed due to low polling periods. But the more frequently you poll, the faster your battery is going to die.
- SMS. Android can intercept SMS messages. You could include a payload to tell the app what to do, but then why not just use SMS in the first place?
- Persistent connection. This would solve the problem of periodic polling but would destroy the battery life. Apple’s push notifications work well because there’s only ever 1 service connecting to Apple’s servers. This is also how the C2DM service works. This means you don’t have every app leaving open connections.
Working with C2DM
Google provides detailed documentation and sample projects onhow to implement C2DM in your Android Java project. They also have a good mailing list with Google employees who actually reply in just a few hours. However, like Apple, their documentation is lacking on how to implement the server side aspects – the bit that actually sends the message from you to Google, and then onto the user.
The complex part of Apple’s service is setting up the SSL certificates. This isn’t necessary for Google but they do require a ClientLogin token, which is equally complex:
“With programmatic authorization implemented, your users can log into their Google account and grant access to their Google service data from inside your application. The application then contacts Google with the login data and requests access to a specified Google service. Once Google authorizes access, your application can access the Google service data, allowing the user to create, read, update, or delete service data as needed using your application interface.
Authorization with the ClientLogin API is a step up from the “low-tech” approach, which required applications to include the user’s login name and password in every request to a Google service. With programmatic login, Google issues a token that can be referenced in all subsequent requests.”
Once you have that token you can then communicate with the C2DM service. How this might work in practice with a real app is as follows:
- The user launches your app on their Android device. You call the C2DM registration method.
- After the user has logged in, Google provides a registration ID to uniquely identify the device. You must send that ID to your servers and store it so you can communicate with the user.
- You send a message to the user using their registration ID. This consists of a POST to the Google C2DM service.
- The user’s device receives the message and you handle it.
Step 3 is the server side code that we’re going to deal with here. The other steps are all implemented in Java in the app itself, and are outside the scope of this tutorial.
Sending messages to Google C2DM – ClientLogin authentication
You first need to register to use C2DM. It’s recommended that you set up a separate Google account just for this. If you use a Google Account that is both a Google Account and a Hosted Google Account (through Google Apps) then you may have a conflict. In this case, the Hosted account will always get registered (source).
“You can also try to request “HOSTED” instead of “HOSTED_OR_GOOGLE” in ClientLogin – the hosted account is enabled for C2DM if there are both a hosted and a consumer ( google ) account. If your domain is converted to use the new ‘consumer’ account style – the problem may go away as well, since the old consumer account will be renamed.”
You then need to obtain the ClientLogin token for the account you registered with C2DM. The process is well documented and there are plenty of things you need to handle (like CAPTCHA and expiring tokens) but this Python sample code will get a token for you:
import urllib, urllib2
class ClientLoginTokenFactory():
_token = None
def __init__(self):
self.url = ‘https://www.google.com/accounts/ClientLogin’
self.accountType = ‘GOOGLE’
self.email = ‘example@gmail.com’
self.password = ‘password’
self.source = ‘Domokun’
self.service = ‘ac2dm’
def getToken(self):
if self._token is None:
# Build payload
values = {‘accountType’ : self.accountType,
‘Email’ : self.email,
‘Passwd’ : self.password,
‘source’ : self.source,
‘service’ : self.service}
# Build request
data = urllib.urlencode(values)
request = urllib2.Request(self.url, data)
# Post
response = urllib2.urlopen(request)
responseAsString = response.read()
# Format response
responseAsList = responseAsString.split(‘\n’)
self._token = responseAsList[2].split(‘=’)[1]
return self._token
(Code taken and modified from sample posted here).
You need to replace self.email, self.password and self.source with your own credentials. The self.email and self.password are for the account you signed up to C2DM with and self.source can be anything identifying who you are to Google – see here for details. If you’re using a hosted Google account then you need to change self.accountType too – see here for details.
To execute this code you’d use:
clientAuthFactory = ClientLoginTokenFactory()
clientAuth = clientAuthFactory.getToken()
Sending messages to Google C2DM – cd2m/send
The payload you send to Google has a number of requirements, as detailed in their documentation. You need to specify the registration ID the user’s device has sent you and also provides a collapse key:
“An arbitrary string that is used to collapse a group of like messages when the device is offline, so that only the last message gets sent to the client. This is intended to avoid sending too many messages to the phone when it comes back online. Note that since there is no guarantee of the order in which messages get sent, the “last” message may not actually be the last message sent by the application server.”
You’ll also notice that there is no required “message” field. This is because the payload can contain many “data” fields and it is up to your app to handle them. This might just be a single field called data.message that is displayed by your app, or you could use it to send any other kind of data to update the app. For example, we could use it to send the latest data from a server, upon receiving it, to automatically refresh the values in the app.
This sample Python code will build the request, get your ClientAuth token (using the class posted above) and then send it.
class C2DM():
def __init__(self):
self.url = 'https://android.apis.google.com/c2dm/send'
self.clientAuth = None
self.registrationId = None
self.collapseKey = None
self.data = {}
def sendMessage(self):
if self.registrationId == None or self.collapseKey == None:
return False
clientAuthFactory = ClientLoginTokenFactory()
self.clientAuth = clientAuthFactory.getToken()
# Loop over any data we want to send
for k, v in self.data.iteritems():
self.data['data.' + k] = v
# Build payload
values = {'registration_id' : self.registrationId,
'collapse_key' : self.collapseKey}
# Build request
headers = {'Authorization': 'GoogleLogin auth=' + self.clientAuth}
data = urllib.urlencode(values)
request = urllib2.Request(self.url, data, headers)
# Post
try:
response = urllib2.urlopen(request)
responseAsString = response.read()
return responseAsString
except urllib2.HTTPError, e:
print 'HTTPError ' + str(e)
(Note this code is designed to be used in the same file as the previous sample code. If you separate them it requires import urllib, urllib2)
To use this code you need to call it like so:
sender = C2DM()
sender.registrationId = 'hats'
sender.collapseKey = 1
sender.data = {'message' : 'Hello there', 'hats' : 54}
response = sender.sendMessage()
sender.data takes a Python dictionary, which will be converted to the right format to send to C2DM. Note that the sender.registrationId is not set – it should be the registration ID for the user you want to send to.
What else you need to do
This sample code is useful for development but doesn’t do some things you’ll need for production:
- Error handling – you’ll need to do more advanced handling of any HTTP errors. If the Google service is down it’ll return a 503 HTTP code and a retry value, which you must honor.
- You must queue messages if the service returns a quota error. This needs to use Exponential backoff.
- The ClientLogin code does not handle CAPTCHA or resetting the auth token. See this post for how this might be presented.
Final words
Push notifications on Android are fairly fragmented right now. The Urban Airship solution provided in my upcoming blog post will provide a good solution; but it requires installing a separate 3rd party app – not ideal.
More resources listed here:
- http://code.google.com/android/c2dm/index.html
- http://android-developers.blogspot.com/2010/05/android-cloud-to-device-messaging.html


