Best Practices für die FCM-Registrierungstoken-Verwaltung

Wenn Sie FCM-APIs verwenden, um Sendeanforderungen programmgesteuert zu erstellen, stellen Sie möglicherweise fest, dass Sie mit der Zeit Ressourcen verschwenden, indem Sie Nachrichten an inaktive Geräte mit veralteten Registrierungstokens senden. Diese Situation kann sich auf die in der Firebase-Konsole gemeldeten Nachrichtenzustellungsdaten oder nach BigQuery exportierten Daten auswirken und sich in einem dramatischen (aber nicht wirklich gültigen) Rückgang der Zustellungsraten zeigen. In diesem Leitfaden werden einige Maßnahmen erläutert, die Sie ergreifen können, um eine effiziente Nachrichtenausrichtung und gültige Zustellungsberichte sicherzustellen.

Grundlegende Best Practices

Es gibt einige grundlegende Vorgehensweisen, die Sie in jeder App befolgen sollten, die FCM-APIs verwendet, um Sendeanforderungen programmgesteuert zu erstellen. Die wichtigsten Best Practices sind:

  • Speichern Sie Registrierungstokens auf Ihrem Server. Eine wichtige Rolle des Servers besteht darin, den Überblick über die Token jedes Clients zu behalten und eine aktualisierte Liste der aktiven Token zu führen. Wir empfehlen dringend, in Ihrem Code und auf Ihren Servern einen Token-Zeitstempel zu implementieren und diesen Zeitstempel in regelmäßigen Abständen zu aktualisieren.
  • Entfernen Sie gespeicherte Token, die veraltet sind . Zusätzlich zum Entfernen von Tokens in offensichtlichen Fällen ungültiger Token-Antworten müssen Sie wahrscheinlich auch andere Anzeichen dafür überwachen, dass das Token veraltet ist. In diesem Leitfaden werden einige Möglichkeiten erläutert, wie Sie dies erreichen können.

Registrierungstoken abrufen und speichern

Beim ersten Start Ihrer App generiert das FCM SDK ein Registrierungstoken für die Client-App-Instanz. Dies ist das Token, das Sie in gezielte Sendeanfragen von der API einbinden oder zu Themenabonnements hinzufügen müssen, um Themen gezielt anzusprechen.

Wie in unseren Client-Setup-Anleitungen erwähnt, sollte Ihre App dieses Token beim ersten Start abrufen und zusammen mit einem Zeitstempel auf Ihrem App-Server speichern . Dieser Zeitstempel muss von Ihrem Code und Ihren Servern implementiert werden, da er Ihnen von FCM SDKs nicht bereitgestellt wird.

Außerdem ist es wichtig, das Token auf dem Server zu speichern und den Zeitstempel zu aktualisieren, wenn er sich ändert, z. B. wenn:

  • Die App wird auf einem neuen Gerät wiederhergestellt
  • Der Benutzer deinstalliert/neuinstalliert die App
  • Der Benutzer löscht App-Daten.

Beispiel: Token und Zeitstempel im Cloud Firestore speichern

