หากใช้ FCM API เพื่อสร้างคำขอแบบเป็นโปรแกรม คุณอาจสิ้นเปลืองทรัพยากรไปกับการส่งข้อความไปยังอุปกรณ์ที่ไม่มีการใช้งานซึ่งมีโทเค็นการลงทะเบียนเก่าเกินไป สถานการณ์นี้อาจส่งผลต่อข้อมูลการส่งข้อความที่รายงานในคอนโซล Firebase หรือข้อมูลที่ส่งออกไปยัง BigQuery ซึ่งทำให้อัตราการส่งข้อความลดลงอย่างมาก (แต่ไม่ถูกต้องจริง) คู่มือนี้กล่าวถึงมาตรการบางอย่างที่คุณสามารถใช้เพื่อช่วยให้การกำหนดเป้าหมายข้อความมีประสิทธิภาพและการรายงานการแสดงโฆษณาที่ถูกต้อง
โทเค็นการลงทะเบียนไม่มีอัปเดตและหมดอายุ
โทเค็นการลงทะเบียนที่ไม่มีการอัปเดตคือโทเค็นที่เชื่อมโยงกับอุปกรณ์ที่ไม่ได้ใช้งานซึ่งไม่ได้เชื่อมต่อกับ FCM นานกว่า 1 เดือน เมื่อเวลาผ่านไป อุปกรณ์จะเชื่อมต่อกับ FCM อีกครั้ง น้อยลงเรื่อยๆ การส่งและการ Fanout หัวข้อสําหรับโทเค็นที่ไม่มีอัปเดตเหล่านี้มีแนวโน้มที่จะไม่มีการส่งเลย
มีสาเหตุหลายประการที่ทำให้โทเค็นไม่มีอัปเดต เช่น อุปกรณ์ที่เชื่อมโยงกับโทเค็นอาจสูญหาย ถูกทำลาย หรืออยู่ในพื้นที่เก็บข้อมูลและถูกลืม
เมื่อโทเค็นที่ไม่มีความเคลื่อนไหวมีจำนวนถึง 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 และตอบกลับโดยลบโทเค็นการลงทะเบียนที่ทราบแล้วว่าไม่ถูกต้องหรือหมดอายุออกจากระบบ เมื่อใช้ HTTP v1 API ข้อความแสดงข้อผิดพลาดเหล่านี้อาจบ่งบอกว่าโทเค็นที่คุณส่งคำขอกำหนดเป้าหมายไม่ถูกต้องหรือหมดอายุ
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
ไม่ว่าคุณจะใช้รูปแบบการกำหนดเวลาแบบใด อย่าลืมอัปเดตโทเค็นเป็นระยะๆ ความถี่ในการอัปเดต 1 ครั้งต่อเดือนจะช่วยให้เกิดความสมดุลระหว่างการใช้งานแบตเตอรี่และการตรวจหาโทเค็นการลงทะเบียนที่ไม่ได้ใช้งาน เมื่อรีเฟรชแล้ว คุณจะมั่นใจได้ว่าอุปกรณ์ที่ไม่มีการใช้งานจะรีเฟรชการลงทะเบียนเมื่อกลับมาใช้งานอีกครั้ง การรีเฟรชให้บ่อยกว่าสัปดาห์ละครั้งก็ไม่มีประโยชน์อะไร
นำโทเค็นการจดทะเบียนที่ไม่มีการอัปเดตออก
ก่อนที่จะส่งข้อความไปยังอุปกรณ์ โปรดตรวจสอบว่าการประทับเวลาของโทเค็นการลงทะเบียนของอุปกรณ์นั้นอยู่ภายในกรอบเวลาที่ไม่มีการอัปเดต ตัวอย่างเช่น คุณอาจใช้ฟังก์ชัน 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 เดือน (หรือกรอบเวลาที่ไม่มีอัปเดตของคุณเอง) คุณควรยกเลิกการสมัครรับข้อมูลจากหัวข้อต่างๆ โดยใช้ Firebase Admin SDK เพื่อลบโทเค็นไปยังการแมปหัวข้อจากแบ็กเอนด์ FCM
ข้อดีของ 2 ขั้นตอนนี้คือ การ Fanout จะเกิดขึ้นเร็วขึ้นเนื่องจากมีโทเค็นเก่าให้กระจายข้อมูลน้อยลง และอินสแตนซ์แอปที่ไม่มีอัปเดตจะสมัครใช้บริการอีกครั้งโดยอัตโนมัติเมื่อกลับมาใช้งานอีกครั้ง
วัดความสำเร็จในการแสดงโฆษณา
เพื่อให้เห็นภาพของการส่งข้อความได้อย่างถูกต้องที่สุด วิธีที่ดีที่สุดคือการส่งข้อความไปยังอินสแตนซ์แอปที่ใช้งานอยู่เท่านั้น การทำเช่นนี้มีความสำคัญมาก โดยเฉพาะอย่างยิ่งหากคุณส่งข้อความถึงหัวข้อที่มีสมาชิกจำนวนมากอยู่เป็นประจำ หากสมาชิกบางส่วนไม่ได้ใช้งานจริงๆ ผลกระทบที่มีต่อสถิติการนำส่งอาจมีนัยสำคัญเมื่อเวลาผ่านไป
ก่อนที่จะกำหนดเป้าหมายข้อความไปยังโทเค็น โปรดพิจารณาสิ่งต่อไปนี้
- Google Analytics, ข้อมูลที่บันทึกไว้ใน BigQuery หรือสัญญาณการติดตามอื่นๆ บ่งชี้ว่าโทเค็นมีการใช้งานอยู่หรือไม่
- เคยพยายามนำส่งก่อนหน้านี้ไม่สำเร็จอย่างต่อเนื่องในช่วงระยะเวลาหนึ่งหรือไม่
- โทเค็นการลงทะเบียนได้รับการอัปเดตในเซิร์ฟเวอร์ของคุณในเดือนที่ผ่านมาหรือไม่
- สำหรับอุปกรณ์ Android นั้น FCM Data API
รายงานว่าพบเปอร์เซ็นต์ที่สูงในการส่งข้อความไม่สำเร็จเนื่องจาก
droppedDeviceInactive
หรือไม่
ดูข้อมูลเพิ่มเติมเกี่ยวกับการส่งข้อความได้ที่การทำความเข้าใจการส่งข้อความ