Behandeln von Änderungen der Registrierungs-ID in Google Cloud Messaging unter Android


78

In den Dokumenten zu Google Cloud Messaging heißt es:

Die Android-Anwendung sollte diese ID zur späteren Verwendung speichern (z. B. um onCreate () zu überprüfen, wenn sie bereits registriert ist). Beachten Sie, dass Google die Registrierungs-ID möglicherweise regelmäßig aktualisiert. Sie sollten Ihre Android-Anwendung daher so gestalten, dass die Absicht com.google.android.c2dm.intent.REGISTRATION möglicherweise mehrmals aufgerufen wird. Ihre Android-Anwendung muss in der Lage sein, entsprechend zu reagieren.

Ich registriere mein Gerät mit folgendem Code:

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

Die GoogleCloudMessaging-Klasse kapselt den Registrierungsprozess. Wie soll ich also mit com.google.android.c2dm.intent.REGISTRATION umgehen, da die Behandlung intern von der GoogleCloudMessaging-Klasse durchgeführt wird?

Antworten:


137

Das ist eine interessante Frage.

Google empfiehlt Ihnen, zum neuen Registrierungsprozess zu wechseln:

Eine Android-Anwendung, die auf einem mobilen Gerät ausgeführt wird, registriert sich, um Nachrichten zu empfangen, indem sie das GoogleCloudMessaging-Methodenregister (senderID ...) aufruft. Diese Methode registriert die Anwendung für GCM und gibt die Registrierungs-ID zurück. Dieser optimierte Ansatz ersetzt den vorherigen GCM-Registrierungsprozess.

Der Hinweis, der besagt, wird Google may periodically refresh the registration IDnur auf der Seite angezeigt, auf der noch der alte Registrierungsprozess angezeigt wird. Daher ist dieser Hinweis möglicherweise nicht mehr relevant.

Wenn Sie sicher sein möchten, können Sie weiterhin den alten Registrierungsprozess verwenden. Oder Sie können den neuen Prozess verwenden, haben aber zusätzlich den Code, der die com.google.android.c2dm.intent.REGISTRATIONAbsicht behandelt, um sicherzustellen, dass Sie abgesichert sind, wenn Google die Registrierungs-ID aktualisiert.

Trotzdem habe ich noch nie eine solche Aktualisierung erlebt, und selbst wenn sich die Registrierungs-ID geändert hat (normalerweise aufgrund des Sendens einer Benachrichtigung nach der Deinstallation der App und der anschließenden Neuinstallation), bleibt die alte Registrierungs-ID erhalten funktioniert (was zu einer kanonischen Registrierungs-ID führt, die in der Antwort von Google gesendet wurde), sodass kein Schaden angerichtet wurde.

EDIT (06.06.2013):

Google hat seine Demo-App geändert , um die neue Benutzeroberfläche zu verwenden. Sie aktualisieren die Registrierungs-ID, indem sie ein Ablaufdatum für den Wert festlegen, der lokal von der App beibehalten wird. Wenn die App gestartet wird, laden sie ihre lokal gespeicherte Registrierungs-ID. Wenn es "abgelaufen" ist (was in der Demo bedeutet, dass es vor über 7 Tagen von GCM empfangen wurde), rufen sie gcm.register(senderID)erneut an.

Dies behandelt nicht das hypothetische Szenario, in dem eine Registrierungs-ID von Google für eine App aktualisiert wird, die seit langer Zeit nicht mehr gestartet wurde. In diesem Fall ist der App die Änderung nicht bekannt, ebenso wenig wie dem Server eines Drittanbieters.

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;
}

BEARBEITEN (14.08.2013):

Google hat seine Demo-App erneut geändert (vor zwei Tagen). Diesmal haben sie die Logik entfernt, nach der die Registrierungs-ID nach 7 Tagen abgelaufen ist. Jetzt aktualisieren sie die Registrierungs-ID nur, wenn eine neue Version der App installiert wurde.

EDIT (24.04.2014):

Der Vollständigkeit halber sind hier die Worte von Costin Manolache (von hier übernommen ), einem Google-Entwickler, der an der Entwicklung von GCM beteiligt ist, zu diesem Thema:

Die "regelmäßige" Aktualisierung hat nie stattgefunden, und die Aktualisierung der Registrierung ist nicht in der neuen GCM-Bibliothek enthalten.

Die einzige bekannte Ursache für die Änderung der Registrierungs-ID ist der alte Fehler, dass Apps automatisch abgemeldet werden, wenn sie während des Upgrades eine Nachricht erhalten. Bis dieser Fehler behoben ist, müssen Apps nach dem Upgrade noch register () aufrufen. Bisher kann sich die Registrierungs-ID in diesem Fall ändern. Wenn Sie unregister () explizit aufrufen, wird normalerweise auch die Registrierungs-ID geändert.

