Praktik terbaik untuk pengelolaan token pendaftaran FCM

Jika menggunakan FCM API untuk membuat permintaan kirim secara terprogram, Anda mungkin mendapati bahwa, dari waktu ke waktu, Anda menyia-nyiakan resource dengan mengirimkan pesan ke perangkat yang tidak aktif dengan token pendaftaran yang sudah usang. Situasi ini dapat memengaruhi data pengiriman pesan yang dilaporkan di Firebase console atau data yang diekspor ke BigQuery, yang ditampilkan sebagai penurunan rasio penayangan yang drastis (tetapi tidak valid). Panduan ini berisi pembahasan mengenai beberapa langkah yang dapat Anda ambil untuk membantu memastikan penargetan pesan yang efisien dan pelaporan pengiriman yang valid.

Token pendaftaran yang sudah usang dan tidak berlaku lagi

Token pendaftaran yang sudah usang adalah token yang terkait dengan perangkat tidak aktif yang tidak terhubung ke FCM selama lebih dari sebulan. Seiring waktu, kemungkinan perangkat terhubung ke FCM lagi akan semakin menurun. Pengiriman pesan dan fanout topik untuk token usang ini kemungkinan tidak akan pernah dikirim.

Ada beberapa alasan mengapa token dapat menjadi usang. Misalnya, perangkat yang terkait dengan token hilang, hancur, atau dimasukkan ke dalam penyimpanan dan terlupakan.

Saat token yang sudah usang tidak aktif selama 270 hari, FCM akan menganggapnya sebagai token yang sudah tidak berlaku. Setelah masa berlaku token berakhir, FCM menandainya sebagai tidak valid dan menolak permintaan kirim ke alamat tersebut. Namun, FCM mengeluarkan token baru untuk instance aplikasi dalam kasus yang jarang terjadi ketika perangkat terhubung kembali dan aplikasi dibuka.

Praktik terbaik dasar

Ada beberapa praktik dasar yang harus Anda ikuti dalam aplikasi apa pun yang menggunakan FCM API untuk membuat permintaan kirim secara terprogram. Praktik terbaik utama adalah:

  • Ambil token pendaftaran dari FCM dan simpan di server Anda. Peran penting server adalah memantau setiap token klien dan menyimpan daftar terbaru token aktif. Sebaiknya terapkan stempel waktu token dalam kode serta server Anda, dan update stempel waktu ini secara berkala.
  • Pertahankan keaktualan token dan hapus token yang sudah tidak berlaku. Selain menghapus token yang tidak lagi dianggap valid oleh FCM, sebaiknya pantau indikator lain yang menandakan bahwa token telah menjadi usang dan menghapusnya secara proaktif. Panduan ini berisi pembahasan mengenai beberapa opsi yang Anda miliki untuk melakukannya.

Mengambil dan menyimpan token pendaftaran

Saat aplikasi dijalankan untuk pertama kalinya, FCM SDK akan menghasilkan token pendaftaran untuk instance aplikasi klien. Ini adalah token yang harus disertakan dalam permintaan kirim yang ditargetkan dari API, atau yang harus ditambahkan ke langganan topik untuk menarget topik.

Sebaiknya aplikasi Anda mengambil token ini saat pertama kali aplikasi dijalankan dan menyimpannya ke server aplikasi bersama stempel waktu. Stempel waktu ini harus diterapkan oleh kode dan server Anda, karena tidak disediakan oleh FCM SDK.

Selain itu, Anda harus menyimpan token ke server dan mengupdate stempel waktu setiap kali ada perubahan, seperti saat:

  • Aplikasi dipulihkan di perangkat baru
  • Pengguna meng-uninstal atau menginstal ulang aplikasi
  • Pengguna menghapus data aplikasi
  • Aplikasi menjadi aktif kembali setelah token yang ada untuk FCM tidak lagi tersedia.

Contoh: simpan token dan stempel waktu di Cloud Firestore

Misalnya, Anda dapat menggunakan Cloud Firestore untuk menyimpan token dalam koleksi yang disebut fcmTokens. Setiap ID dokumen dalam koleksi terkait dengan sebuah ID pengguna, dan dokumen menyimpan token pendaftaran saat ini beserta stempel waktunya yang terakhir diperbarui. Gunakan fungsi set seperti yang ditunjukkan dalam contoh Kotlin ini:

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

Setiap kali token diambil, token tersebut akan disimpan di Cloud Firestore dengan memanggil 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()
            }
        }

Mempertahankan keaktualan token dan menghapus token yang sudah tidak berlaku

Menentukan apakah sebuah token masih baru atau sudah usang tidak selalu mudah. Untuk mencakup semua kasus, Anda harus menerapkan batasan guna menentukan kapan token dianggap usang. Secara default, FCM menganggap token sudah usang jika instance aplikasinya belum terhubung selama sebulan. Token apa pun yang berusia lebih dari satu bulan kemungkinan merupakan perangkat yang tidak aktif. Perangkat yang aktif seharusnya telah memperbarui tokennya.

Tergantung pada kasus penggunaan Anda, satu bulan mungkin terlalu singkat atau terlalu lama, jadi terserah Anda untuk menentukan kriteria yang sesuai untuk Anda.

