How to Get Canonical Id from Gcm

How to get Canonical ID from GCM

The Canonical id is returned in the response when you send a message from your server to google's gcm server.

https://developer.android.com/google/gcm/http.html#response

Interpreting a success response

When a JSON request is successful (HTTP status code 200), the response
body contains a JSON object with the following fields:

Field Description multicast_id Unique ID (number) identifying the
multicast message. success Number of messages that were processed
without an error. failure Number of messages that could not be
processed. canonical_ids Number of results that contain a canonical
registration ID. See Advanced Topics for more discussion of this
topic. results Array of objects representing the status of the
messages processed. The objects are listed in the same order as the
request (i.e., for each registration ID in the request, its result is
listed in the same index in the response) and they can have these
fields: message_id: String representing the message when it was
successfully processed. registration_id: If set, means that GCM
processed the message but it has another canonical registration ID for
that device, so sender should replace the IDs on future requests
(otherwise they might be rejected). This field is never set if there
is an error in the request. error: String describing an error that
occurred while processing the message for that recipient. The possible
values are the same as documented in the above table, plus
"Unavailable" (meaning GCM servers were busy and could not process the
message for that particular recipient, so it could be retried). If the
value of failure and canonical_ids is 0, it's not necessary to parse
the remainder of the response.

Update

Below is some more info on Canonical IDs. Basically, if somehow the device reg id becomes out of sync with what Google thinks it should be, then when your server sends a request with the out-of-sync id, the gcm server will include in it's response , the correct id to be used in the future.

Think about it, the way this works is; your server should have stored the reg id when the device registered with gcm. Your server sends a request to gcm with that id, gcm uses that id to send a message to your device. GCM can't the reg id on your device without telling the server about it. If it did your server would just keep sending the wrong reg id. Instead, gcm tell the server that the reg id it is using for a particular device is bad, your server can then send a message to the device to update its stored reg id to what it should be, and then the device can ack the change in REG IDs. The info below implies there is some time limit as too how long the "bad" id can still be used to send messages. I think the assumption is that it should be long enough for your server to change the device id (via a gcm message using the "bad" id)

Canonical IDs

On the server side, as long as the application is behaving well, everything should work normally. However, if a bug in the application triggers multiple registrations for the same device, it can be hard to reconcile state and you might end up with duplicate messages.

GCM provides a facility called "canonical registration IDs" to easily recover from these situations. A canonical registration ID is defined to be the ID of the last registration requested by your application. This is the ID that the server should use when sending messages to the device.

If later on you try to send a message using a different registration ID, GCM will process the request as usual, but it will include the canonical registration ID in the registration_id field of the response. Make sure to replace the registration ID stored in your server with this canonical ID, as eventually the ID you're using will stop working.

Android using Canonical ID GCM

Yes. You can use canonical IDs to help you more easily recover from your errors. It is the registration token of the last registration requested by the client app. This is the ID that the server should use when sending messages to the device.

If you try to send a message using an old registration token, GCM will process the request as usual, but it will include the canonical ID in the registration_id field of the response. Make sure to replace the registration token stored in your server with this canonical ID, as eventually the old registration token will stop working.

Based from this blog, GCM service returns the cannonical IDs in the order notifications were sent. Here is a sample 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.

Check these related SO questions about Canonical IDs:

  • How to get Canonical ID from GCM
  • Get GCM canonical registration ID without sending a message

GCM canonical id

Eran's answer is correct, though I found it still a bit foggy for me. However, thanks to him I found a solution.

Say this is your response:

{
"multicast_id":xxxxx,
"success":7,
"failure":0,
"canonical_ids":2,
"results":[
{
"message_id":"0:xxx%xxxxx"
},
{
"message_id":"0:xxx%xxxxx"
},
{
"registration_id":"MY_REG_ID_1",
"message_id":"0:xxx%xxxxx"
},
{
"message_id":"0:xxx%xxxxx"
},
{
"message_id":"0:xxx%xxxxx"
},
{
"registration_id":"MY_REG_ID_2",
"message_id":"0:xxx%xxxxx"
},
{
"message_id":"0:xxx%xxxxx"
}
]
}

As you can see 2 of the 7 messages are a duplicate.

This is the way I send messages to the server:

$tokenResult = mysql_query("SELECT reg_ids FROM table_with_regids"); //
$i = 0;
while($row = mysql_fetch_array($tokenResult)) {

$registrationIDs[$i] = $row['reg_ids'];
$i++;
}

from Eran's answer:

Since you get a response from Google for each request you send, you
should know which Registration IDs were sent to Google in the request
that triggered this response. The old Registration ID that you have to
delete is the second Registration ID in that request.

This means that index 2 and 5 of the array $registrationIDs[] should be replaced with MY_REG_ID_1 and MY_REG_ID_2.

