Sprawdzone metody zarządzania rejestracją w FCM

Jeśli używasz interfejsów API FCM do automatycznego tworzenia żądań wysyłania, z czasem możesz zauważyć, że marnujesz zasoby, wysyłając wiadomości do nieaktywnych urządzeń z nieaktualnymi rejestracjami. Taka sytuacja może mieć wpływ na dane o dostarczaniu wiadomości raportowane w konsoli Firebase lub eksportowane do BigQuery, co może się objawiać gwałtownym (ale nieprawdziwym) spadkiem współczynników dostarczania. W tym przewodniku omawiamy pewne środki, które możesz podjąć, aby zapewnić skuteczne kierowanie wiadomości i prawidłowe raportowanie dostarczania.

Nieaktualne i wygasłe rejestracje

Nieaktualne rejestracje są powiązane z nieaktywnymi urządzeniami, które nie łączyły się z FCM od ponad miesiąca. Z czasem prawdopodobieństwo, że urządzenie ponownie połączy się z FCM, maleje. Wysyłanie wiadomości i rozsyłanie tematów w przypadku tych nieaktualnych rejestracji prawdopodobnie nigdy nie zostanie zrealizowane.

Istnieje kilka powodów, dla których rejestracja może stać się nieaktualna. Na przykład urządzenie, z którym jest powiązana rejestracja, może zostać zgubione, zniszczone lub umieszczone w magazynie i zapomniane.

W przypadku Androida, gdy rejestracja jest nieaktywna przez 270 dni, FCM uznaje ją za wygasłą i usuwa. Gdy rejestracja wygaśnie, FCM oznacza ją jako nieprawidłową i odrzuca wysyłanie do niej. Pamiętaj, że identyfikatory instalacji Firebase (FID) są zarządzane przez usługę instalacji Firebase (FIS), a nie przez FCM. W rzadkich przypadkach, gdy urządzenie ponownie się połączy, a aplikacja zostanie otwarta po usunięciu jej rejestracji, aplikacja kliencka zarejestruje się ponownie w FCM, używając identyfikatora FID pobranego z FIS. Pamiętaj, że identyfikator FID może się zmienić. Szczegółowe informacje o tym, kiedy identyfikatory FID są ponownie wydawane, znajdziesz w artykule Zarządzanie instalacjami Firebase.

Na innych platformach, takich jak iOS, FCM korzysta z podstawowej usługi push (np. APNs), która nie ma takiego samego 270-dniowego okresu ważności opartego na braku aktywności. Zalecamy proaktywne utrzymywanie aktualności rejestracji i usuwanie nieaktualnych.

Podstawowe sprawdzone metody

W każdej aplikacji, która używa interfejsów API FCM do automatycznego tworzenia żądań wysyłania, należy stosować pewne podstawowe praktyki. Najważniejsze sprawdzone metody to:

  • Pobierz identyfikatory instalacji Firebase (FID) z FCM i zapisz je na serwerze aplikacji. Ważną rolą serwera jest śledzenie zarejestrowanych identyfikatorów FID każdego klienta i prowadzenie aktualnej listy aktywnych identyfikatorów FID. Zdecydowanie zalecamy wdrożenie sygnatury czasowej rejestracji w bazie danych i aktualizowanie jej przy każdym przesłaniu rejestracji.
  • Utrzymuj aktualność rejestracji i usuwaj nieaktualne. Oprócz usuwania rejestracji, które FCM nie uważa już za prawidłowe, możesz monitorować inne oznaki, że rejestracje stały się nieaktualne, i usuwać je proaktywnie. W tym przewodniku omawiamy kilka sposobów na osiągnięcie tego celu.

Pobieranie i przechowywanie identyfikatorów instalacji Firebase

Przy pierwszym uruchomieniu aplikacji pakiet SDK FCM rejestruje instancję aplikacji w FCM i zwraca identyfikator instalacji Firebase (FID). Jest to identyfikator, który musisz uwzględnić w żądaniach wysyłania kierowanego z interfejsu API lub użyć w przypadku subskrypcji tematów.

Zdecydowanie zalecamy zapisywanie identyfikatora FID na serwerze aplikacji wraz z sygnaturą czasową przy każdym przesłaniu. Dzięki aktualizowaniu sygnatury czasowej przy każdym żądaniu przesyłania serwer wie, kiedy instancja aplikacji została ostatnio otwarta i pomyślnie zsynchronizowana z backendem FCM.