Mendeteksi respons token yang tidak valid dari backend FCM

Pastikan untuk mendeteksi respons token yang tidak valid dari FCM dan meresponsnya dengan menghapus token pendaftaran apa pun yang didapati tidak valid atau telah habis masa berlakunya dari sistem Anda. Dengan HTTP v1 API, pesan error ini dapat menunjukkan bahwa permintaan kirim Anda menarget token yang tidak valid atau sudah tidak berlaku lagi:

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

Jika Anda yakin bahwa payload pesan valid dan Anda menerima salah satu respons tersebut untuk token yang ditarget, Anda dapat menghapus data token ini karena tidak akan valid lagi. Misalnya, untuk menghapus token yang tidak valid dari Cloud Firestore, Anda dapat men-deploy dan menjalankan fungsi seperti berikut:

    // 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 hanya akan menampilkan respons token yang tidak valid jika masa berlaku token telah berakhir setelah 270 hari atau jika klien secara eksplisit membatalkan pendaftaran. Jika perlu melacak keusangan secara lebih akurat menurut definisi Anda sendiri, Anda dapat secara proaktif menghapus token pendaftaran yang sudah usang.

Mengupdate token secara rutin

Sebaiknya Anda mengambil dan mengupdate semua token pendaftaran di server Anda secara berkala. Hal ini mengharuskan Anda untuk:

  • Menambahkan logika aplikasi di aplikasi klien untuk mengambil token saat ini menggunakan panggilan API yang sesuai (seperti token(completion): untuk platform Apple atau getToken() untuk Android), lalu mengirimkan token saat ini ke server aplikasi Anda untuk disimpan (dengan stempel waktu). Tugas ini dapat dilakukan per bulan, dan dikonfigurasi untuk mencakup semua klien atau token.
  • Menambahkan logika server untuk mengupdate stempel waktu token secara berkala, terlepas dari apakah token telah berubah atau belum.

Untuk contoh logika Android dalam mengupdate token menggunakan WorkManager, lihat Mengelola Token Cloud Messaging di blog Firebase.

Apa pun pola pengaturan waktu yang Anda ikuti, pastikan untuk mengupdate token secara berkala. Frekuensi update satu kali per bulan akan menghasilkan keseimbangan antara dampak terhadap baterai dan pendeteksian token pendaftaran yang tidak aktif. Dengan melakukan update ini, Anda juga memastikan bahwa perangkat yang tidak aktif akan me-refresh pendaftarannya saat perangkat kembali aktif. Tidak ada gunanya melakukan refresh lebih dari seminggu sekali.

Menghapus token pendaftaran yang sudah tidak berlaku

Sebelum mengirim pesan ke perangkat, pastikan stempel waktu token pendaftaran perangkat berada dalam periode tenggang ketidakberlakuan. Misalnya, Anda dapat menerapkan Cloud Functions for Firebase untuk menjalankan pemeriksaan harian guna memastikan bahwa stempel waktu berada dalam periode tenggang ketidakberlakuan, seperti const EXPIRATION_TIME = 1000 * 60 * 60 * 24 * 30;, lalu menghapus token yang sudah usang:

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

Menghentikan langganan token usang pada topik

Jika menggunakan topik, Anda juga dapat membatalkan pendaftaran token usang dari topik langganannya. Hal ini melibatkan dua langkah:

  1. Aplikasi Anda harus kembali berlangganan topik sebulan sekali dan setiap kali token pendaftaran berubah. Ini akan membentuk solusi pemulihan diri, ketika langganan muncul kembali secara otomatis saat aplikasi kembali aktif.
  2. Jika instance aplikasi tidak aktif selama satu bulan (atau periode keusangan yang Anda tentukan sendiri), Anda harus menghentikan langganannya dari topik menggunakan Firebase Admin SDK untuk menghapus pemetaan token ke topik dari backend FCM.

Dua langkah ini bermanfaat mempercepat fanout karena jumlah token usang yang harus di-fanout menjadi lebih sedikit, dan instance aplikasi yang usang akan berlangganan kembali secara otomatis setelah aktif lagi.

Mengukur keberhasilan pengiriman

Untuk mendapatkan gambaran pengiriman pesan yang paling akurat, sebaiknya hanya kirim pesan ke instance aplikasi yang digunakan secara aktif. Hal ini sangat penting jika Anda rutin mengirim pesan ke topik dengan jumlah pelanggan yang besar. Jika sebagian pelanggan tersebut sebenarnya tidak aktif, dampaknya pada statistik pengiriman Anda dapat menjadi signifikan dari waktu ke waktu.

Sebelum menargetkan pesan ke token, pertimbangkan:

  • Apakah Google Analytics, data yang diambil di BigQuery, atau sinyal pelacakan lainnya menunjukkan bahwa token aktif?
  • Apakah upaya pengiriman sebelumnya gagal secara konsisten selama jangka waktu tertentu?
  • Apakah token pendaftaran telah diupdate di server Anda dalam sebulan terakhir?
  • Untuk perangkat Android, apakah FCM Data API melaporkan persentase kegagalan pengiriman pesan yang tinggi karena droppedDeviceInactive?

Untuk mendapatkan informasi lebih lanjut tentang pengiriman, baca artikel Memahami pengiriman pesan.