web-dev-qa-db-fra.com

Gestion des modifications de l'ID d'enregistrement dans Google Cloud Messaging sur Android

Dans la documentation de Google Cloud Messaging, il est indiqué:

L’application Android doit stocker cet identifiant pour une utilisation ultérieure (par exemple, pour vérifier si onCreate () est déjà enregistré). Notez que Google peut actualiser périodiquement l’ID d’enregistrement. votre Android application, étant entendu que l'intention de com.google.Android.c2dm.intent.REGISTRATION peut être appelée plusieurs fois. Votre Android doit être capable de répondre en conséquence.

J'enregistre mon appareil en utilisant le code suivant:

GoogleCloudMessaging gcm = GoogleCloudMessaging.getInstance(context);
String regID = gcm.register(senderID);

La classe GoogleCloudMessaging encapsule le processus d'inscription. Alors, comment dois-je gérer com.google.Android.c2dm.intent.REGISTRATION puisque le traitement est effectué en interne par la classe GoogleCloudMessaging?

77
AndroidDev

C'est une question intéressante.

Google vous encourage à passer au nouveau processus d'inscription:

Une application Android s'exécutant sur un appareil mobile s'enregistre pour recevoir des messages en appelant le registre de méthode GoogleCloudMessaging (senderID ...). Cette méthode enregistre l'application pour GCM et renvoie l'ID d'enregistrement. Cette approche simplifiée remplace le processus d'enregistrement précédent de GCM.

La note portant la mention Google may periodically refresh the registration ID Apparaît uniquement sur la page affichant encore l'ancien processus d'enregistrement. Il est donc possible que cette note ne soit plus pertinente.

Si vous voulez être en sécurité, vous pouvez toujours utiliser l'ancien processus d'inscription. Vous pouvez également utiliser le nouveau processus, mais avoir en plus le code qui gère l'intention com.google.Android.c2dm.intent.REGISTRATION, Afin de vous assurer que vous êtes couvert si Google décide d'actualiser l'ID d'enregistrement.

Cela dit, je n'ai jamais connu une telle actualisation, et même lorsque j'ai constaté une modification de l'ID d'enregistrement (généralement à la suite de l'envoi d'une notification après la désinstallation de l'application, puis sa réinstallation), l'ancien ID d'enregistrement était toujours travaillé (entraînant un identifiant d’enregistrement canonique envoyé dans la réponse de Google), aucun dommage n’a donc été causé.

EDIT (06.06.2013):

Google a changé son Demo App pour utiliser la nouvelle interface. Ils actualisent l'ID d'enregistrement en définissant une date d'expiration sur la valeur persistante localement par l'application. Lorsque l'application démarre, ils chargent leur identifiant d'enregistrement stocké localement. S'il est "expiré" (ce qui dans la démo signifie qu'il a été reçu de GCM il y a plus de 7 jours), ils appellent à nouveau gcm.register(senderID).

Cela ne gère pas le scénario hypothétique dans lequel un identifiant d'enregistrement est actualisé par Google pour une application qui n'a pas été lancée depuis longtemps. Dans ce cas, l'application ne sera pas informée du changement, pas plus que le serveur tiers.

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 a de nouveau changé leur application de démonstration (il y a deux jours). Cette fois, ils ont supprimé la logique qui considère que l'ID d'enregistrement a expiré après 7 jours. Désormais, ils actualisent uniquement l'ID d'enregistrement lorsqu'une nouvelle version de l'application l'a installée.

EDIT (04.24.2014):

Par souci d’exhaustivité, voici les propos de Costin Manolache (extrait de ici ), un développeur de Google impliqué dans le développement de GCM, à ce sujet:

L'actualisation "périodique" n'a jamais eu lieu et l'actualisation d'enregistrement n'est pas incluse dans la nouvelle bibliothèque de GCM.

La seule cause connue du changement d'identifiant d'enregistrement est l'ancien bogue des applications qui se désinscrivaient automatiquement si elles recevaient un message lors de la mise à niveau. Jusqu'à ce que ce bogue soit corrigé, les applications doivent toujours appeler register () après la mise à niveau. Jusqu'à présent, l'ID d'enregistrement peut changer dans ce cas. L'appel de unregister () de manière explicite modifie généralement l'ID d'enregistrement également.

La solution proposée consiste à générer votre propre identifiant aléatoire, enregistré sous forme de préférence partagée, par exemple. Lors de chaque mise à niveau de l'application, vous pouvez télécharger l'identifiant et le nouvel identifiant d'enregistrement potentiellement nouveau. Cela peut également aider à suivre et à déboguer les modifications de mise à niveau et d’enregistrement côté serveur.

Ceci explique la mise en œuvre actuelle de l'application officielle GCM Demo. com.google.Android.c2dm.intent.REGISTRATION Ne devrait jamais être manipulé lors de l'utilisation de la classe GoogleCloudMessaging.

137
Eran

En lisant la nouvelle API InstanceID, j'ai trouvé plus d'informations sur le moment où le jeton pourrait changer:

Votre application peut demander des jetons au service ID d'instance selon les besoins à l'aide de la méthode getToken () et, tout comme InstanceID, votre application peut également stocker des jetons sur votre propre serveur. Tous les jetons émis vers votre application appartiennent à l'instance InstanceID de l'application.

Les jetons sont uniques et sécurisés, mais votre application ou le service ID d’instance peut avoir besoin d’actualiser les jetons en cas de problème de sécurité ou lorsqu'un utilisateur désinstalle et réinstalle votre application lors de la restauration du périphérique . Votre application doit implémenter un écouteur pour répondre aux demandes d'actualisation de jeton du service ID d'instance.

Plus de détails:

Le service ID d'instance initie des rappels périodiquement (par exemple, tous les 6 mois), demandant à votre application d'actualiser ses jetons. Il peut également initier des rappels lorsque:

  • Il y a des problèmes de sécurité; par exemple, SSL ou problèmes de plate-forme.
  • Les informations sur le périphérique ne sont plus valides. par exemple, sauvegarde et restauration.
  • Le service ID d'instance est affecté d'une autre manière.

Sources:

https://developers.google.com/instance-id/

https://developers.google.com/instance-id/guides/Android-implementation

6
marius bardan

Après avoir parcouru des tonnes de réponses trompeuses sur le net, y compris SO, le seul endroit où j'ai trouvé une réponse complète était comme le remarquait la réponse d'Eran et ici :

Bien que l'actualisation de l'enregistrement automatique puisse ou ne se soit jamais produite, Google décrit un algorithme simple permettant de gérer les identificateurs canocical en analysant la réponse obtenue:

If the value of failure and canonical_ids is 0, it's not necessary to parse the remainder of the response. Otherwise, we recommend that you iterate through the results field and do the following for each object in that list:

If message_id is set, check for registration_id:
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 code>registration_ids passed in the request (using the same index).
Otherwise, get the value of error:
If it is Unavailable, you could retry to send it in another request.
If it is NotRegistered, you should remove the registration ID from your server database because the application was uninstalled from the device or it does not have a broadcast receiver configured to receive com.google.Android.c2dm.intent.RECEIVE intents.
Otherwise, there is something wrong in the registration ID passed in the request; it is probably a non-recoverable error that will also require removing the registration from the server database. See Interpreting an error response for all possible error values.

De lien précité.

2
rahulserver