Práticas recomendadas para gerenciamento de token de registro do FCM

Se você usar APIs FCM para criar solicitações de envio programaticamente, poderá descobrir que, com o tempo, estará desperdiçando recursos enviando mensagens para dispositivos inativos com tokens de registro obsoletos. Essa situação pode afetar os dados de entrega de mensagens informados no console do Firebase ou os dados exportados para o BigQuery, resultando em uma queda drástica (mas não válida) nas taxas de entrega. Este guia discute algumas medidas que você pode tomar para ajudar a garantir o direcionamento eficiente da mensagem e relatórios de entrega válidos.

Tokens de registro obsoletos e expirados

Tokens de registro obsoletos são tokens associados a dispositivos inativos que não estão conectados ao FCM há mais de um mês. Com o passar do tempo, torna-se cada vez menos provável que o dispositivo se conecte ao FCM novamente. É improvável que os envios de mensagens e fanouts de tópicos para esses tokens obsoletos sejam entregues.

Existem vários motivos pelos quais um token pode ficar obsoleto. Por exemplo, o dispositivo ao qual o token está associado pode ser perdido, destruído ou armazenado e esquecido.

Quando os tokens obsoletos atingirem 270 dias de inatividade, o FCM os considerará como tokens expirados . Quando um token expira, o FCM o marca como inválido e rejeita os envios para ele. No entanto, o FCM emite um novo token para a instância do aplicativo no caso raro de o dispositivo se conectar novamente e o aplicativo ser aberto.

Melhores práticas básicas

Existem algumas práticas fundamentais que você deve seguir em qualquer aplicativo que use APIs FCM para criar solicitações de envio de maneira programática. As principais práticas recomendadas são:

  • Recupere tokens de registro do FCM e armazene-os em seu servidor. Uma função importante do servidor é acompanhar o token de cada cliente e manter uma lista atualizada de tokens ativos. Recomendamos fortemente a implementação de um carimbo de data/hora de token em seu código e em seus servidores, e a atualização desse carimbo de data/hora em intervalos regulares.
  • Mantenha a atualização do token e remova tokens obsoletos. Além de remover tokens que o FCM não considera mais válidos, você pode monitorar outros sinais de que os tokens ficaram obsoletos e removê-los proativamente. Este guia discute algumas de suas opções para conseguir isso.

Recuperar e armazenar tokens de registro

Na inicialização do seu aplicativo, o SDK do FCM gera um token de registro para a instância do aplicativo cliente. Este é o token que você deve incluir em solicitações de envio direcionadas da API ou incluir em assinaturas de tópicos para direcionar tópicos.

Recomendamos fortemente que seu aplicativo recupere esse token na inicialização e salve-o no servidor do aplicativo junto com um carimbo de data/hora . Esse carimbo de data/hora deve ser implementado pelo seu código e pelos seus servidores, pois não é fornecido pelos SDKs do FCM.

Além disso, é importante salvar o token no servidor e atualizar o carimbo de data/hora sempre que ele for alterado, como quando:

  • O aplicativo é restaurado em um novo dispositivo
  • O usuário desinstala ou reinstala o aplicativo
  • O usuário limpa os dados do aplicativo
  • O aplicativo fica ativo novamente depois que o token existente do FCM expira

Exemplo: armazenar tokens e carimbos de data/hora no Cloud Firestore

Por exemplo, você pode usar o Cloud Firestore para armazenar tokens em uma coleção chamada fcmTokens . Cada ID de documento na coleção corresponde a um ID de usuário, e o documento armazena o token de registro atual e seu carimbo de data/hora da última atualização. Use a função set conforme mostrado neste exemplo 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)
    }

Sempre que um token é recuperado, ele é armazenado no Cloud Firestore chamando 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()
            }
        }

Mantenha a atualização do token e remova tokens obsoletos

Determinar se um token é novo ou obsoleto nem sempre é simples. Para cobrir todos os casos, você deve adotar um limite para quando considerar os tokens obsoletos. Por padrão, o FCM considera um token obsoleto se a instância do aplicativo não estiver conectada há um mês. Qualquer token com mais de um mês provavelmente será um dispositivo inativo; caso contrário, um dispositivo ativo teria atualizado seu token.

Dependendo do seu caso de uso, um mês pode ser muito curto ou muito longo, então cabe a você determinar os critérios que funcionam para você.

Detecte respostas de token inválidas do back-end do FCM