W zależności od tego, czy automatyczna inicjalizacja jest włączona czy wyłączona (lub nieobsługiwana), rejestrację i aktualizacje należy obsługiwać w następujący sposób:

  • (Zalecane) Gdy automatyczna inicjalizacja jest włączona: pakiet SDK automatycznie dba o aktualność rejestracji i monitoruje zmiany. Wywołanie zwrotne onRegistered() jest wywoływane regularnie podczas rutynowych synchronizacji podczas uruchamiania aplikacji, a także w przypadku zmian FID. Wystarczy zaimplementować to wywołanie zwrotne, aby przesłać identyfikator FID na serwer i zapisać bieżącą sygnaturę czasową.
  • Gdy automatyczna inicjacja jest wyłączona: wywołanie zwrotne onRegistered() nie zostanie automatycznie wywołane na początku. Aby śledzić rejestracje i je aktualizować, wywołaj register() podczas uruchamiania aplikacji, np. na Androidzie w onCreate() głównej aktywności. Udane wywołanie uruchamia proces rejestracji FCM przy użyciu identyfikatora FID i dostarcza go do wywołania zwrotnego onRegistered(), co umożliwia aplikacji przesłanie identyfikatora FID i zaktualizowanie sygnatury czasowej na serwerze.

Przykład: przechowywanie identyfikatorów FID i sygnatur czasowych w Cloud Firestore

Możesz na przykład użyć Cloud Firestore do przechowywania identyfikatorów FID w kolekcji o nazwie fcmRegistrations. Każdy identyfikator dokumentu w kolekcji odpowiada identyfikatorowi użytkownika, a dokument przechowuje bieżący identyfikator FID i sygnaturę czasową ostatniej aktualizacji. Użyj funkcji set, jak pokazano w tym przykładzie w Kotlinie:

private fun sendRegistrationToServer(installationId: String?) {
    // If you're running your own server, call API to send registration details and today's date for the user

    // Example shown uses Firestore
    // Add FID and timestamp to Firestore for this user
    val deviceFid = hashMapOf(
        "installationId" to installationId,
        "timestamp" to FieldValue.serverTimestamp(),
    )
    // Get user ID from Firebase Auth or your own server
    Firebase.firestore.collection("fcmRegistrations").document("myuserid")
        .set(deviceFid)
}

Za każdym razem, gdy identyfikator instalacji Firebase zostanie zarejestrowany lub zaktualizowany, wywoływane jest wywołanie zwrotne onRegistered(). Zaimplementuj to wywołanie zwrotne, aby przesłać identyfikator FID i zaktualizować sygnaturę czasową:

override fun onRegistered(installationId: String) {
    Log.d(TAG, "Registered installation ID: $installationId")

    // Send the Firebase Installation ID (FID) to your app server. Your app
    // server should save the FID and update the timestamp upon receipt.
    sendRegistrationToServer(installationId)
}

W przypadkach, gdy automatyczna inicjalizacja jest wyłączona, wywołaj register() podczas uruchamiania aplikacji (np. w onCreate()), aby aktywować proces rejestracji i dostarczanie identyfikatora FID przez onRegistered():

// Trigger manual registration if auto-initialization is turned off.
FirebaseMessaging.getInstance().register()
    .addOnCompleteListener(this) { task ->
        if (task.isSuccessful) {
            // The registration callback onRegistered() will be invoked with the current FID.
        } else {
            Log.w(TAG, "Failed to register with Firebase Cloud Messaging", task.exception)
        }
    }

Utrzymywanie aktualności rejestracji i usuwanie nieaktualnych rejestracji

Określenie, czy rejestracja jest aktualna czy nie, nie zawsze jest proste. Aby uwzględnić wszystkie przypadki, należy przyjąć próg, po przekroczeniu którego rejestracje będą uznawane za nieaktualne. Domyślnie FCM uznaje rejestrację za nieaktualną, jeśli instancja aplikacji nie połączyła się przez miesiąc. Każda rejestracja starsza niż miesiąc prawdopodobnie dotyczy nieaktywnego urządzenia. W przeciwnym razie aktywne urządzenie odświeżyłoby rejestrację.

