Prácticas recomendadas para la administración de tokens de registro de FCM

Si usas las APIs de FCM para crear solicitudes de envío de manera programática, es posible que, con el tiempo, desperdicies recursos a través del envío de mensajes a dispositivos inactivos con tokens de registro inactivos. Esta situación puede afectar los datos de entrega de mensajes informados en Firebase console o los datos que se exportan a BigQuery, en los que aparecen como una disminución dramática (pero no válida) de las tasas de entrega. En esta guía, se analizan algunas medidas que puedes tomar para garantizar una segmentación por mensajes eficaz y generar informes de entrega válidos.

Tokens de registro inactivos y vencidos

Los tokens de registro inactivos son tokens asociados con dispositivos inactivos que no se han conectado a FCM desde hace más de un mes. A medida que pasa el tiempo, es cada vez menos probable que el dispositivo vuelva a conectarse a FCM. Es poco probable que se garantice la entrega de los envíos de mensajes y las distribuciones de temas para estos tokens inactivos.

Existen varios motivos por los que un token puede volverse inactivo. Por ejemplo, el dispositivo al que está asociado el token puede perderse, destruirse o almacenarse y olvidarse.

Cuando los tokens inactivos alcancen los 270 días de inactividad, FCM los considerará tokens vencidos. Una vez que vence un token, FCM lo marca como no válido y rechaza los envíos a este. Sin embargo, FCM emite un token nuevo para la instancia de la app en el caso excepcional de que el dispositivo se vuelva a conectar y se abra la app.

Prácticas recomendadas básicas

Hay algunas prácticas fundamentales que debes seguir en cualquier app que use las APIs de FCM para crear solicitudes de envío de manera programática. Las siguientes son las principales prácticas recomendadas:

  • Recupera tokens de registro de FCM y guárdalos en tu servidor. Una función importante del servidor es realizar un seguimiento del token de cada cliente y mantener una lista actualizada de los tokens activos. Recomendamos implementar una marca de tiempo de token en el código y los servidores, y actualizarla en intervalos regulares.
  • Mantén los tokens actualizados y quita los inactivos. Además de quitar los tokens que FCM ya no se consideran válidos, es posible que quieras supervisar otros indicadores de que los tokens quedaron inactivos y quítalos de forma proactiva. En esta guía, se analizan algunas de las opciones disponibles para lograrlo.

Recupera y almacena tokens de registro

Cuando se inicia tu app por primera vez, el SDK de FCM genera un token de registro para la instancia de la app cliente. Este es el token que debes incluir en las solicitudes de envío orientadas de la API o agregar a suscripciones a temas para temas de orientación.

Recomendamos que tu app recupere este token durante el inicio y lo guarde en tu servidor de apps junto con una marca de tiempo. Tu código y tus servidores deben implementar esta marca de tiempo, ya que los SDKs de FCM no la proporcionan.

Además, es importante guardar el token en el servidor y actualizar la marca de tiempo cada vez que cambia, por ejemplo:

  • La app se restablece en un dispositivo nuevo.
  • El usuario desinstala o vuelve a instalar la app.
  • El usuario borra los datos de la app.
  • La app vuelve a estar activa después de que venza el token existente de FCM.

Ejemplo: Almacena tokens y marcas de tiempo en Cloud Firestore

Por ejemplo, puedes usar Cloud Firestore para almacenar tokens en una colección llamada fcmTokens. Cada ID de documento de la colección corresponde a un ID de usuario, y el documento almacena el token de registro actual y la última actualización de la marca de tiempo. Usa la función set como se muestra en este ejemplo de Kotlin:

    /**
     * Persist token to third-party servers.
     *
     * Modify this method to associate the user's FCM registration token with any server-side account
     * maintained by your application.
     *
     * @param token The new token.
     */
    private fun sendTokenToServer(token: String?) {
        // If you're running your own server, call API to send token and today's date for the user

        // Example shown below with Firestore
        // Add token and timestamp to Firestore for this user
        val deviceToken = hashMapOf(
            "token" to token,
            "timestamp" to FieldValue.serverTimestamp(),
        )
        // Get user ID from Firebase Auth or your own server
        Firebase.firestore.collection("fcmTokens").document("myuserid")
            .set(deviceToken)
    }

