แนวทางปฏิบัติแนะนำสำหรับการจัดการโทเค็นการลงทะเบียน FCM

หากใช้ FCMAPI เพื่อสร้างคำขอส่งแบบเป็นโปรแกรม คุณอาจพบว่าเมื่อเวลาผ่านไป คุณกำลังสิ้นเปลืองทรัพยากรโดยการส่งข้อความไปยังอุปกรณ์ที่ไม่ได้ใช้งานซึ่งมีโทเค็นการลงทะเบียนที่ล้าสมัย สถานการณ์นี้อาจส่งผลต่อข้อมูลการนำส่งข้อความที่รายงานในคอนโซล Firebase หรือข้อมูลที่ส่งออกไปยัง BigQuery ซึ่งจะแสดงเป็นการลดลงอย่างมาก (แต่ไม่ถูกต้องจริง) ในอัตราการนำส่ง คำแนะนำนี้จะกล่าวถึงมาตรการบางอย่างที่คุณสามารถใช้เพื่อช่วยให้มั่นใจได้ว่าการกำหนดเป้าหมายข้อความจะมีประสิทธิภาพและมีการรายงานการนำส่งที่ถูกต้อง

โทเค็นการลงทะเบียนที่ล้าสมัยและหมดอายุ

โทเค็นการลงทะเบียนที่ล้าสมัยคือโทเค็นที่เชื่อมโยงกับอุปกรณ์ที่ไม่ได้ใช้งานซึ่งไม่ได้เชื่อมต่อกับ FCM เป็นเวลานานกว่า 1 เดือน เมื่อเวลาผ่านไป อุปกรณ์ก็จะมีโอกาสน้อยลงเรื่อยๆ ที่จะเชื่อมต่อกับ FCM อีกครั้ง ข้อความ ที่ส่งและการกระจายหัวข้อสำหรับโทเค็นที่ล้าสมัยเหล่านี้อาจไม่ได้รับการนำส่ง เลย

โทเค็นอาจหมดอายุได้จากหลายสาเหตุ เช่น อุปกรณ์ที่เชื่อมโยงโทเค็นอาจสูญหาย ถูกทำลาย หรือเก็บไว้และลืมไปแล้ว

เมื่อโทเค็นที่ล้าสมัยไม่มีการใช้งานเป็นเวลา 270 วัน FCM จะถือว่าโทเค็นเหล่านั้นเป็นโทเค็นที่หมดอายุ เมื่อโทเค็นหมดอายุ FCM จะทำเครื่องหมายว่าโทเค็นใช้งานไม่ได้และ ปฏิเสธการส่งไปยังโทเค็นนั้น อย่างไรก็ตาม FCM จะออกโทเค็นใหม่สำหรับอินสแตนซ์ของแอป ในกรณีที่อุปกรณ์เชื่อมต่ออีกครั้งและเปิดแอป ซึ่งเกิดขึ้นได้ยาก

แนวทางปฏิบัติแนะนำขั้นพื้นฐาน

มีแนวทางปฏิบัติพื้นฐานบางอย่างที่คุณควรปฏิบัติตามในแอปที่ใช้ FCM API เพื่อสร้างคำขอส่งแบบเป็นโปรแกรม แนวทางปฏิบัติแนะนำหลักๆ มีดังนี้

  • ดึงโทเค็นการลงทะเบียนจาก FCM และจัดเก็บไว้ในเซิร์ฟเวอร์ บทบาทสำคัญของเซิร์ฟเวอร์คือการติดตามโทเค็นของไคลเอ็นต์แต่ละราย และเก็บรายชื่อโทเค็นที่ใช้งานอยู่ซึ่งอัปเดตแล้ว เราขอแนะนำ ให้ใช้การประทับเวลาโทเค็นในโค้ดและเซิร์ฟเวอร์ของคุณ รวมถึงอัปเดต การประทับเวลานี้เป็นระยะๆ
  • รักษาโทเค็นให้เป็นเวอร์ชันล่าสุดและนำโทเค็นที่ไม่ได้ใช้แล้วออก นอกเหนือจาก การนำโทเค็นที่FCM ไม่ถือว่าใช้ได้อีกต่อไปออกแล้ว คุณอาจต้อง ตรวจสอบสัญญาณอื่นๆ ที่บ่งบอกว่าโทเค็นหมดอายุและนำออก อย่างรวดเร็ว คู่มือนี้จะกล่าวถึงตัวเลือกบางอย่างในการดำเนินการดังกล่าว

เรียกข้อมูลและจัดเก็บโทเค็นการลงทะเบียน

เมื่อเริ่มต้นแอปครั้งแรก FCM SDK จะสร้างโทเค็นการลงทะเบียน สำหรับอินสแตนซ์แอปไคลเอ็นต์ นี่คือโทเค็นที่คุณต้องรวมไว้ใน คำขอส่งที่กำหนดเป้าหมายจาก API หรือเพิ่มลงในการสมัครรับข้อมูลหัวข้อเพื่อกำหนดเป้าหมาย หัวข้อ

