Лучшие практики управления регистрационными токенами FCM

Если вы используете API-интерфейсы FCM для создания запросов на отправку программно, вы можете обнаружить, что со временем вы тратите ресурсы, отправляя сообщения на неактивные устройства с устаревшими маркерами регистрации. Эта ситуация может повлиять на данные о доставке сообщений, сообщаемые в консоли Firebase, или данные, экспортируемые в BigQuery, что проявляется в резком (но не действительном) падении скорости доставки. В этом руководстве обсуждаются некоторые меры, которые вы можете предпринять, чтобы обеспечить эффективный таргетинг сообщений и достоверные отчеты о доставке.

Основные рекомендации

Есть несколько основных рекомендаций, которым вы должны следовать в любом приложении, использующем FCM API для создания запросов на отправку программным путем. Основные лучшие практики:

  • Храните регистрационные токены на своем сервере. Важной ролью сервера является отслеживание токена каждого клиента и поддержание обновленного списка активных токенов. Мы настоятельно рекомендуем реализовать временную метку токена в коде и на ваших серверах и обновлять эту временную метку через регулярные промежутки времени.
  • Удалите сохраненные токены, которые устарели . Помимо удаления токенов в очевидных случаях недопустимых ответов на токен, вам, вероятно, потребуется отслеживать другие признаки того, что токен устарел. В этом руководстве обсуждаются некоторые варианты достижения этой цели.

Получение и хранение токенов регистрации

При первоначальном запуске приложения пакет SDK FCM создает маркер регистрации для экземпляра клиентского приложения. Это токен, который вы должны включать в целевые запросы на отправку из API или добавлять в подписки на темы для целевых тем.

Как указано в наших руководствах по настройке клиента, ваше приложение должно получить этот токен при первоначальном запуске и сохранить его на сервере приложений вместе с меткой времени . Эта отметка времени должна быть реализована вашим кодом и вашими серверами, поскольку она не предоставляется вам FCM SDK.

Кроме того, важно сохранять токен на сервере и обновлять временную метку всякий раз, когда она изменяется, например, когда:

  • Приложение восстановлено на новом устройстве
  • Пользователь удаляет/переустанавливает приложение
  • Пользователь очищает данные приложения.

Пример: хранить токены и временные метки в Cloud Firestore

Например, вы можете использовать Cloud Firestore для хранения токенов в коллекции fcmTokens . Каждый идентификатор документа в коллекции соответствует идентификатору пользователя, а документ хранит текущий маркер регистрации и его отметку времени последнего обновления. Используйте функцию set , как показано в этом примере 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)
    }

Всякий раз, когда токен извлекается, он сохраняется в Cloud Firestore путем вызова 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()
            }
        }

Обнаружение недопустимых ответов токена от серверной части FCM

Обязательно обнаружьте недопустимые ответы на токены от FCM и ответьте, удалив из своей системы все регистрационные токены, которые, как известно, недействительны. При использовании HTTP v1 API эти сообщения об ошибках могут указывать на то, что ваш запрос на отправку нацелен на устаревшие или недействительные токены:

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

Обратите внимание, что, поскольку INVALID_ARGUMENT выдается также в случаях проблем с полезной нагрузкой сообщения, он сигнализирует о недопустимом токене только в том случае, если полезная нагрузка полностью действительна. Дополнительные сведения см. в разделе ErrorCodes .

Если вы уверены, что полезная нагрузка сообщения действительна, и вы получаете любой из этих ответов для целевого маркера, безопасно удалить свою запись этого маркера, поскольку он больше никогда не будет действительным. Например, чтобы удалить недействительные токены из Cloud Firestore, вы можете развернуть и запустить следующую функцию:

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

Обеспечение актуальности токена регистрации

Определить, является ли токен свежим или устаревшим, не всегда просто. Чтобы охватить все случаи, вы должны установить порог, когда вы считаете токены устаревшими; наша рекомендация - два месяца. Любой токен старше двух месяцев, скорее всего, будет неактивным устройством; в противном случае активное устройство обновило бы свой токен.

Регулярно обновляйте токены

Мы рекомендуем вам периодически получать и обновлять все токены регистрации на вашем сервере. Это требует от вас:

  • Добавьте логику приложения в клиентское приложение, чтобы получить текущий токен с помощью соответствующего вызова API (например token(completion): для платформ Apple или getToken() для Android), а затем отправить текущий токен на сервер приложений для хранения (с отметкой времени ). Это может быть ежемесячное задание, настроенное для покрытия всех клиентов/токенов.
  • Добавьте логику сервера для регулярного обновления временной метки токена независимо от того, изменился ли токен.

Пример логики Android для обновления токенов с помощью WorkManager см. в разделе Управление токенами Cloud Messaging в блоге Firebase.

Какой бы временной паттерн вы ни использовали, обязательно периодически обновляйте токены. Частота обновления один раз в два месяца, вероятно, обеспечивает хороший баланс между воздействием батареи и обнаружением неактивных регистрационных токенов. Выполняя это обновление, вы также гарантируете, что любое неактивное устройство обновит свою регистрацию, когда снова станет активным. Нет смысла делать обновление чаще, чем раз в неделю.

Удалить устаревшие регистрационные токены

Перед отправкой сообщений на устройство убедитесь, что временная метка маркера регистрации устройства находится в пределах периода окна устаревания. Например, вы можете реализовать облачные функции для Firebase, чтобы запускать ежедневную проверку, чтобы убедиться, что отметка времени находится в пределах определенного периода окна устаревания, например const EXPIRATION_TIME = 1000 * 60 * 60 * 24 * 60; а затем удалите устаревшие токены:

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

Отписаться от устаревших токенов из тем

Еще одним соображением является управление подписками на темы для удаления устаревших токенов регистрации. Он включает в себя два шага:

  1. Ваше приложение должно повторно подписываться на темы один раз в месяц и/или при каждом изменении токена регистрации. Это формирует самовосстанавливающееся решение, в котором подписки автоматически появляются снова, когда приложение снова становится активным.
  2. Если экземпляр приложения не используется в течение 2 месяцев (или вашего собственного окна устаревания), вы должны отменить подписку на темы с помощью Firebase Admin SDK , чтобы удалить сопоставление токена/темы из бэкэнда FCM.

Преимущество этих двух шагов заключается в том, что ваши разветвления будут происходить быстрее, поскольку будет меньше устаревших токенов для разветвления, а ваши устаревшие экземпляры приложений будут автоматически повторно подписываться, как только они снова станут активными.

Измерение успеха доставки

Как правило, мы рекомендуем настраивать таргетинг сообщений на основе действий, наблюдаемых или зафиксированных в активно используемых экземплярах приложения. Это особенно важно, если вы регулярно отправляете сообщения в темы с большим количеством подписчиков; если часть этих подписчиков на самом деле неактивны, влияние на статистику доставки может быть значительным с течением времени.

Прежде чем нацеливать сообщения на токен, подумайте:

  • Указывают ли Google Analytics, данные, собранные в BigQuery, или другие сигналы отслеживания, что токен активен?
  • Были ли предыдущие попытки доставки постоянно неудачными в течение определенного периода времени?
  • Обновлялся ли токен регистрации на ваших серверах за последние два месяца?
  • Для устройств Android сообщает ли FCM Data API о высоком проценте сбоев доставки сообщений из-за droppedDeviceInactive ?

Дополнительные сведения о доставке см. в разделе Общие сведения о доставке сообщений .