Certifique-se de detectar respostas de token inválidas do FCM e responda excluindo do seu sistema quaisquer tokens de registro que sejam inválidos ou que tenham expirado. Com a API HTTP v1, estas mensagens de erro podem indicar que sua solicitação de envio tinha como alvo tokens inválidos ou expirados:

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

Se você tiver certeza de que a carga útil da mensagem é válida e receber qualquer uma dessas respostas para um token direcionado, é seguro excluir o registro desse token, pois ele nunca mais será válido. Por exemplo, para excluir tokens inválidos do Cloud Firestore, você pode implantar e executar uma função como esta:

    // 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()
        }
    });

O FCM só retornará uma resposta de token inválida se um token expirar após 270 dias ou se um cliente cancelar explicitamente o registro. Se você precisar rastrear a desatualização com mais precisão de acordo com suas próprias definições, poderá remover proativamente os tokens de registro desatualizados .

Atualize tokens regularmente

Recomendamos que você recupere e atualize periodicamente todos os tokens de registro no seu servidor. Isso exige que você:

  • Adicione lógica de aplicativo em seu aplicativo cliente para recuperar o token atual usando a chamada de API apropriada (como token(completion): para plataformas Apple ou getToken() para Android) e, em seguida, envie o token atual para seu servidor de aplicativo para armazenamento (com um carimbo de data/hora). Este poderia ser um trabalho mensal configurado para cobrir todos os clientes ou tokens.
  • Adicione lógica de servidor para atualizar o carimbo de data/hora do token em intervalos regulares, independentemente de o token ter sido alterado ou não.

Para ver um exemplo de lógica do Android para atualizar tokens usando WorkManager , consulte Gerenciando tokens de mensagens na nuvem no blog do Firebase.

Qualquer que seja o padrão de tempo que você seguir, certifique-se de atualizar os tokens periodicamente. Uma frequência de atualização de uma vez por mês proporciona um bom equilíbrio entre o impacto da bateria e a detecção de tokens de registro inativos. Ao fazer essa atualização, você também garante que qualquer dispositivo que fique inativo atualizará seu registro quando ficar ativo novamente. Não há benefício em fazer a atualização com mais frequência do que semanalmente.

Remover tokens de registro obsoletos

Antes de enviar mensagens para um dispositivo, certifique-se de que o carimbo de data/hora do token de registro do dispositivo esteja dentro do período da janela de inatividade. Por exemplo, você pode implementar o Cloud Functions para Firebase para executar uma verificação diária para garantir que o carimbo de data/hora esteja dentro de um período de janela de inatividade definido, como const EXPIRATION_TIME = 1000 * 60 * 60 * 24 * 30; e, em seguida, remova os tokens obsoletos:

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

Cancelar assinatura de tokens obsoletos de tópicos

Se você usar tópicos, também poderá cancelar o registro de tokens obsoletos dos tópicos nos quais eles estão inscritos. Isso envolve duas etapas:

  1. Seu aplicativo deve se inscrever novamente nos tópicos uma vez por mês e sempre que o token de registro for alterado. Isso forma uma solução de autocorreção, onde as assinaturas reaparecem automaticamente quando um aplicativo fica ativo novamente.
  2. Se uma instância de aplicativo ficar inativa por um mês (ou por sua própria janela de inatividade), cancele a inscrição dela nos tópicos usando o SDK Admin do Firebase para excluir o token para mapeamento de tópico do back-end do FCM.

O benefício dessas duas etapas é que seus fanouts ocorrerão mais rapidamente, pois há menos tokens obsoletos para distribuir, e suas instâncias de aplicativos obsoletos serão automaticamente assinadas novamente assim que estiverem ativas novamente.

Avalie o sucesso da entrega

Para obter uma imagem mais precisa da entrega de mensagens, é melhor enviar mensagens apenas para instâncias de aplicativos usadas ativamente. Isto é especialmente importante se você envia mensagens regularmente para tópicos com grande número de assinantes; se uma parte desses assinantes estiver realmente inativa, o impacto nas estatísticas de entrega poderá ser significativo ao longo do tempo.

Antes de direcionar mensagens para um token, considere:

  • O Google Analytics, os dados capturados no BigQuery ou outros sinais de rastreamento indicam que o token está ativo?
  • As tentativas de entrega anteriores falharam consistentemente durante um período de tempo?
  • O token de registro foi atualizado em seus servidores no último mês?
  • Para dispositivos Android, a API FCM Data relata uma alta porcentagem de falhas na entrega de mensagens devido a droppedDeviceInactive ?

Para obter mais informações sobre entrega, consulte Noções básicas sobre entrega de mensagens .