אם אתם משתמשים בממשקי ה-API של FCM כדי ליצור בקשות שליחה באופן פרוגרמטי, יכול להיות שתגלו שבמהלך הזמן אתם מבזבזים משאבים על ידי שליחת הודעות למכשירים לא פעילים עם אסימוני רישום לא תקפים. המצב הזה יכול להשפיע על ההודעה נתוני מסירה שמדווחים במסוף Firebase או בנתונים שיוצאו ל-BigQuery, מוצגת כירידה חדה (אבל לא בפועל) בתעריפי ההצגה. הזה במדריך הזה מתוארות כמה מהצעדים שתוכלו לנקוט כדי להבטיח שהמסר יהיה יעיל טירגוט ודיווח תקין על הצגת מודעות.
טוקני רישום לא תקפים ותוקפם פג
אסימוני הרשמה לא תקפים הם אסימונים שמשויכים למכשירים לא פעילים שלא חוברו ל-FCM במשך יותר מחודש. ככל שעובר הזמן, הסיכוי שהמכשיר יתחבר שוב ל-FCM הולך ופוחת. סביר להניח שהודעות שנשלחות ואוספי נושאים של אסימונים לא תקינים לא יישלחו אף פעם.
יש כמה סיבות לכך שאסימון יכול להפוך למיושן. לדוגמה, יכול להיות שהמכשיר שאליו משויך האסימון אבד, הושמד או הועבר לאחסון ונשכח.
כשאסימונים לא פעילים מגיעים ל-270 יום של חוסר פעילות, FCM יתייחס אליהם אסימונים שפג תוקפם. אחרי שתוקף הטוקן פג, FCM מסמן אותו כלא תקף ומסרב לשלוח אליו הודעות. עם זאת, FCM מנפיק אסימון חדש עבור האפליקציה במקרה הנדיר שהמכשיר מתחבר שוב והאפליקציה נפתחת.
שיטות מומלצות בסיסיות
יש כמה שיטות בסיסיות שכדאי לפעול לפיהן בכל אפליקציה שבה משתמשים ממשקי API של FCM לבניית בקשות שליחה באופן פרוגרמטי. השיטות המומלצות העיקריות הן:
- אחזור אסימוני רישום מ-FCM ושמירתם בשרת אחד התפקידים החשובים של השרת הוא לעקוב אחרי האסימונים של כל לקוח ולשמור רשימה מעודכנת של האסימונים הפעילים. מומלץ מאוד להטמיע חותמת זמן של אסימון בקוד ובשרתים, ולעדכן את חותמת הזמן הזו במרווחי זמן קבועים.
- שומרים על עדכניות האסימון ומסירים אסימונים לא פעילים. בנוסף להסרת אסימונים ש-FCM כבר לא מחשיב כתקינים, כדאי לעקוב אחרי סימנים אחרים לכך שהאסימונים לא תקפים יותר ולהסיר אותם באופן יזום. המדריך הזה מתואר בחלק מהאפשרויות העומדות לרשותכם לצורך כך.
אחזור ואחסון של אסימוני רישום
בהפעלה הראשונית של האפליקציה, ה-SDK של FCM יוצר אסימון רישום למכונה של אפליקציית הלקוח. זהו האסימון שצריך לכלול בבקשות שליחה ממוקדות מה-API, או להוסיף למינוי לנושאים לצורך טירגוט נושאים.
מומלץ מאוד שהאפליקציה תאחזר את האסימון הזה במהלך ההפעלה הראשונית ותשמור לשרת האפליקציה לצד חותמת זמן. את חותמת הזמן הזו צריך להטמיע בקוד ובשרתים שלכם, כי היא לא מסופקת על ידי ערכות ה-SDK של FCM.
בנוסף, חשוב לשמור את האסימון בשרת ולעדכן את חותמת הזמן בכל פעם שהיא משתנה, למשל:
- האפליקציה משוחזרת במכשיר חדש
- המשתמש מסיר את האפליקציה או מתקין אותה מחדש
- המשתמש מנקה את נתוני האפליקציה
- האפליקציה חוזרת להיות פעילה אחרי שפג התוקף של 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 נחשב ללא פעיל אם האפליקציה שלו המכונה לא מחוברת כבר חודש. סביר להניח שכל אסימון מלפני יותר מחודש להיות מכשיר לא פעיל, אחרת, מכשיר פעיל היה מרענן את ב-Assistant.
בהתאם לתרחיש לדוגמה שלכם, יכול להיות שחודש אחד קצר מדי או ארוך מדי, ולכן אתם צריכים לקבוע את הקריטריונים שמתאימים לכם.
זיהוי תשובות לא חוקיות של אסימונים מהקצה העורפי של 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.
לא משנה איזה דפוס תזמון תבחרו, חשוב לעדכן את האסימונים מדי פעם. תדירות העדכון של פעם בחודש יוצרת איזון טוב בין השפעת הסוללה וזיהוי של אסימוני רישום לא פעילים. כך תוכלו לוודא גם שמכשיר שהפסיק לפעול יתעדכן כשהוא יהיה פעיל שוב. אין יתרון לרענון בתדירות גבוהה יותר מאשר פעם בשבוע.
הסרת טוקני רישום לא תקינים
לפני שליחת הודעות למכשיר, חשוב לוודא שחותמת הזמן של אסימון הרישום של המכשיר נמצאת בחלון הזמן של סטטוס הלא עדכני. לדוגמה, אפשר להטמיע את 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(); });
});
ביטול ההרשמה לאסימונים לא פעילים לנושאים
אם משתמשים בנושאים, כדאי גם לבטל את הרישום של אסימונים לא פעילים מהנושאים שאליהם הם מנויים. כדי לעשות זאת:
- האפליקציה שלכם אמורה להירשם מחדש לנושאים פעם בחודש, ובכל פעם שינויים באסימון הרישום. כך נוצר פתרון לתיקון עצמי, המינויים מופיעים מחדש באופן אוטומטי כשהאפליקציה הופכת לפעילה שוב.
- אם מכונה של אפליקציה לא פעילה במשך חודש (או חלון הזמן שלכם לסטלות), עליכם לבטל את ההרשמה שלה לנושאים באמצעות Firebase Admin SDK כדי למחוק את המיפוי של האסימון לנושאים בקצה העורפי של FCM.
היתרון של שני השלבים האלה הוא שהמעריצים שלך יתרחשו מהר יותר, יהיו פחות אסימונים לא פעילים שאפשר להשתמש בהם, ומופעי האפליקציה הלא פעילים שלכם להירשם מחדש באופן אוטומטי כשהם יהיו פעילים שוב.
מדידת ההצלחה של הצגת המודעות
כדי לקבל את התמונה המדויקת ביותר של מסירת ההודעה, מומלץ לשלוח רק הודעות למופעים של אפליקציות שנמצאות בשימוש פעיל. חשוב במיוחד לעשות זאת אם אתם שולחים הודעות באופן קבוע לנושאים עם מספר גדול של מנויים. אם חלק מהמנויים האלה לא פעילים בפועל, ההשפעה על נתוני ההעברה עשויה להיות משמעותית לאורך זמן.
לפני שמטרגטים הודעות לאסימון, כדאי להביא בחשבון את הנקודות הבאות:
- ביצוע האימות ב-Google Analytics, נתונים שתועדו ב-BigQuery או אותות מעקב אחרים לציין שהאסימון פעיל.
- האם ניסיונות קודמים למשלוח נכשלו באופן עקבי לאורך זמן?
- האם אסימון הרישום עודכן בשרתים שלך בחודש האחרון?
- במכשירי Android, האם FCM Data API מדווח על אחוז גבוה של כשלים בהעברת הודעות בגלל
droppedDeviceInactive
?
מידע נוסף על העברה זמין במאמר הסבר על העברת הודעות.