Introduction

Having recently written a library to unify the sending of push messages for Android devices with GCM (Google Cloud Messaging for Android) and iOS devices with APNs (Apple Push Notification Service), I have gained a valuable insight on the technical differences between how push messaging works identical and differently between the two platforms.

In my opinion, there are more differences than similarities between them, so let’s start with what is the same for Android and iOS push messages:

Similarities between Android and iOS push messages

Both Android and iOS requires the device to contact their respective push message provider (GCM or APNs) to receive a special string (which I will call the identifier), that uniquely identifies a specific app on a specific device. In GCM this is called the device ID, while APNs calls it a device token. It is the app’s responsibilty to receive this identifier from the provider and send it to your application server, so your app can receive push messages from your application server.

Both platforms allow for sending messages from one application server to multiple devices, and for multiple application servers to send to the same device.

Lastly, both platforms allow for an arbitrary JSON object to be sent from your application server to the device, though the maximum allowed size of this object differs (more on that later).

Differences between Android and iOS push messages

The format of the identifier is different: APNs’ device token is always a 64-byte hex-string, while I’m not so sure about GCM’s device ID (As an example, I got a 183-byte string which seemed to follow the regex pattern [a-zA-Z0-9_\-] (letters, numbers, underscores and dashes).

Push messages sent to GCM always returns a reply to the application server informing whether or not the delivery of the message to GCM was successful, and this reply can tell the application server if a device ID has changed or if it has become invalid and can no longer receive push messages. With APNs, you have to periodically connect to a APNs feedback server, that will tell you if any device tokens used previously have become invalid.

Note that none of the providers can or will tell you if the message actually got delivered to the device, they merely tell you whether or not the message was accepted for delivery. The primary reason for this is that a device may be unavailable (e.g. turned off, no network coverage) and the provider then stores the message for later delivery up to a maximum timeperiod (APNs does not inform of this timeperiod, while for GCM it is 4 weeks – in fact you can choose a time-to-live for GCM messages anywhere for 0 seconds to 4 weeks).

And now that we are on the subject of delivery, GCM has quite an advantage over APNs: APNs only stores one unsent message – the most recent: If you send another message to a device that already has a queued message on APNs, the queued message is discarded in favor of the newer. GCM supports this behaviour through the use of collapse keys, but it is not the default behaviour. GCM’s default is attempting to deliver every accepted message.

Differences in the contents of the push messages

The raw contents and interpretations of the push messages are probably the biggest differences between the GCM and APNs:

Where GCM simply passes raw JSON data to a background service from your app, free for the app to process whether it is in the foreground, background or not even started. You can choose to ignore the message, post a notification in the notification bar, trigger a synchronization action, display a dialog (though frowned upon if your app isn’t in the foreground) or something entirely different. It is totally up to you.

APNs makes up for iOS’ limited support for background services in the following way: You can specify an alert dialog (possibly localized with format arguments) to pop up to tell the user that something has happened in your app. Furthermore you can play an optional sound from your app and put a badge on your app’s icon (The number in the red circle in the top right corner of the icon). This is all done by iOS. You don’t have to do any programming on the app side for this. This is default behaviour if the app isn’t in the foreground. If it is in the foreground, you receive the parameters for the alert, badge and sound in your code along with an arbitrary JSON payload, where you can do whatever you want with it.

Notice, however, that there is limitations on the size of the payload in the messages. For GCM the payload is limited to 4 KB (4096 bytes), while APNs only allows 256 bytes(!) for payload. Also, with APNs, the alert, badge and sound parameters are part of these 256 bytes, so there isn’t much space for additional data: An alert with format parameters can easily take up 75-100 bytes, so you have to be conservative with the data that you pass along. It is better to notify your app that something has changed than to send along the change in the push message (which is practically impossible for real life data)

Conclusion

These are, in my opinion, the most important differences and similarities between Google Cloud Messaging for Android and Apple Push Notification Service.

Though I am heavily biased in favor of the Android platform, this is not a bashing of Apple’s push service. It is intended to give an overview of the differences, so you get a better understanding of how to implement your cross-platform push message solution