Cada vez que se recupera un token, se almacena en Cloud Firestore; para ello, se llama a sendTokenToServer:

    /**
     * Called if the FCM registration token is updated. This may occur if the security of
     * the previous token had been compromised. Note that this is called when the
     * FCM registration token is initially generated so this is where you would retrieve the token.
     */
    override fun onNewToken(token: String) {
        Log.d(TAG, "Refreshed token: $token")

        // If you want to send messages to this application instance or
        // manage this apps subscriptions on the server side, send the
        // FCM registration token to your app server.
        sendTokenToServer(token)
    }
        var token = Firebase.messaging.token.await()

        // Check whether the retrieved token matches the one on your server for this user's device
        val preferences = this.getPreferences(Context.MODE_PRIVATE)
        val tokenStored = preferences.getString("deviceToken", "")
        lifecycleScope.launch {
            if (tokenStored == "" || tokenStored != token)
            {
                // If you have your own server, call API to send the above token and Date() for this user's device

                // Example shown below with Firestore
                // Add token and timestamp to Firestore for this user
                val deviceToken = hashMapOf(
                    "token" to token,
                    "timestamp" to FieldValue.serverTimestamp(),
                )

                // Get user ID from Firebase Auth or your own server
                Firebase.firestore.collection("fcmTokens").document("myuserid")
                    .set(deviceToken).await()
            }
        }

Mantén los tokens actualizados y quita los inactivos

Determinar si un token está activo o inactivo no siempre es sencillo. Para abarcar todos los casos, debes adoptar un umbral sobre el momento en que consideres inactivos a los tokens. De forma predeterminada, FCM considera que un token está inactivo si su instancia de app no se conectó durante un mes. Es probable que cualquier token que tenga más de un mes de antigüedad sea un dispositivo inactivo; de lo contrario, un dispositivo activo habría actualizado su token.

Según tu caso de uso, un mes puede ser demasiado corto o demasiado largo, por lo que depende de ti determinar los criterios que funcionan mejor.

Detecta respuestas de token no válidas del backend de FCM

Asegúrate de detectar las respuestas de token no válidas de FCM y borrar de tu sistema los tokens de registro que se identifiquen como no válidos o vencidos. Con la API de HTTP v1, estos mensajes de error pueden indicar que tu solicitud de envío se orientó a tokens no válidos o vencidos:

  • UNREGISTERED (HTTP 404)
  • INVALID_ARGUMENT (HTTP 400)

Si tienes la certeza de que la carga útil del mensaje es válida y recibes cualquiera de estas respuestas para un token de destino, puedes borrar tu registro de este token, ya que nunca volverá a ser válido. Por ejemplo, para borrar tokens no válidos de Cloud Firestore, puedes implementar y ejecutar una función como la siguiente:

    // Registration token comes from the client FCM SDKs
    const registrationToken = 'YOUR_REGISTRATION_TOKEN';

    const message = {
    data: {
        // Information you want to send inside of notification
    },
    token: registrationToken
    };

    // Send message to device with provided registration token
    getMessaging().send(message)
    .then((response) => {
        // Response is a message ID string.
    })
    .catch((error) => {
        // Delete token for user if error code is UNREGISTERED or INVALID_ARGUMENT.
        if (errorCode == "messaging/registration-token-not-registered") {
            // If you're running your own server, call API to delete the
            token for the user

            // Example shown below with Firestore
            // Get user ID from Firebase Auth or your own server
            Firebase.firestore.collection("fcmTokens").document(user.uid).delete()
        }
    });

FCM solo devolverá una respuesta de token no válido si un token venció después de 270 días o si un cliente canceló su registro de forma explícita. Si necesitas hacer un seguimiento más preciso de la inactividad según tus propias definiciones, puedes quitar los tokens de registro inactivos de forma proactiva.

Actualiza los tokens periódicamente

