2

I'm creating an app which uses Facebook and GCM. A user can use the app on multiple devices, a friend can send him GCM messages using his facebook id.

On my server, I have a table which maps the facebook id to a gcm id. The table does not require the facebook id to be unique, so messages can be sent to multiple devices.

In the docs, it demonstrates the following way to handle errors when sending a message:

if (result.getMessageId() != null) {
 String canonicalRegId = result.getCanonicalRegistrationId();
 if (canonicalRegId != null) {
   //CASE 1
   // same device has more than on registration ID: update database
 }
} else {
 String error = result.getErrorCodeName();
 if (error.equals(Constants.ERROR_NOT_REGISTERED)) {
   // CASE 2
   // application has been removed from device - unregister database
 }
}

In CASE 1, it says to replace a registration id with the canonical registration id. But how do I know what registration id to replace? Say the receiver has 2 devices, I have 2 registration ids to choose from, but no idea which one I should pick.

In CASE 2, a same problem occurs. How do I know which registration id to remove from the database?

EDIT
For clarity, this is the code I'm using at the moment:

List<String> gcmIds = getGCMIds(c, fbId);
if (gcmIds != null && !gcmIds.isEmpty()) {
    Sender sender = new Sender(Params.GOOGLE_API_KEY);
    Message message = new Message.Builder().addData("message", apiMessage.buildJSONString()).build();
    MulticastResult result = sender.send(message, gcmIds, 5);

    List<Result> results = result.getResults();
        /* Do something with the results */

    success = result.getFailure() == 0;
} else {
    success = false;
}
nhaarman
  • 98,571
  • 55
  • 246
  • 278

2 Answers2

3

For Case 1: from the docs:

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.

When sending a message to a list of devices, the list of results will be in the same order. So, you can actually just look up the regID used at the same index as in the results, and replace that registrationID in your dataStore. Remember to keep the canonical ID, as that's the most recently registered one.

For Case 2: Similarly, delete the regID that was at the same index.

For a full sample implementation, take a look at the official demo code for a send call similar to the one you're implementing.

Alexander Lucas
  • 22,171
  • 3
  • 46
  • 43
  • For case 1: So I still have only one regid, not knowing the old regid to replace in my table. For case 2, that would seem a decent solution, thanks! – nhaarman Dec 06 '12 at 21:58
  • Ah, apologies, updated my answer for clarification. Basically the same as case 2, you want to use a local record of message ids and which reg id they were sent to, and use that record to perform a lookup :) – Alexander Lucas Dec 06 '12 at 22:02
  • Ah, ofcourse. But now for the message id, how would I get it before sending? The `Message` class has no id getter. Perhaps I should send the messages not at once, using the `send(Message, String, int)` instead of `send(Message, List, int)`. Then I would know the regid i've sent it to, because that is the only one at that moment. Still seems a bit hacky. – nhaarman Dec 06 '12 at 22:11
2

You might want to take a look at the GCM response format documentation: https://developer.android.com/google/gcm/gcm.html#response

Specifically this part:

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).

And this part:

If registration_id is set, replace the original ID with the new value (canonical ID) in your server database. Note that the original ID is not part of the result, so you need to obtain it from the list of registration_ids passed in the request (using the same index).

So the registration ID that you need to update is located at the same index (in the registration ID array you created for the message) as the canonical ID you found.

Community
  • 1
  • 1
selsine
  • 2,813
  • 2
  • 21
  • 22