เราขอแนะนำอย่างยิ่งให้แอปของคุณเรียกโทเค็นนี้เมื่อเริ่มต้นครั้งแรกและบันทึกโทเค็นไว้ในเซิร์ฟเวอร์แอปพร้อมกับประทับเวลา การประทับเวลาต้อง ใช้โค้ดและเซิร์ฟเวอร์ของคุณ เนื่องจาก FCM SDK ไม่ได้ให้ข้อมูลนี้ แก่คุณ

นอกจากนี้ คุณควรบันทึกโทเค็นไว้ในเซิร์ฟเวอร์และอัปเดตการประทับเวลา ทุกครั้งที่มีการเปลี่ยนแปลง เช่น เมื่อเกิดกรณีต่อไปนี้

  • มีการกู้คืนแอปในอุปกรณ์เครื่องใหม่
  • ผู้ใช้ถอนการติดตั้งหรือติดตั้งแอปอีกครั้ง
  • ผู้ใช้ล้างข้อมูลแอป
  • แอปจะกลับมาทำงานอีกครั้งหลังจาก FCM ได้หมดอายุโทเค็นที่มีอยู่

ตัวอย่าง: จัดเก็บโทเค็นและแสตมป์เวลาใน 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 จะถือว่าโทเค็นหมดอายุหากอินสแตนซ์แอป ไม่ได้เชื่อมต่อเป็นเวลา 1 เดือน โทเค็นที่เก่ากว่า 1 เดือนมักจะเป็นอุปกรณ์ที่ไม่ได้ใช้งาน ส่วนอุปกรณ์ที่ใช้งานอยู่จะรีเฟรชโทเค็น

ระยะเวลา 1 เดือนอาจสั้นหรือยาวเกินไป ทั้งนี้ขึ้นอยู่กับกรณีการใช้งานของคุณ ดังนั้นคุณจึงต้องเป็นผู้กำหนดเกณฑ์ที่เหมาะกับคุณ

ตรวจหาการตอบกลับโทเค็นที่ไม่ถูกต้องจากแบ็กเอนด์ FCM

โปรดตรวจหาการตอบกลับโทเค็นที่ไม่ถูกต้องจาก FCM และตอบกลับโดย ลบโทเค็นการลงทะเบียนที่ทราบว่าไม่ถูกต้อง หรือหมดอายุแล้วออกจากระบบ ข้อความแสดงข้อผิดพลาดเหล่านี้อาจบ่งบอกว่าคำขอส่งของคุณกำหนดเป้าหมายไปยังโทเค็นที่ไม่ถูกต้องหรือหมดอายุ

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

หากคุณมั่นใจว่าเพย์โหลดของข้อความถูกต้องและคุณได้รับคำตอบใดคำตอบหนึ่งต่อไปนี้สำหรับโทเค็นเป้าหมาย คุณสามารถลบบันทึกโทเค็นนี้ได้ เนื่องจากโทเค็นนี้จะไม่มีวันถูกต้องอีก ตัวอย่างเช่น หากต้องการลบโทเค็นที่ไม่ถูกต้องออกจาก 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()
        }
    });

FCM จะส่งคืนการตอบกลับโทเค็นที่ไม่ถูกต้องก็ต่อเมื่อโทเค็นหมดอายุ หลังจาก 270 วัน หรือหากไคลเอ็นต์ยกเลิกการลงทะเบียนอย่างชัดเจน หากต้องการติดตามความล้าสมัยให้แม่นยำยิ่งขึ้นตามคำจำกัดความของคุณเอง คุณสามารถนำโทเค็นการลงทะเบียนที่ล้าสมัยออกได้ล่วงหน้า

อัปเดตโทเค็นเป็นประจำ

เราขอแนะนําให้คุณเรียกข้อมูลและอัปเดตโทเค็นการลงทะเบียนทั้งหมดเป็นระยะๆ ในเซิร์ฟเวอร์ โดยคุณต้องทำดังนี้

  • เพิ่มตรรกะของแอปในแอปไคลเอ็นต์เพื่อเรียกโทเค็นปัจจุบันโดยใช้การเรียก API ที่เหมาะสม (เช่น token(completion): สำหรับแพลตฟอร์ม Apple หรือ getToken() สำหรับ Android) จากนั้นส่งโทเค็นปัจจุบันไปยังเซิร์ฟเวอร์ของแอปเพื่อจัดเก็บ (พร้อมการประทับเวลา) ซึ่งอาจเป็นงานรายเดือนที่กำหนดค่าให้ครอบคลุมไคลเอ็นต์หรือโทเค็นทั้งหมด
  • เพิ่มตรรกะของเซิร์ฟเวอร์เพื่ออัปเดตการประทับเวลาของโทเค็นเป็นระยะๆ ไม่ว่าโทเค็นจะมีการเปลี่ยนแปลงหรือไม่ก็ตาม

ดูตัวอย่างตรรกะของ Android สำหรับการอัปเดตโทเค็นโดยใช้ WorkManager ได้ที่ การจัดการโทเค็น Cloud Messaging ในบล็อกของ Firebase

