Manejo de cambios de ID de registro en Google Cloud Messaging en Android

78

En los documentos sobre Google Cloud Messaging, dice:

La aplicación de Android debe almacenar este ID para su uso posterior (por ejemplo, para verificar onCreate () si ya está registrado). Tenga en cuenta que Google puede actualizar periódicamente el ID de registro, por lo que debe diseñar su aplicación de Android con el entendimiento de que la intención com.google.android.c2dm.intent.REGISTRATION se puede llamar varias veces. Su aplicación de Android debe poder responder en consecuencia.

Registro mi dispositivo usando el siguiente código:

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

La clase GoogleCloudMessaging encapsula el proceso de registro. Entonces, ¿cómo se supone que debo manejar com.google.android.c2dm.intent.REGISTRATION ya que el manejo se realiza internamente por la clase GoogleCloudMessaging?

AndroidDev
fuente

Respuestas:

137

Esa es una pregunta interesante.

Google le anima a cambiar al nuevo proceso de registro:

Una aplicación de Android que se ejecuta en un dispositivo móvil se registra para recibir mensajes llamando al registro del método GoogleCloudMessaging (senderID ...). Este método registra la aplicación para GCM y devuelve el ID de registro. Este enfoque simplificado reemplaza el proceso de registro de GCM anterior.

La nota que dice Google may periodically refresh the registration IDsolo aparece en la página que aún muestra el proceso de registro anterior, por lo que es posible que esta nota ya no sea relevante.

Si desea estar seguro, puede seguir utilizando el proceso de registro anterior. O puede usar el nuevo proceso, pero además tenga el código que maneja la com.google.android.c2dm.intent.REGISTRATIONintención, para asegurarse de que está cubierto si Google decide actualizar el ID de registro.

Dicho esto, nunca experimenté tal actualización, e incluso cuando experimenté un cambio en el ID de registro (generalmente como resultado de enviar una notificación después de desinstalar la aplicación y luego volver a instalarla), el ID de registro anterior todavía funcionó (lo que resultó en un ID de registro canónico enviado en la respuesta de Google), por lo que no se hizo ningún daño.

EDITAR (06.06.2013):

Google cambió su aplicación de demostración para usar la nueva interfaz. Actualizan el ID de registro estableciendo una fecha de vencimiento en el valor persistente localmente por la aplicación. Cuando se inicia la aplicación, cargan su identificación de registro almacenada localmente. Si está "caducado" (lo que en la demostración significa que se recibió de GCM hace más de 7 días), vuelven a llamar gcm.register(senderID).

Esto no maneja el escenario hipotético en el que Google actualiza un ID de registro para una aplicación que no se ha lanzado durante mucho tiempo. En ese caso, la aplicación no se dará cuenta del cambio, ni tampoco el servidor de terceros.

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

EDITAR (14.08.2013):

Google volvió a cambiar su aplicación de demostración (hace dos días). Esta vez eliminaron la lógica que considera que el ID de registro caduca después de 7 días. Ahora solo actualizan el ID de registro cuando se instala una nueva versión de la aplicación.

EDITAR (24.04.2014):

En aras de la integridad, aquí están las palabras de Costin Manolache (tomadas de aquí ), un desarrollador de Google involucrado en el desarrollo de GCM, sobre el tema:

La actualización 'periódica' nunca ocurrió y la actualización del registro no está incluida en la nueva biblioteca de GCM.

La única causa conocida para el cambio de ID de registro es el antiguo error de que las aplicaciones se anulan automáticamente si reciben un mensaje mientras se actualizan. Hasta que se solucione este error, las aplicaciones aún deben llamar a register () después de la actualización, y hasta ahora la ID de registro puede cambiar en este caso. Llamar a unregister () explícitamente generalmente también cambia el ID de registro.

La sugerencia / solución es generar su propio identificador aleatorio, guardado como preferencia compartida, por ejemplo. En cada actualización de la aplicación, puede cargar el identificador y el ID de registro potencialmente nuevo. Esto también puede ayudar a rastrear y depurar los cambios de actualización y registro en el lado del servidor.

Esto explica la implementación actual de la aplicación oficial de demostración de GCM. com.google.android.c2dm.intent.REGISTRATIONnunca debe manejarse al usar la GoogleCloudMessagingclase para registrarse.

Eran
fuente
Creo que tiene razón en su respuesta y que cualquier cambio en regid puede ser manejado por las respuestas php o jsp en el servidor de aplicaciones del proyecto. Sin embargo, ¡ya es hora de que Google actualice su código de cliente / servidor de demostración incluido con el SDK!
NickT
Parece que los documentos de Google están desactualizados. La clase GCMBaseIntentService, cuando se implementa, tiene onUnregistered que se llama. No se indica si se llama cuando se actualiza el ID de registro. La sección "Comenzando" en GCM ni siquiera menciona GCMBaseIntentService, pero está incluida en el código de muestra. Google realmente necesita limpiar sus documentos.
AndroidDev
@AndroidDev Sí, sus documentos están un poco desordenados en este momento. Sin embargo, afirman que existen múltiples formas de implementar GCM. Getting Started muestra la nueva forma, pero menciona (en el Paso 3) que hay otra forma y enlaza con ella. GCMBaseIntentServicetodavía se menciona en la página Uso de las bibliotecas auxiliares de GCM .
Eran
19
+1 para editar (24/04/2014) las viejas preguntas y respuestas de SO engañaron y me hicieron perder el tiempo ... Ojalá todos publicaran una edición de sus respuestas anteriores que ya no son válidas
Harshad Ranganathan
2
Necesitaremos una edición para GCM 3.0. developers.google.com/cloud-messaging/android/start
Kowlown
6

Al leer la nueva API de InstanceID, encontré más información sobre cuándo podría cambiar el token:

Su aplicación puede solicitar tokens del servicio de ID de instancia según sea necesario utilizando el método getToken () y, al igual que InstanceID, su aplicación también puede almacenar tokens en su propio servidor. Todos los tokens emitidos para su aplicación pertenecen al InstanceID de la aplicación.

Los tokens son únicos y seguros, pero su aplicación o el servicio de ID de instancia pueden necesitar actualizar los tokens en caso de un problema de seguridad o cuando un usuario desinstala y reinstala su aplicación durante la restauración del dispositivo . Tu aplicación debe implementar un agente de escucha para responder a las solicitudes de actualización de tokens del servicio de ID de instancia.

Más detalles:

El servicio de ID de instancia inicia devoluciones de llamada periódicamente (por ejemplo, cada 6 meses), solicitando que su aplicación actualice sus tokens. También puede iniciar devoluciones de llamada cuando:

  • Hay problemas de seguridad; por ejemplo, problemas de plataforma o SSL.
  • La información del dispositivo ya no es válida; por ejemplo, copia de seguridad y restauración.
  • De lo contrario, el servicio de ID de instancia se ve afectado.

Fuentes:

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

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

marius bardan
fuente
2

Después de revisar toneladas de respuestas engañosas en la red, incluido SO, el único lugar donde encontré una respuesta completa fue como lo comentó la respuesta de Eran y aquí :

Si bien la actualización automática del registro podría haber ocurrido o nunca, Google describe un algoritmo simple para manejar canocical_ids analizando la respuesta exitosa:

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.

Desde el enlace antes mencionado.

rahulserver
fuente