Handling Registration Id Changes in Google Cloud Messaging on Android

Handling registration ID changes in Google Cloud Messaging on Android

That's an interesting question.

Google encourage you to switch to the new registration process :

An Android application running on a mobile device registers to receive messages by calling the GoogleCloudMessaging method register(senderID...). This method registers the application for GCM and returns the registration ID. This streamlined approach replaces the previous GCM registration process.

The note that says Google may periodically refresh the registration ID only appears on the page that still shows the old registration process, so it's possible that this note is no longer relevant.

If you want to be safe, you can still use the old registration process. Or you can use the new process, but have in addition the code that handles the com.google.android.c2dm.intent.REGISTRATION intent, in order to make sure you are covered if Google do decide to refresh the registration ID.

That said, I never experienced such a refresh, and even when I did experience a change in the registration ID (usually as a result of sending a notification after un-installing the app and then re-installing it), the old registration ID still worked (resulting in a canonical registration ID sent in the response from Google), so no harm was done.

EDIT (06.06.2013) :

Google changed their Demo App to use the new interface. They refresh the registration ID by setting an expiration date on the value persisted locally by the app. When the app starts, they load their locally stored registration id. If it is "expired" (which in the demo means it was received from GCM over 7 days ago), they call gcm.register(senderID) again.

This doesn't handle the hypothetical scenario in which a registration ID is refreshed by Google for an app that hasn't been launched for a long time. In that case, the app won't be aware of the change, and neither will the 3rd party server.

public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

setContentView(R.layout.main);
mDisplay = (TextView) findViewById(R.id.display);

context = getApplicationContext();
regid = getRegistrationId(context);

if (regid.length() == 0) {
registerBackground();
}
gcm = GoogleCloudMessaging.getInstance(this);
}

/**
* Gets the current registration id for application on GCM service.
* <p>
* If result is empty, the registration has failed.
*
* @return registration id, or empty string if the registration is not
* complete.
*/
private String getRegistrationId(Context context) {
final SharedPreferences prefs = getGCMPreferences(context);
String registrationId = prefs.getString(PROPERTY_REG_ID, "");
if (registrationId.length() == 0) {
Log.v(TAG, "Registration not found.");
return "";
}
// check if app was updated; if so, it must clear registration id to
// avoid a race condition if GCM sends a message
int registeredVersion = prefs.getInt(PROPERTY_APP_VERSION, Integer.MIN_VALUE);
int currentVersion = getAppVersion(context);
if (registeredVersion != currentVersion || isRegistrationExpired()) {
Log.v(TAG, "App version changed or registration expired.");
return "";
}
return registrationId;
}

/**
* Checks if the registration has expired.
*
* <p>To avoid the scenario where the device sends the registration to the
* server but the server loses it, the app developer may choose to re-register
* after REGISTRATION_EXPIRY_TIME_MS.
*
* @return true if the registration has expired.
*/
private boolean isRegistrationExpired() {
final SharedPreferences prefs = getGCMPreferences(context);
// checks if the information is not stale
long expirationTime =
prefs.getLong(PROPERTY_ON_SERVER_EXPIRATION_TIME, -1);
return System.currentTimeMillis() > expirationTime;
}

EDIT (08.14.2013) :

Google changed their Demo App again (two days ago). This time they removed the logic that considers the Registration ID to be expired after 7 days. Now they only refresh the Registration ID when a new version of the app it installed.

EDIT (04.24.2014) :

For the sake of completeness, here are the words of Costin Manolache (taken from here), a Google developer involved in the development of GCM, on the matter :

The 'periodical' refresh never happened, and the registration refresh
is not included in the new GCM library.

The only known cause for registration ID change is the old bug of apps
getting unregistered automatically if they receive a message while
getting upgraded. Until this bug is fixed apps still need to call
register() after upgrade, and so far the registration ID may change in
this case. Calling unregister() explicitly usually changes the
registration ID too.

