FCM kayıt jetonu yönetimi için en iyi uygulamalar

Gönderme isteklerini programatik olarak oluşturmak için FCM API'lerini kullanıyorsanız zaman içinde eski kayıt jetonlarına sahip etkin olmayan cihazlara mesaj göndererek kaynak israf ettiğinizi fark edebilirsiniz. Bu durum, Firebase konsolunda raporlanan mesaj yayını verilerini veya BigQuery'ye aktarılan verileri etkileyebilir. Bu durumda, yayın oranlarında önemli (ancak aslında geçerli olmayan) bir düşüş görülebilir. Bu kılavuzda, etkili ileti hedefleme ve geçerli teslimat raporlaması sağlamak için uygulayabileceğiniz bazı önlemler ele alınmaktadır.

Eski ve süresi dolmuş kayıt jetonları

Eski kayıt jetonları, bir aydan uzun süredir FCM'e bağlanmayan etkin olmayan cihazlarla ilişkili jetonlardır. Zaman geçtikçe cihazın FCM'e tekrar bağlanma olasılığı azalır. Bu eski jetonlar için mesaj gönderme ve konu dağıtımlarının teslim edilme olasılığı yoktur.

Bir jetonun eski olmasının birkaç nedeni vardır. Örneğin, jetonun ilişkili olduğu cihaz kaybolabilir, imha edilebilir veya depoya kaldırılıp unutulabilir.

Eski jetonlar 270 gün boyunca etkin olmadığında FCM bunları geçersiz jetonlar olarak kabul eder. Bir jetonun süresi dolduktan sonra FCM, jetonu geçersiz olarak işaretler ve jetona gönderilen mesajları reddeder. Ancak FCM, cihazın tekrar bağlanıp uygulamanın açılması gibi nadir durumlarda uygulama örneği için yeni bir jeton yayınlar.

Temel en iyi uygulamalar

Programatik olarak istek göndermek için FCM API'lerini kullanan tüm uygulamalarda uygulamanız gereken bazı temel uygulamalar vardır. En iyi uygulamalardan bazıları şunlardır:

  • FCM'dan kayıt jetonlarını alıp sunucunuzda saklayın. Sunucunun önemli bir rolü, her istemcinin jetonunu takip etmek ve etkin jetonların güncel bir listesini tutmaktır. Kodunuza ve sunucularınıza jeton zaman damgası uygulamanızı ve bu zaman damgasını düzenli aralıklarla güncellemenizi önemle tavsiye ederiz.
  • Jetonların güncelliğini koruyun ve eski jetonları kaldırın. FCM'nin artık geçerli olarak kabul etmediği jetonları kaldırmanın yanı sıra, jetonların eskidiğine dair diğer işaretleri de izlemek ve bunları proaktif olarak kaldırmak isteyebilirsiniz. Bu kılavuzda, bu hedefe ulaşmak için kullanabileceğiniz seçeneklerden bazıları ele alınmaktadır.

Kayıt jetonlarını alma ve saklama

Uygulamanız ilk kez başlatıldığında FCM SDK'sı, istemci uygulama örneği için bir kayıt jetonu oluşturur. Bu, API'den gelen hedeflenmiş gönderme isteklerine eklemeniz veya konuları hedeflemek için konu aboneliklerine eklemeniz gereken jetondur.

Uygulamanızın ilk başlatmada bu jetonu almasını ve bir zaman damgasıyla birlikte uygulama sunucunuza kaydetmesini önemle tavsiye ederiz. Bu zaman damgası, FCM SDK'ları tarafından size sağlanmadığından kodunuz ve sunucularınız tarafından uygulanmalıdır.

Ayrıca, jetonu sunucuya kaydetmeniz ve zaman damgasını her değiştiğinde güncellemeniz önemlidir. Örneğin:

  • Uygulama yeni bir cihaza geri yüklendiğinde
  • Kullanıcı uygulamayı kaldırır veya yeniden yükler
  • Kullanıcı uygulama verilerini temizler
  • FCM mevcut jetonunun süresinin dolmasından sonra uygulama tekrar etkin hale gelir

Örnek: store tokens and timestamps in Cloud Firestore

Örneğin, jetonları fcmTokens adlı bir koleksiyonda depolamak için Cloud Firestore kullanabilirsiniz. Koleksiyondaki her belge kimliği bir kullanıcı kimliğine karşılık gelir ve belge, mevcut kayıt jetonunu ve son güncellenme zaman damgasını depolar. set işlevini bu Kotlin örneğinde gösterildiği gibi kullanın:

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

Her jeton alındığında sendTokenToServer çağrılarak Cloud Firestore içinde saklanır:

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

Jetonların güncelliğini koruma ve eski jetonları kaldırma

Bir jetonun yeni mi yoksa eski mi olduğunu belirlemek her zaman kolay değildir. Tüm durumları kapsayacak şekilde, jetonları ne zaman eski olarak değerlendireceğinize dair bir eşik belirlemeniz gerekir. Varsayılan olarak FCM, uygulama örneği bir ay boyunca bağlanmamışsa jetonu eski olarak kabul eder. Bir aydan eski jetonlar muhtemelen etkin olmayan cihazlara aittir. Etkin cihazlar jetonlarını yeniler.

Kullanım alanınıza bağlı olarak bir ay çok kısa veya çok uzun olabilir. Bu nedenle, sizin için uygun olan ölçütleri belirlemek size bağlıdır.

FCM arka ucundan geçersiz jeton yanıtlarını algılama