W zależności od przypadku użycia miesiąc może być zbyt krótkim lub zbyt długim okresem, więc to Ty musisz określić kryteria, które będą dla Ciebie odpowiednie.

Wykrywanie nieprawidłowych odpowiedzi z backendu FCM

Pamiętaj, aby wykrywać nieprawidłowe odpowiedzi z usługi FCM i reagować na nie, usuwając ze swojego systemu wszystkie rejestracje, które są nieprawidłowe lub wygasły. W przypadku interfejsu HTTP v1 API te komunikaty o błędach mogą wskazywać, że żądanie wysłania było skierowane do nieprawidłowych lub wygasłych rejestracji:

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

Jeśli masz pewność, że ładunek wiadomości jest prawidłowy, i otrzymasz jedną z tych odpowiedzi w przypadku rejestracji docelowej, możesz bezpiecznie usunąć rekord tej rejestracji, ponieważ nie będzie już ważny. Aby na przykład usunąć nieprawidłowe rejestracje z Cloud Firestore, możesz wdrożyć i uruchomić funkcję podobną do tej:

        // Firebase Installation ID comes from the client FCM SDKs
        const firebaseInstallationId = 'YOUR_FIREBASE_INSTALLATION_ID';

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

        // Send message to device with provided Firebase Installation ID
        getMessaging().send(message)
        .then((response) => {
            // Response is a message ID string.
        })
        .catch((error) => {
            // Delete registration for user if error code is UNREGISTERED or INVALID_ARGUMENT.
            if (error.errorCode == "messaging/registration-token-not-registered") {
                // If you're running your own server, call API to delete the registration for the user
                // Example shown uses Firestore
                // Get user ID from Firebase Auth or your own server
                Firebase.firestore.collection("fcmRegistrations").document(user.uid).delete()
            }
        });

FCM zwraca nieprawidłową odpowiedź, jeśli rejestracja urządzenia z Androidem wygasła po 270 dniach braku aktywności lub jeśli klient wyraźnie wyrejestrował urządzenie. Jeśli chcesz dokładniej śledzić nieaktualność zgodnie z własnymi definicjami, możesz proaktywnie usuwać nieaktualne rejestracje.

Regularne aktualizowanie rejestracji

Niezależnie od tego, czy rejestracje są oparte na identyfikatorach FID czy starszych tokenach rejestracji, serwer powinien zawsze aktualizować sygnaturę czasową rejestracji w bazie danych przy każdym żądaniu przesłania. Ta sygnatura czasowa działa jako sygnał instalacji aplikacji, informując, że klient pomyślnie otworzył aplikację i zsynchronizował ją z backendem FCM. W zależności od używanych interfejsów API wdróż odpowiednią strategię:

W przypadku aplikacji klienckich korzystających z interfejsów API FID nie musisz planować okresowych zadań w tle w aplikacji klienckiej, aby pobierać lub odświeżać rejestracje. Pakiet SDK automatycznie dba o odświeżanie w ramach automatycznej inicjalizacji, regularnie dostarczając prawidłowy bieżący identyfikator FID do wywołania zwrotnego onRegistered() podczas rutynowych synchronizacji przy uruchamianiu aplikacji.

Aby serwer był aktualny, wdróż strategie przesyłania podczas uruchamiania opisane w artykule Pobieranie i przechowywanie identyfikatorów instalacji Firebase:

  • Włączona automatyczna inicjalizacja: pakiet SDK automatycznie dba o to, aby podczas rutynowych synchronizacji przy uruchamianiu aplikacji na serwer był wysyłany najnowszy identyfikator FID.
  • Automatyczna inicjalizacja jest wyłączona lub nieobsługiwana: wywołaj register() podczas uruchamiania aplikacji (np. na Androidzie w głównej aktywności onCreate()), aby wymusić sekwencję rejestracji i wywołać dostarczenie FID do wywołania zwrotnego onRegistered().

Te strategie gwarantują, że serwer zawsze ma najnowszy aktywny identyfikator FID i może automatycznie przywracać nieudane przesyłanie, dzięki czemu aplikacja jest bardzo odporna na błędy.

Wycofane interfejsy API tokenów rejestracji

