The basics of sending a message are really quite simple; all we need to do is send a well formed HTTPS request to https://android.apis.google.com/c2dm/send and pass along the registration ID of the device that we wish to send a message to, our authentication token, and the payload of the message itself. So just like we did before when obtaining the authentication token, we start off with the
HttpURLConnection
object:HttpURLConnection connection = null; try { URL url = null; try { url = new URL("https://android.apis.google.com/c2dm/send"); } catch (MalformedURLException e) { // Exception handling } connection = (HttpURLConnection) url.openConnection(); connection.setDoOutput(true); connection.setUseCaches(false); connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); connection.setRequestProperty("Authorization", "GoogleLogin auth=" + token); } catch (Exception e) { // Exception handling }Once again, I'm using
HttpURLConnection
as my application is going to be hosted using Google App Engine, and HttpsURLConnection
is simply not allowed. Also, notice how we need to send our authentication token; it needs to be prefixed with the String "GoogleLogin auth=
".Next up, we need to set the parameters that we're going to pass to the C2DM service. For this, we need to include the registration id that the device received from the C2DM service when the device first registered itself (yes, that means the device will also need to pass that id to us as soon as it gets it). We also need to specify our message payload in the form of key-value pairs, with the key prefixed with "
data.
":StringBuilder sb = new StringBuilder(); addEncodedParameter(sb, "registration_id", deviceRegistrationId); addEncodedParameter(sb, "collapse_key", "goobr.blogspot.com.someKey"); addEncodedParameter(sb, "data.payload1", "payload1 message data"); addEncodedParameter(sb, "data.payload2", "payload2 message data"); addEncodedParameter(sb, "data.anotherPayload", "even more message data"); String data = sb.toString();One thing to note is the
collapse_key
parameter. This is simply a required key that will be used to collapse our messages so that if the device is switched off, it won't get a ton of messages when it comes online again...in this situation, only the last message will actually be received by the device (although C2DM makes no guarantee on message order, so it might not actually be the last message that was sent). And just like before, we're using the same addEncodedParameter()
method to format our parameters into a String:public static void addEncodedParameter(StringBuilder sb, String name, String value) { if (sb.length() > 0) { sb.append("&"); } try { sb.append(URLEncoder.encode(name, "UTF-8")); sb.append("="); sb.append(URLEncoder.encode(value, "UTF-8")); } catch (UnsupportedEncodingException e) { // Exception handling } }Finally, we come to the actual sending of the message itself, and processing the response:
try { DataOutputStream stream = new DataOutputStream(connection.getOutputStream()); stream.writeBytes(data); stream.flush(); stream.close(); switch (connection.getResponseCode()) { case 200: // Success, but check for errors in the body break; case 503: // Service unavailable break; case 401: // Invalid authentication token break; } } catch (IOException e) { // Exception handling }If the service is unavailable, then we need to check for (and honor) any
Retry-After
header in the response, and failing that, we need to implement exponential backoff (that is, keep doubling our wait time before trying the request again). Also, even if we get a 200 response code, that doesn't mean that the message went through. We still need to check the response body for any of the following:- Error=QuotaExceeded
- Error=DeviceQuotaExceeded
- Error=InvalidRegistration
- Error=NotRegistered
- Error=MessageTooBig
- Error=MissingCollapseKey
InvalidRegistration
and NotRegistered
errors, we need to make sure that we stop sending messages to this registration id as the device has either unregistered itself, uninstalled our Android app (uh-oh!), or simply switched off notifications. And for the final two errors, well we simply need to look at our code and make sure that:- the message is 1024 bytes in size or less and
- we include a
collapse_key
in the request
Update-Client-Auth
header from time to time, and all this means is that the authentication token that was used to send the message is about to expire, and so the C2DM framework has generated a new one that we should start using instead.And that's all there is to it really. See...told you it was really quite simple! Have fun sending push notifications to your Android apps. :)
No comments:
Post a Comment