FCM tarafından gönderilen geçersiz jeton yanıtlarını algıladığınızdan ve geçersiz olduğu veya süresi dolduğu bilinen tüm kayıt jetonlarını sisteminizden silerek yanıt verdiğinizden emin olun. HTTP v1 API'de aşağıdaki hata mesajları, gönderme isteğinizin geçersiz veya süresi dolmuş jetonları hedeflediğini gösterebilir:

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

Mesaj yayının geçerli olduğundan eminseniz ve hedeflenen jeton için bu yanıtlardan birini alırsanız bu jetonla ilgili kaydınızı silebilirsiniz. Bu jeton bir daha geçerli olmayacak. Örneğin, Cloud Firestore kaynağındaki geçersiz jetonları silmek için aşağıdaki gibi bir işlev dağıtıp çalıştırabilirsiniz:

    // 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 yalnızca bir jetonun geçerlilik süresi 270 gün sonra sona ererse veya bir istemci açıkça kaydını iptal ederse geçersiz jeton yanıtı döndürür. Eskiliği kendi tanımlarınıza göre daha doğru bir şekilde izlemeniz gerekiyorsa proaktif olarak eski kayıt jetonlarını kaldırabilirsiniz.

Jetonları düzenli olarak güncelleme

Sunucunuzdaki tüm kayıt jetonlarını düzenli olarak almanızı ve güncellemenizi öneririz. Bunun için:

  • İstemci uygulamanıza, uygun API çağrısını (ör. Apple platformları için token(completion): veya Android için getToken()) kullanarak mevcut jetonu almak ve ardından mevcut jetonu depolanması için uygulama sunucunuza göndermek (zaman damgasıyla) üzere uygulama mantığı ekleyin. Bu, tüm istemcileri veya jetonları kapsayacak şekilde yapılandırılmış aylık bir iş olabilir.
  • Jetonun değişip değişmediğinden bağımsız olarak jetonun zaman damgasını düzenli aralıklarla güncellemek için sunucu mantığı ekleyin.

WorkManager'ı kullanarak jetonları güncellemeye yönelik Android mantığı örneği için Firebase blogundaki Cloud Messaging Jetonlarını Yönetme başlıklı makaleyi inceleyin.

Hangi zamanlama düzenini izlerseniz izleyin jetonları düzenli olarak güncellediğinizden emin olun. Ayda bir güncelleme sıklığı, pil üzerindeki etki ile etkin olmayan kayıt jetonlarının algılanması arasında iyi bir denge sağlar. Bu yenilemeyi yaparak, etkinliği durdurulan cihazların tekrar etkinleştirildiğinde kayıtlarının yenilenmesini de sağlarsınız. Yenilemeyi haftalıktan daha sık yapmanın bir faydası yoktur.

Eski kayıt jetonlarını kaldırma

Bir cihaza mesaj göndermeden önce, cihazın kayıt jetonunun zaman damgasının eskilik aralığı içinde olduğundan emin olun. Örneğin, zaman damgasının const EXPIRATION_TIME = 1000 * 60 * 60 * 24 * 30; gibi tanımlanmış bir eskilik aralığı içinde olduğundan emin olmak için günlük kontrol çalıştırmak üzere Cloud Functions for Firebase'ü uygulayabilir ve ardından eski jetonları kaldırabilirsiniz:

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

Eski jetonları konulardan çıkarma

Konu kullanıyorsanız abone oldukları konulardaki eski jetonların kaydını da silebilirsiniz. Bu işlem iki adımdan oluşur:

  1. Uygulamanız, konulara ayda bir kez ve kayıt jetonu değiştiğinde yeniden abone olmalıdır. Bu, bir uygulama tekrar etkin olduğunda aboneliklerin otomatik olarak yeniden göründüğü kendi kendini iyileştiren bir çözüm oluşturur.
  2. Bir uygulama örneği bir ay boyunca (veya kendi eskilik aralığınız) etkin değilse FCM arka ucundan jetonla konu eşlemesini silmek için Firebase Admin SDK'sını kullanarak uygulamanın konu aboneliğini iptal etmeniz gerekir.

Bu iki adımın avantajı, dağıtılacak eski jeton sayısı daha az olduğu için dağıtımlarınızın daha hızlı gerçekleşmesi ve eski uygulama örnekleriniz tekrar etkinleştirildiğinde otomatik olarak yeniden abone olmasıdır.

Yayınlama başarısını ölçme

Mesaj yayını hakkında en doğru bilgileri almak için mesajları yalnızca etkin olarak kullanılan uygulama örneklerine göndermeniz önerilir. Bu, özellikle çok sayıda abonesi olan konulara düzenli olarak mesaj gönderiyorsanız önemlidir. Bu abonelerin bir kısmı etkin değilse teslimat istatistikleriniz üzerinde zaman içinde önemli bir etkisi olabilir.

Mesajları jetona hedeflemeden önce şunları göz önünde bulundurun:

  • Google Analytics, BigQuery'de yakalanan veriler veya diğer izleme sinyalleri jetonun etkin olduğunu gösteriyor mu?
  • Önceki teslimat denemeleri bir süre boyunca sürekli olarak başarısız oldu mu?
  • Kayıt jetonu, sunucularınızda son bir ay içinde güncellendi mi?
  • Android cihazlarda FCM Veri API, droppedDeviceInactive nedeniyle ileti yayınlama hatalarının yüksek bir yüzdesini mi bildiriyor?

Teslimat hakkında daha fazla bilgi için Mesaj teslimini anlama başlıklı makaleyi inceleyin.