Jeśli używasz starszych tokenów rejestracji, pakiet SDK klienta nie zarządza automatycznie odświeżeniami podczas rutynowych synchronizacji. Dlatego zalecamy okresowe pobieranie i aktualizowanie wszystkich tokenów rejestracji na serwerze. Wymagania:

  • Dodaj logikę aplikacji w aplikacji klienckiej, aby pobrać bieżący token za pomocą odpowiedniego wywołania interfejsu API (np. token(completion): na platformach Apple lub getToken() na Androidzie), a następnie wyślij bieżący token na serwer aplikacji w celu zapisania (ze znacznikiem czasu). Może to być comiesięczne zadanie skonfigurowane tak, aby obejmowało wszystkich klientów lub wszystkie tokeny.
  • Dodaj logikę serwera, aby aktualizować sygnaturę czasową tokena w regularnych odstępach czasu, niezależnie od tego, czy token się zmienił.

Przykład logiki Androida do aktualizowania starszych tokenów za pomocą WorkManagera znajdziesz w artykule Zarządzanie tokenami Komunikacji w chmurze na blogu Firebase.

Niezależnie od tego, jaki wzorzec czasowy stosujesz, pamiętaj o okresowym aktualizowaniu tokenów. Częstotliwość aktualizacji raz w miesiącu zapewnia dobrą równowagę między wpływem na baterię a wykrywaniem nieaktywnych tokenów rejestracji. Dzięki temu odświeżeniu masz też pewność, że każde urządzenie, które stanie się nieaktywne, odświeży swoją rejestrację, gdy znów będzie aktywne. Nie ma potrzeby odświeżania częściej niż raz w tygodniu.

Usuwanie nieaktualnych rejestracji

Zanim wyślesz wiadomości na urządzenie, upewnij się, że sygnatura czasowa rejestracji urządzenia mieści się w okresie nieaktualności. Możesz na przykład wdrożyć Cloud Functions for Firebase, aby codziennie sprawdzać, czy sygnatura czasowa mieści się w określonym okresie nieaktualności, np. const EXPIRATION_TIME = 1000 * 60 * 60 * 24 * 30;, a następnie usuwać nieaktualne rejestracje:

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

Anulowanie subskrypcji tematów przez nieaktywne rejestracje

Jeśli używasz tematów, możesz też anulować subskrypcję nieaktualnych rejestracji w tematach, które subskrybują. Wymaga to wykonania 2 czynności:

  1. Aplikacja powinna ponownie subskrybować tematy za każdym razem, gdy zmieni się identyfikator instalacji Firebase (FID). Dzięki temu subskrypcje pojawią się automatycznie, gdy aplikacja znów stanie się aktywna.
  2. Jeśli instancja aplikacji jest nieaktywna przez miesiąc (lub przez okres nieaktywności określony przez Ciebie), należy anulować jej subskrypcję tematów za pomocą pakietu SDK Firebase Admin, aby usunąć mapowanie identyfikatora instalacji Firebase na temat z backendu FCM.

Korzyścią z tych 2 kroków jest to, że rozsyłanie będzie przebiegać szybciej, ponieważ będzie mniej nieaktualnych rejestracji, do których trzeba rozsyłać wiadomości, a nieaktualne instancje aplikacji będą automatycznie ponownie subskrybować, gdy znów staną się aktywne.

Pomiar skuteczności dostarczania

Aby uzyskać jak najdokładniejszy obraz dostarczania wiadomości, najlepiej wysyłać wiadomości tylko do aktywnie używanych instancji aplikacji. Jest to szczególnie ważne, jeśli regularnie wysyłasz wiadomości do tematów z dużą liczbą subskrybentów. Jeśli część z nich jest nieaktywna, może to mieć z czasem znaczący wpływ na statystyki dostarczania.

Zanim zaczniesz kierować wiadomości na instancję aplikacji, weź pod uwagę te kwestie:

  • Czy Google Analytics, dane zarejestrowane w BigQuery lub inne sygnały śledzenia wskazują, że rejestracja jest aktywna?
  • Czy poprzednie próby dostarczenia nie powiodły się w określonym czasie?
  • Czy identyfikator instalacji Firebase został zaktualizowany na Twoich serwerach w ciągu ostatniego miesiąca?
  • Czy w przypadku urządzeń z Androidem interfejs FCM Data API zgłasza wysoki odsetek niepowodzeń dostarczania wiadomości z powodu błędu droppedDeviceInactive?

Więcej informacji o dostarczaniu znajdziesz w artykule Informacje o dostarczaniu wiadomości.