ไม่ว่าคุณจะใช้รูปแบบการกำหนดเวลาใด โปรดอย่าลืมอัปเดตโทเค็นเป็นระยะๆ ความถี่ในการอัปเดตเดือนละครั้งจะช่วยรักษาสมดุลที่ดีระหว่างผลกระทบต่อแบตเตอรี่ กับการตรวจหาโทเค็นการลงทะเบียนที่ไม่มีการใช้งาน การรีเฟรชนี้ยังช่วยให้มั่นใจได้ว่าอุปกรณ์ที่ไม่มีการใช้งานจะรีเฟรชการลงทะเบียนเมื่อกลับมาใช้งานอีกครั้ง การรีเฟรชบ่อยกว่าสัปดาห์ละครั้งไม่ก่อให้เกิดประโยชน์ใดๆ

นำโทเค็นการลงทะเบียนที่ล้าสมัยออก

ก่อนส่งข้อความไปยังอุปกรณ์ โปรดตรวจสอบว่าการประทับเวลาของโทเค็นการลงทะเบียนของอุปกรณ์อยู่ภายในระยะเวลาของหน้าต่างความล้าสมัย ตัวอย่างเช่น คุณ สามารถใช้ Cloud Functions for Firebase เพื่อเรียกใช้การตรวจสอบรายวันเพื่อให้แน่ใจว่า การประทับเวลาอยู่ภายในระยะเวลาของกรอบเวลาความล้าที่กำหนด เช่น const EXPIRATION_TIME = 1000 * 60 * 60 * 24 * 30; จากนั้นนำโทเค็นที่ล้าสมัยออกได้

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

ยกเลิกการสมัครรับโทเค็นที่ล้าสมัยจากหัวข้อ

หากใช้หัวข้อ คุณอาจต้องยกเลิกการลงทะเบียนโทเค็นที่ล้าสมัยจากหัวข้อ ที่โทเค็นเหล่านั้นสมัครรับข้อมูลไว้ด้วย โดยมี 2 ขั้นตอนดังนี้

  1. แอปควรสมัครรับหัวข้ออีกครั้งเดือนละครั้งและทุกครั้งที่โทเค็นการลงทะเบียนเปลี่ยนแปลง ซึ่งจะสร้างโซลูชันการซ่อมแซมตัวเอง โดยการสมัครใช้บริการจะปรากฏอีกครั้งโดยอัตโนมัติเมื่อแอปกลับมาใช้งานได้อีกครั้ง
  2. หากอินสแตนซ์แอปไม่ได้ใช้งานเป็นเวลา 1 เดือน (หรือช่วงเวลาที่ข้อมูลไม่เป็นปัจจุบันของคุณเอง) คุณควรยกเลิกการติดตามหัวข้อจากอินสแตนซ์นั้นโดยใช้ Firebase Admin SDK เพื่อลบการแมปโทเค็นกับหัวข้อออกจากแบ็กเอนด์ FCM

ประโยชน์ของ 2 ขั้นตอนนี้คือการกระจายข้อมูลจะเกิดขึ้นเร็วขึ้นเนื่องจากมีโทเค็นที่ล้าสมัยน้อยลงที่จะกระจายข้อมูล และอินสแตนซ์แอปที่ล้าสมัยจะสมัครรับข้อมูลอีกครั้งโดยอัตโนมัติเมื่อกลับมาใช้งานได้อีกครั้ง

วัดความสำเร็จในการนำส่ง

หากต้องการทราบภาพรวมการนำส่งข้อความที่แม่นยำที่สุด คุณควรส่งข้อความไปยังอินสแตนซ์แอปที่ใช้งานอยู่เท่านั้น ซึ่งมีความสำคัญอย่างยิ่งหากคุณส่งข้อความไปยังหัวข้อที่มีผู้ติดตามจำนวนมากเป็นประจำ เนื่องจากหากผู้ติดตามบางส่วนไม่มีการใช้งานจริง สถิติการนำส่งของคุณอาจได้รับผลกระทบอย่างมากเมื่อเวลาผ่านไป

ก่อนกำหนดเป้าหมายข้อความไปยังโทเค็น ให้พิจารณาสิ่งต่อไปนี้

  • Google Analytics, ข้อมูลที่บันทึกใน BigQuery หรือสัญญาณการติดตามอื่นๆ ระบุว่าโทเค็นใช้งานอยู่หรือไม่
  • การนำส่งครั้งก่อนๆ ล้มเหลวอย่างต่อเนื่องในช่วงระยะเวลาหนึ่งใช่ไหม
  • คุณได้อัปเดตโทเค็นการลงทะเบียนในเซิร์ฟเวอร์ในช่วงเดือนที่ผ่านมาหรือไม่
  • สำหรับอุปกรณ์ Android FCM Data API รายงานเปอร์เซ็นต์สูงของการนำส่งข้อความไม่สำเร็จเนื่องจาก droppedDeviceInactive หรือไม่

ดูข้อมูลเพิ่มเติมเกี่ยวกับการนำส่งได้ที่ ทำความเข้าใจการนำส่งข้อความ