How to handle GCM's canonical registration IDs

This article is already obsolete, Google discontinued their service. Use Firebase by Google.

If you have an Android app which requires to receive some sort of push notification coming from a server, you have probably already met GCM.

To use GCM you need a server which will send the notifications and a client which will receive them. The client must save its registration_id in a place accessible to the server (eg. server's database).

DISCLAIMER In this post I will not describe the process of acquiring such ID.

Let's say you have a table in your MySQL Database called notifications. Table's schema looks like this:

CREATE TABLE `notifications` (
    `id` int(11) NOT NULL AUTO_INCREMENT,
    `user_id` int(11) NOT NULL,
    `reg_id` text NOT NULL
    PRIMARY KEY(`id`),
    KEY `` (`user_id`)

There you have relation between users and their device registration ids.

Google's Cloud Messaging service generates registration ids to every device as explained:

A Registration ID is an identifier assigned by GCM to a single instance of a single application installed on an Android device. The device is assigned this identifier when it registers to Google Cloud Messaging. The GCM documentation doesn't sprecify what information is encoded in this identifier.

In some older Android versions (pre-4.0.4), a Google account is required to register to GCM.

If multiple users use the same app on the same device, they will be have the same registration ID, since GCM doesn't care about which user logs-in to the app. It's up to your server to determine which user is currently logged in to your app in a certain device, and based on that knowledge to deliver only relevant GCM messages to that device.

Source: What is GCM Registration ID@StackOverflow

After having a table created for the registration ids (which is related to our "imaginary" users table), let's say that our Android Client makes a request with its acquired registration id and the user's id. We will get this ID and query our database to check whether we already have it or not:

SELECT * FROM notifications WHERE reg_id = 'REG_ID_ANDROID_SENT' AND user_id = 1 LIMIT 1

There are several cases that will occur:

  • There's a record for this registration ID, but it doesn't belong to this user (so, it's either someone else using this device or the client made a new account) - We have to update our existing record for this.
  • There is no record for this user and this registration id - We have to create a record for this data.
  • There's a record for this user, but it doesn't match the registration ID (probably, the user used another device - tablet, another smartphone, etc...) - We have to create a new record with this data.

The first case is easy to handle. Updating the record will "unlink" the previous user from this device. In most cases no further actions are required.

The second one is a bit tricky. It can be split in two:

  • It is a new user with registration ID you have never received;
  • It is a new user with a device which has an updated version of your app (which means that you might already have this device ID)

So to check which is the case we will send a "dummy" notification through GCM.

It is really important to handle these "dummy" notifications well in your android app, because they must not trigger any action on the user's device.

Tip: you might check use the context of the notification in your Android app and choose whether to display it or not.

When sending the notification, Google Cloud Messaging service returns the cannonical IDs in the order notifications were sent.

Below is an example response:

    "multicast_id": 7036866281258904189,
    "success": 1,
    "failure": 0,
    "canonical_ids": 1,
    "results": [
            "registration_id": "CANNONICAL_REGISTRATION_ID",
            "message_id": "0:1415529915241995%64ac3713f9fd7ecd"

The canonical id = 0 means that registration id which your push sever used is OK and not should be replaced by canonical id, i.e. often GCM server will be response canonical_id = 0.
In the example response there's one cannonical id and it means that your server has to replace existing registrtation id on new value which you see in response. This case easy reproduce if user reinstall your client application, but your push server doesn't know about it and GCM server will pass in response new registration id.

So this situation might be handled this way:

  1. Send "dummy" notifications to your user in your requests where you send client's registration ID (usually it's a separate request made after your signin/signup request).
  2. Read the response and check whether gcm returned cannocal_ids > 0.
  3. Loop through results (you must keep the list of registration ids you sent this dummy notification in the same order).
  4. Check if this cannonical id is present in your database. If it's not present add it to the user that received this notification.
  5. Then delete from your notifications table the registration id with the key of the cannonical ID. (that's why it's important to keep your list of regisration IDs in the same order as they were sent)

And the third case has to options:

  • it's a new device of an existing user;
  • it's a new registration_id of the a device that has already been registered;

The first option is handled by creating a new record, but most importantly is that you do the same check as the one described above to exclude the second option.

Deleting old registration IDs is important, because GCM keeps the old ones valid for some period of time. This way it might send the same notification multiple times (depending on how many registration ids you keep and they are still valid to GCM) to a single user, which will annoy your clients (probably).

unsplash-logoGeran de Klerk provided this awesome picture.

Show Comments