Der Vorschlag / die Problemumgehung besteht darin, eine eigene zufällige Kennung zu generieren, die beispielsweise als gemeinsame Präferenz gespeichert wird. Bei jedem App-Upgrade können Sie die Kennung und die möglicherweise neue Registrierungs-ID hochladen. Dies kann auch dazu beitragen, die Aktualisierungs- und Registrierungsänderungen auf der Serverseite zu verfolgen und zu debuggen.

Dies erklärt die aktuelle Implementierung der offiziellen GCM-Demo-Anwendung. com.google.android.c2dm.intent.REGISTRATIONsollte niemals behandelt werden, wenn die GoogleCloudMessagingKlasse zum Registrieren verwendet wird.


Ich denke, dass Sie in Ihrer Antwort korrekt sind und dass alle Änderungen in regid durch die PHP- oder JSP-Antworten auf dem App-Server des Projekts behandelt werden können. Es ist jedoch an der Zeit, dass Google den im SDK enthaltenen Demo-Client / Server-Code aktualisiert!
NickT

Es scheint, dass die Dokumente von Google veraltet sind. Die GCMBaseIntentService-Klasse hat bei ihrer Implementierung onUnregistered, das aufgerufen wird. Ob dies aufgerufen wird, wenn die Registrierungs-ID aktualisiert wird, wird nicht angegeben. Der Abschnitt "Erste Schritte" in GCM erwähnt GCMBaseIntentService nicht einmal, ist jedoch im Beispielcode enthalten. Google muss seine Dokumente wirklich bereinigen.
AndroidDev

@AndroidDev Ja, ihre Dokumente sind im Moment etwas chaotisch. Sie geben jedoch an, dass es mehrere Möglichkeiten gibt, GCM zu implementieren. Erste Schritte zeigt den neuen Weg, erwähnt jedoch (in Schritt 3), dass es einen anderen Weg gibt, und verlinkt darauf. GCMBaseIntentServicewird weiterhin auf der Seite Verwenden der GCM-Hilfsbibliotheken erwähnt .
Eran

19
+1 für die Bearbeitung (24.04.2014) Die alten SO-Fragen und -Antworten haben meine Zeit in die Irre geführt und verschwendet. Ich wünschte, jeder hätte eine Bearbeitung seiner alten Antworten veröffentlicht, die nicht mehr gültig sind
Harshad Ranganathan,

2
Wir benötigen eine Bearbeitung für das GCM 3.0. developer.google.com/cloud-messaging/android/start
Kowlown

6

Beim Lesen der neuen InstanceID-API habe ich weitere Informationen darüber gefunden, wann sich das Token ändern könnte:

Ihre App kann bei Bedarf mithilfe der Methode getToken () Token vom Instanz-ID-Dienst anfordern. Wie InstanceID kann Ihre App auch Token auf Ihrem eigenen Server speichern. Alle an Ihre App ausgegebenen Token gehören zur InstanceID der App.

Token sind eindeutig und sicher, aber Ihre App oder der Instanz-ID-Dienst müssen möglicherweise Token aktualisieren, wenn ein Sicherheitsproblem auftritt oder wenn ein Benutzer Ihre App während der Gerätewiederherstellung deinstalliert und neu installiert . Ihre App muss einen Listener implementieren, um auf Tokenaktualisierungsanforderungen vom Instanz-ID-Dienst zu antworten.

Mehr Details:

Der Instanz-ID-Dienst initiiert regelmäßig Rückrufe (z. B. alle 6 Monate) und fordert Ihre App auf, ihre Token zu aktualisieren. Es kann auch Rückrufe auslösen, wenn:

  • Es gibt Sicherheitsprobleme. Zum Beispiel SSL- oder Plattformprobleme.
  • Geräteinformationen sind nicht mehr gültig. Zum Beispiel sichern und wiederherstellen.
  • Der Instanz-ID-Dienst ist ansonsten betroffen.

Quellen:

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

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


2

Nachdem ich Tonnen von irreführenden Antworten im Internet, einschließlich SO, durchgesehen hatte, fand ich nur eine vollständige Antwort, wie in Erans Antwort und hier bemerkt :

Während die automatische Aktualisierung der Registrierung möglicherweise oder möglicherweise nie stattgefunden hat, beschreibt Google einen einfachen Algorithmus zur Behandlung der canocical_ids durch Analyse der erfolgreichen Antwort:

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.

Vom oben genannten Link.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.