Sie könnten beispielsweise Cloud Firestore verwenden, um Token in einer Sammlung namens fcmTokens zu speichern. Jede Dokument-ID in der Sammlung entspricht einer Benutzer-ID, und das Dokument speichert das aktuelle Registrierungstoken und seinen zuletzt aktualisierten Zeitstempel. Verwenden Sie die set Funktion wie in diesem Kotlin-Beispiel gezeigt:

    /**
     * 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)
    }

Immer wenn ein Token abgerufen wird, wird es durch den Aufruf von sendTokenToServer im Cloud Firestore gespeichert:

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

Erkennen Sie ungültige Token-Antworten vom FCM-Backend

Stellen Sie sicher, dass Sie ungültige Token-Antworten von FCM erkennen und reagieren Sie, indem Sie alle Registrierungstokens, die bekanntermaßen ungültig sind, aus Ihrem System löschen. Bei der HTTP v1-API können diese Fehlermeldungen darauf hinweisen, dass Ihre Sendeanforderung auf veraltete oder ungültige Token abzielte:

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

Beachten Sie, dass INVALID_ARGUMENT auch bei Problemen mit der Nachrichtennutzlast ausgelöst wird und nur dann ein ungültiges Token signalisiert, wenn die Nutzlast vollständig gültig ist. Weitere Informationen finden Sie unter Fehlercodes .

Wenn Sie sicher sind, dass die Nachrichtennutzlast gültig ist und Sie eine dieser Antworten für ein Ziel-Token erhalten, können Sie Ihren Datensatz dieses Tokens bedenkenlos löschen, da er nie wieder gültig sein wird. Um beispielsweise ungültige Token aus Cloud Firestore zu löschen, könnten Sie eine Funktion wie die folgende bereitstellen und ausführen:

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

Gewährleistung der Aktualität des Registrierungstokens

Es ist nicht immer einfach festzustellen, ob ein Token frisch oder veraltet ist. Um alle Fälle abzudecken, sollten Sie einen Schwellenwert festlegen, ab dem Sie Token als veraltet betrachten. Unsere Empfehlung liegt bei zwei Monaten. Jeder Token, der älter als zwei Monate ist, ist wahrscheinlich ein inaktives Gerät; Ein aktives Gerät hätte andernfalls sein Token aktualisiert.

Aktualisieren Sie die Token regelmäßig

Wir empfehlen Ihnen, regelmäßig alle Registrierungstokens auf Ihrem Server abzurufen und zu aktualisieren. Dies erfordert Folgendes:

  • Fügen Sie Ihrer Client-App App-Logik hinzu, um das aktuelle Token mithilfe des entsprechenden API-Aufrufs abzurufen (z. B. token(completion): für Apple-Plattformen oder getToken() für Android) und senden Sie dann das aktuelle Token zur Speicherung an Ihren App-Server (mit Zeitstempel). ). Dies könnte ein monatlicher Job sein, der so konfiguriert ist, dass er alle Clients/Tokens abdeckt.
  • Fügen Sie Serverlogik hinzu, um den Zeitstempel des Tokens in regelmäßigen Abständen zu aktualisieren, unabhängig davon, ob sich das Token geändert hat oder nicht.

Ein Beispiel für die Android-Logik zum Aktualisieren von Tokens mit WorkManager finden Sie unter Managing Cloud Messaging Tokens im Firebase-Blog.

Unabhängig davon, welchem ​​Zeitmuster Sie folgen, stellen Sie sicher, dass Sie die Token regelmäßig aktualisieren. Eine Aktualisierungshäufigkeit alle zwei Monate schafft wahrscheinlich ein gutes Gleichgewicht zwischen der Belastung der Batterie und der Erkennung inaktiver Registrierungstokens. Durch diese Aktualisierung stellen Sie außerdem sicher, dass jedes Gerät, das inaktiv wird, seine Registrierung aktualisiert, wenn es wieder aktiv wird. Es hat keinen Vorteil, die Aktualisierung häufiger als wöchentlich durchzuführen.

Entfernen Sie veraltete Registrierungstoken

Stellen Sie vor dem Senden von Nachrichten an ein Gerät sicher, dass der Zeitstempel des Registrierungstokens des Geräts innerhalb Ihres Veraltungsfensterzeitraums liegt. Sie könnten beispielsweise Cloud Functions für Firebase implementieren, um eine tägliche Prüfung durchzuführen, um sicherzustellen, dass der Zeitstempel innerhalb eines definierten Veraltungsfensterzeitraums liegt, z. B. const EXPIRATION_TIME = 1000 * 60 * 60 * 24 * 60; und dann veraltete Token entfernen:

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

Abbestellen veralteter Token von Themen

Ein weiterer Aspekt ist die Verwaltung von Themenabonnements, um veraltete Registrierungstoken zu entfernen. Es umfasst zwei Schritte:

  1. Ihre App sollte Themen einmal im Monat und/oder bei jeder Änderung des Registrierungstokens erneut abonnieren. Dadurch entsteht eine selbstheilende Lösung, bei der die Abonnements automatisch wieder angezeigt werden, wenn eine App wieder aktiv wird.
  2. Wenn eine App-Instanz zwei Monate lang (oder Ihr eigenes Veraltungsfenster) inaktiv ist, sollten Sie sie mithilfe des Firebase Admin SDK von Themen abmelden, um die Token-/Themenzuordnung aus dem FCM-Backend zu löschen.

Der Vorteil dieser beiden Schritte besteht darin, dass Ihr Fanout schneller erfolgt, da weniger veraltete Token zum Fanout vorhanden sind und Ihre veralteten App-Instanzen automatisch erneut abonniert werden, sobald sie wieder aktiv sind.

Messung des Liefererfolgs

Im Allgemeinen empfehlen wir die gezielte Ausrichtung von Nachrichten auf der Grundlage von Aktionen, die bei aktiv genutzten App-Instanzen beobachtet oder erfasst werden. Dies ist besonders wichtig, wenn Sie regelmäßig Nachrichten zu Themen mit einer großen Anzahl von Abonnenten versenden; Wenn ein Teil dieser Abonnenten tatsächlich inaktiv ist, kann die Auswirkung auf Ihre Zustellstatistiken im Laufe der Zeit erheblich sein.

Bevor Sie Nachrichten an ein Token richten, sollten Sie Folgendes berücksichtigen:

  • Zeigen Google Analytics, in BigQuery erfasste Daten oder andere Tracking-Signale an, dass das Token aktiv ist?
  • Sind frühere Zustellversuche über einen längeren Zeitraum immer wieder fehlgeschlagen?
  • Wurde das Registrierungstoken auf Ihren Servern in den letzten zwei Monaten aktualisiert?
  • Meldet die FCM-Daten-API bei Android-Geräten einen hohen Prozentsatz an Nachrichtenübermittlungsfehlern aufgrund droppedDeviceInactive ?

Weitere Informationen zur Zustellung finden Sie unter Grundlegendes zur Nachrichtenzustellung .