Finally check for double values and remove the exact duplicates. The result should be an array with 5 regids (or directly delete that index from your array instead of replacing with MY_REG_ID_#).

CM getting Canonical ID

Here's an example of how the response is parsed by Sender.java in sendNoRetry method :

   try {
BufferedReader reader =
new BufferedReader(new InputStreamReader(conn.getInputStream()));
try {
String line = reader.readLine();

if (line == null || line.equals("")) {
throw new IOException("Received empty response from GCM service.");
}
String[] responseParts = split(line);
String token = responseParts[0];
String value = responseParts[1];
if (token.equals(TOKEN_MESSAGE_ID)) {
Builder builder = new Result.Builder().messageId(value);
// check for canonical registration id
line = reader.readLine();
if (line != null) {
responseParts = split(line);
token = responseParts[0];
value = responseParts[1];
if (token.equals(TOKEN_CANONICAL_REG_ID)) {
builder.canonicalRegistrationId(value);
} else {
logger.warning("Received invalid second line from GCM: " + line);
}
}

Result result = builder.build();
if (logger.isLoggable(Level.FINE)) {
logger.fine("Message created succesfully (" + result + ")");
}
return result;
} else if (token.equals(TOKEN_ERROR)) {
return new Result.Builder().errorCode(value).build();
} else {
throw new IOException("Received invalid response from GCM: " + line);
}
} finally {
reader.close();
}
} finally {
conn.disconnect();
}

As you can see, the canonical registration ID is searched for in the second line of the response, but only if the first line of the response contains message ID.

android GCM get original id of canonical id

As described in the post that you linked to, it's all based on the position in the response list. So when you get the canonical ID you need to update the original registration ID in the same position of your "send list".

So in your example here are the results 4 of which are canonical (0, 3, 4, 5):

[0] {"registration_id":"3","message_id":"m1"},
[1] {"message_id":"m1"},
[2] {"message_id":"m1"},
[3] {"registration_id":"3","message_id":"m1"},
[4] {"registration_id":"3","message_id":"m1"},
[5] {"registration_id":"3","message_id":"m1"}

And here is your "send list":

[0] "1",
[1] "2",
[2] "3",
[3] "4",
[4] "5",
[5] "6"

According to the results you need to update the registration ID's in position 0, 3, 4, 5 to the ID of 3. That means that you will end up with a registration list like the following:

[0] "3",
[1] "2",
[2] "3",
[3] "3",
[4] "3",
[5] "3"

And finally:

[0] "3",
[1] "2",

Also see: https://developer.android.com/google/gcm/adv.html#canonical and https://developer.android.com/google/gcm/gcm.html#response

Handle GCM Canonical Id with Amazon SNS

Amazon SNS will handle token management only if your app is registered with them. Since you have your own database and endpoints, you would have to manage it yourself.

After pushing the message from the server, you would recieve the canonical id in the response.

As per Google's docs,

A canonical registration ID is the registration token of the last
registration requested by the client app .This is the ID that the
server should use when sending messages to the device.

If you try to send a message using an old registration token, GCM will
process the request as usual, but it will include the canonical ID in
the registration_id field of the response. Make sure to replace the
registration token stored in your server with this canonical ID, as
eventually the old registration token will stop working.

It is good practice to update your registration id with the canonical id returned after the push.

Also if your device is receiving duplicate notifications these could help:-

  • It could be due to a bug in the client app triggering multiple registrations for the same device. So make sure the same device is not getting registered many times.

  • Also, if you uninstall the app from device and you try to send a push to that device, you would get a NotRegistered error from GCM server. Then your server should delete the registration token and not use that registration token again to push messages.

P.S. Even if one user has multiple devices, your db mappings should be such that :- each device of the user will have a different registration token and each of the tokens will be mapped to a single user.
Since the tokens are different, receiving the same message pushed on all devices of the user would not be a problem.

Hope this helps! Cheers!

Get GCM canonical registration ID without sending a message

You can specify "dry_run": true option in /send request.

I found that devices do not receive any push notifications with "dry_run": true option, while a server get canonical_ids response.

Here is a sample code in Ruby. You may have to install gcm Gem beforehand.

$ gem install gcm

ask_canonical_ids.rb

require 'gcm'
require 'json'

API_KEY = "YourApiKey"
gcm = GCM.new(API_KEY)

registration_ids = [
'OldRegistrationId',
]

option = { data: { 'message' => 'Hello Gcm!' }, dry_run: true }
response = gcm.send_notification(registration_ids, option)

p response[:canonical_ids]

output of $ ruby ask_canonical_ids.rb (formatted)

[{
:old => "OldRegistrationId",
:new => "NewRegistrationId"
}]

Again, your device will not receive any push notifications.

regarding canonical id's in GCM (google cloud messaging)

  1. 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. If for some reasons your server sends push on not actual registration id GCM server's response will be:

    GCM HTTP status: 200
    GCM response body:

    {
    "multicast_id": 7036866281258904189,
    "success": 1,
    "failure": 0,
    "canonical_ids": 1,
    "results": [
    {
    "registration_id": "APA91bH88lV-u5XNdJoF5p0W2d0F_z_7AM6_cjx1e62s83bvDZYcdU_lkmRaFdnkZ5PPUBdYssfpB2QygMW5V0kTqVpV4atCyKpnBEkVnd_YTY0qr4V9oHSyYpv_HIDGNzpfHyGfXz5fWCKnlnACHr37y1zT91JcrHyUMR6DB15WzwjAE1QtloI",
    "message_id": "0:1415529915241995%64ac3713f9fd7ecd"
    }
    ]
    }

Now, cannonical_ids = 1 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. You can test this situation on my test push server


  1. @mandeep_m91 as to message_id and multicast_id i just suggest you read documentation. In a practise i haven't use this fields yet


Related Topics



Leave a reply



Submit