The suggestion/workaround is to generate your own random identifier,
saved as a shared preference for example. On each app upgrade you can
upload the identifier and the potentially new registration ID. This
may also help tracking and debugging the upgrade and registration
changes on server side.

This explains the current implementation of the official GCM Demo application.
com.google.android.c2dm.intent.REGISTRATION should never be handled when using the GoogleCloudMessaging class to register.

GCM Registration ID changed

I read the 2 reasons over here when you GCM Registration Id might change:

  1. You’ll need to re-register every device each time you update your
    app.
  2. You’ll also need to re-register a device if the version of Android it’s running has been updated

P.S: The below old answer's reference has been removed from Google's page, so might not be valid anymore

If you see the second point under the heading Enable GCM on Architectural Overview page, it says:

Note that Google may periodically refresh the registration ID, so you
should design your Android application with the understanding that the
com.google.android.c2dm.intent.REGISTRATION intent may be called
multiple times. Your Android application needs to be able to respond
accordingly.

So, for handling that you should have a Broadcast Listener which could handle com.google.android.c2dm.intent.REGISTRATION intent, which Google send to the app when it has to refresh the registration ID. The broadcast receiver will have the onReceive method with an Intent. From the intent you can get the Bundle using which you can extract the new registration ID from Google. You can save that and send it to the 3rd part server to replace your previous registered ID for that user.

Also you may see this answer on the question In GoogleCloudMessaging API, how to handle the renewal or expiration of registration ID?.

Discussion on Should applications call gcm.register() every seven days to ensure valid registration IDs? question might also be of some use.

Hope this helps you understand how to handle it.

Google Cloud Messaging registration id expiration

I am trying to understand when the registration id expires

GCM server usually refreshes(So your old registration id is expired) the registration ids. When exactly this happens is not documented anywhere. But you will be notified when this happens.

How are we notified?

When you send a notification to a registration id which is expired,
for the 1st time the message(notification) will be delivered but you
will get a new registration id with the name canonical id. Which mean,
the registration id you sent the message to has been changed to this
canonical id, so change it on your server side as well
.


If Google decides to refresh the ID and my server is till sending the
message to the old ID I dont think the message will get sent

Like I said, it will be sent for the 1st time, even after expiry.


Also the same post says that the id would get refreshed when the app
version changes

I don't think this happens for sure. But even if it happens(registration id changes) its the same scenario as explained above, so all you need is to take care of the canonical id.

EDIT

$result = curl_exec($ch);
$result = json_decode($result);
$canonical_ids_count = $result->canonical_ids;
if($canonical_ids_count){
//update your DB by replacing the registration id with
//the canonical id(new registration id)
}

Does an Android GCM device id ever change?

yes it is possible for the ID to change. If you take a look at the tutorial in the SDK, every time the app is updated to a new version it will go and get a new ID because the previous ID is not guaranteed to work.

specifically take a look at this page

http://developer.android.com/google/gcm/client.html

 Check if app was updated; if so, it must clear the registration ID
since the existing regID is not guaranteed to work with the new
app version.

Keeping app GCM registration ID valid robustly during automatic updates

What about below solution:

Create a BroadcastReceiver for intent ACTION_PACKAGE_REPLACED. You will receive this intent when a new version of the package gets installed. Once you get this intent you can re-register to GCM for new registration Id.

Broadcast Action: A new version of an application package has been installed, replacing an existing version that was previously installed. The data contains the name of the package.

Google Cloud Messaging registration not returning registration_id

I have not done anything with the HandleRegistration method yet
because I have not gotten the registration process working yet.

HandleRegistration is called when your app receives the registration response from GCM.

Therefore you are supposed to get the registration ID in HandleRegistration, so I'm not sure where you put the string registrationId = intent.GetStringExtra("registration_id"); line, but you probably put it in the wrong place.

How to handle GCM changing the registration Id?

The old reg id continues to work for a while but Google send out a new one to be used in future in the canonical_id field of the response.



Related Topics



Leave a reply



Submit