Te recomendamos que recuperes y actualices todos los tokens de registro de forma periódica en tu servidor. Para ello, debes hacer lo siguiente:

  • Agrega la lógica de la app a tu app cliente para recuperar el token actual con la llamada a la API correspondiente (como token(completion): para plataformas de Apple o getToken() para Android) y, luego, enviar el token actual al servidor de apps para su almacenamiento (con una marca de tiempo). Este podría ser un trabajo mensual configurado para abarcar todos los clientes o tokens.
  • Agrega lógica del servidor para actualizar la marca de tiempo del token a intervalos regulares, sin importar si el token cambió o no.

Si quieres ver un ejemplo de la lógica de Android para actualizar tokens con WorkManager, consulta Administra tokens de Cloud Messaging en el blog de Firebase.

Sin importar el patrón de sincronización que sigas, asegúrate de actualizar los tokens de forma periódica. Es probable que una frecuencia de actualización de una vez al mes genere un buen equilibrio entre el impacto de la batería y la detección de tokens de registro inactivos. Cuando haces esta actualización, también te aseguras de que cualquier dispositivo que se encuentre inactivo actualizará su registro cuando se vuelva a activar. No hay ningún beneficio en realizar la actualización con mayor frecuencia que una semanal.

Quita los tokens de registro inactivos

Antes de enviar mensajes a un dispositivo, asegúrate de que la marca de tiempo del token de registro del dispositivo esté dentro del período de inactividad. Por ejemplo, puedes implementar Cloud Functions for Firebase para ejecutar una verificación diaria y asegurarte de que la marca de tiempo se encuentre dentro de un período de inactividad definido, como const EXPIRATION_TIME = 1000 * 60 * 60 * 24 * 30;, y, luego, quitar los tokens inactivos:

exports.pruneTokens = functions.pubsub.schedule('every 24 hours').onRun(async (context) => {
  // Get all documents where the timestamp exceeds is not within the past month
  const staleTokensResult = await admin.firestore().collection('fcmTokens')
      .where("timestamp", "<", Date.now() - EXPIRATION_TIME)
      .get();
  // Delete devices with stale tokens
  staleTokensResult.forEach(function(doc) { doc.ref.delete(); });
});

Anula la suscripción de tokens inactivos de temas

Si usas temas, también es posible que quieras cancelar el registro de los tokens inactivos de los temas a los que están suscritos. Esto consta de dos pasos:

  1. Tu app debe volver a suscribirse a los temas una vez al mes y cuando cambie el token de registro. Esto forma una solución autorreparable, en la que las suscripciones vuelven a aparecer automáticamente cuando vuelve a activarse una app.
  2. Si una instancia de app está inactiva durante un mes (o tu propio período de inactividad), debes anular la suscripción a los temas con el SDK de Firebase Admin para borra el token de la asignación de temas del backend de FCM.

El beneficio de estos dos pasos es que tus distribuciones se realizarán más rápido, ya que habrá menos tokens inactivos para distribuir, y tus instancias de apps inactivas se volverán a suscribir automáticamente cuando vuelvan a estar activas.

Mide el éxito de la entrega

Para obtener una imagen más precisa de la entrega de mensajes, lo mejor es enviar mensajes solo a instancias de apps que se usen de forma activa. Esto es especialmente importante si envías mensajes con regularidad a temas con una gran cantidad de suscriptores. Si una parte de esos suscriptores está realmente inactiva, el impacto en tus estadísticas de entrega puede ser significativo con el tiempo.

Antes de orientar mensajes a un token, considera lo siguiente:

  • ¿Indican Google Analytics, los datos capturados en BigQuery o cualquier otro indicador de seguimiento que el token está activo?
  • ¿Se produjo un error al intentar realizar los intentos de entrega anteriores de forma constante durante un período?
  • ¿Se actualizó el token de registro en tus servidores en el último mes?
  • En los dispositivos Android, ¿informa la API de datos de FCM un alto porcentaje de fallas en la entrega de mensajes debido a droppedDeviceInactive?

Para obtener más información sobre la entrega, consulta Información sobre la entrega de mensajes.