אם אתם משתמשים בממשקי API של FCM כדי ליצור בקשות שליחה באופן פרוגרמטי, יכול להיות שתגלו שעם הזמן אתם מבזבזים משאבים על שליחת הודעות למכשירים לא פעילים עם רישומים מיושנים. המצב הזה יכול להשפיע על נתוני מסירת ההודעות שמדווחים בFirebaseמסוף או על נתונים שמיוצאים ל-BigQuery, ויוצג כירידה דרמטית (אבל לא תקפה בפועל) בשיעורי המסירה. במדריך הזה נסביר על כמה פעולות שאפשר לבצע כדי לוודא שההודעות מטורגטות ביעילות ושהדיווח על המסירה תקין.
רישומים לא עדכניים ורישומים שפג תוקפם
רישומים לא עדכניים משויכים למכשירים לא פעילים שלא התחברו אל FCM במשך יותר מחודש. ככל שעובר הזמן, הסיכוי שהמכשיר יתחבר שוב ל-FCM קטן והולך. סביר להניח שהודעות שנשלחות ונושאים שמופצים לרישומים הישנים האלה לא יגיעו ליעד.
יש כמה סיבות לכך שרישום יכול להתיישן. לדוגמה, יכול להיות שהמכשיר שאליו משויך הרישום אבד, נהרס או אוחסן ונשכח.
ב-Android, אם רישום לא פעיל במשך 270 ימים, FCM מחשיב אותו כפג תוקף ומנקה אותו. אחרי שההרשמה פגה, FCM מסמן אותה כלא תקפה ודוחה שליחות אליה. חשוב לדעת שמזהי התקנה של Firebase (FID) מנוהלים על ידי שירות ההתקנות של Firebase (FIS), ולא על ידי FCM. במקרים הנדירים שבהם מכשיר מתחבר שוב והאפליקציה נפתחת אחרי שהרישום שלה נאסף כזבל, אפליקציית הלקוח נרשמת שוב ב-FCM באמצעות ה-FID שאוחזר מ-FIS. שימו לב שה-FID עשוי להשתנות. בניהול התקנות של Firebase מפורט מתי מנפיקים מחדש מזהי FID.
בפלטפורמות אחרות כמו iOS, FCM מסתמך על שירות ההתראות הבסיסי (למשל APNs), שבו אין תפוגה זהה של 270 ימים על סמך חוסר פעילות. מומלץ לשמור על עדכניות הרישום ולהסיר רישומים לא עדכניים.
שיטות מומלצות בסיסיות
יש כמה שיטות בסיסיות שחשוב לפעול לפיהן בכל אפליקציה שמשתמשת בממשקי FCM API כדי ליצור בקשות שליחה באופן פרוגרמטי. השיטות המומלצות העיקריות הן:
- אחזור מזהי ההתקנה של Firebase (FID) מ-FCM ואחסון שלהם בשרת האפליקציה. תפקיד חשוב של השרת הוא לעקוב אחרי מזהה ה-FID הרשום של כל לקוח ולשמור רשימה מעודכנת של מזהי FID פעילים. מומלץ מאוד להטמיע חותמת זמן של רישום במסד הנתונים, ולעדכן אותה בכל פעם שמעלים רישום.
- לשמור על עדכניות הרישומים ולהסיר רישומים לא פעילים. בנוסף להסרת רישומים ש-FCM כבר לא מחשיב כתקפים, כדאי לעקוב אחרי סימנים אחרים לכך שהרישומים כבר לא עדכניים ולהסיר אותם באופן יזום. במדריך הזה נסביר על כמה מהאפשרויות להשגת המטרה הזו.
אחזור ואחסון של מזהי התקנה ב-Firebase
בהפעלה הראשונית של האפליקציה, FCM SDK רושם את מופע האפליקציה ב-FCM ומחזיר מזהה התקנה של Firebase (FID). זהו המזהה שצריך לכלול בבקשות שליחה ממוקדות מה-API, או להשתמש בו למינויים לנושאים.
מומלץ מאוד לשמור את ה-FID בשרת האפליקציה לצד חותמת זמן בכל פעם שהוא מועלה. כשמעדכנים את חותמת הזמן בכל בקשת העלאה, השרת יודע מתי מופע האפליקציה נפתח לאחרונה וסונכרן בהצלחה עם הקצה העורפי של FCM.
בהתאם למצב ההפעלה של האתחול האוטומטי (מופעל, מושבת או לא נתמך), צריך לטפל ברישום ובעדכונים באופן הבא:
- (מומלץ) כשההפעלה האוטומטית מופעלת: ה-SDK מעדכן באופן אוטומטי את הרישום ועוקב אחרי שינויים. הקריאה החוזרת (callback)
onRegistered()מופעלת באופן קבוע בסנכרונים שגרתיים במהלך הפעלת האפליקציה, וגם כשמתרחשים שינויים ב-FID. פשוט מטמיעים את הקריאה החוזרת הזו כדי להעלות את ה-FID לשרת ולשמור את חותמת הזמן הנוכחית. - כשההפעלה האוטומטית מושבתת: הקריאה החוזרת
onRegistered()לא תופעל אוטומטית בהתחלה. כדי לעקוב אחרי הרשמות ולשמור אותן עדכניות, צריך להתקשר אלregister()בהפעלת האפליקציה. לדוגמה, ב-Android, ב-onCreate()של הפעילות הראשית. קריאה מוצלחת מפעילה את תהליך הרישום של FCM באמצעות ה-FID ומעבירה אותו לקריאה החוזרת (callback) שלonRegistered(), וכך האפליקציה יכולה להעלות את ה-FID ולעדכן את חותמת הזמן בשרת.
דוגמה: אחסון של מזהי חנויות וחותמות זמן ב-Cloud Firestore
לדוגמה, אפשר להשתמש ב-Cloud Firestore כדי לאחסן מזהי FID באוסף שנקרא fcmRegistrations. כל מזהה מסמך באוסף תואם למזהה משתמש, והמסמך מאחסן את ה-FID הנוכחי ואת חותמת הזמן של העדכון האחרון שלו. משתמשים בפונקציה set כמו בדוגמה הבאה ב-Kotlin:
private fun sendRegistrationToServer(installationId: String?) {
// If you're running your own server, call API to send registration details and today's date for the user
// Example shown uses Firestore
// Add FID and timestamp to Firestore for this user
val deviceFid = hashMapOf(
"installationId" to installationId,
"timestamp" to FieldValue.serverTimestamp(),
)
// Get user ID from Firebase Auth or your own server
Firebase.firestore.collection("fcmRegistrations").document("myuserid")
.set(deviceFid)
}
בכל פעם שמזהה התקנה ב-Firebase נרשם או מתעדכן בהצלחה, מופעלת קריאה חוזרת (callback) של onRegistered(). צריך להטמיע את הקריאה החוזרת הזו כדי להעלות את ה-FID ולעדכן את חותמת הזמן:
override fun onRegistered(installationId: String) {
Log.d(TAG, "Registered installation ID: $installationId")
// Send the Firebase Installation ID (FID) to your app server. Your app
// server should save the FID and update the timestamp upon receipt.
sendRegistrationToServer(installationId)
}
במקרים שבהם ההפעלה האוטומטית מושבתת, צריך להפעיל את register() בזמן הפעלת האפליקציה (למשל ב-onCreate()) כדי להפעיל את תהליך הרישום ואת שליחת ה-FID דרך onRegistered():
// Trigger manual registration if auto-initialization is turned off.
FirebaseMessaging.getInstance().register()
.addOnCompleteListener(this) { task ->
if (task.isSuccessful) {
// The registration callback onRegistered() will be invoked with the current FID.
} else {
Log.w(TAG, "Failed to register with Firebase Cloud Messaging", task.exception)
}
}
שמירה על עדכניות הרישום והסרת רישומים לא עדכניים
לא תמיד קל לקבוע אם רישום הוא עדכני או לא. כדי לכסות את כל המקרים, כדאי לקבוע סף שמעבר לו הרישומים נחשבים למיושנים. כברירת מחדל, FCM מחשיב רישום כלא עדכני אם מופע האפליקציה שלו לא התחבר במשך חודש. כל רישום שבוצע לפני יותר מחודש הוא כנראה של מכשיר לא פעיל. אחרת, הרישום של המכשיר הפעיל היה מתרענן.
בהתאם לתרחיש השימוש, יכול להיות שחודש אחד יהיה קצר מדי או ארוך מדי, ולכן אתם צריכים לקבוע את הקריטריונים שמתאימים לכם.
זיהוי תגובות לא תקפות מה-backend של FCM
חשוב לזהות תגובות פסולות מ-FCM ולהגיב על ידי מחיקת רישומים מהמערכת שלכם שידוע שהם פסולים או שתוקפם פג. בממשק ה-API של HTTP v1, הודעות השגיאה האלה עשויות להצביע על כך שבקשת השליחה שלכם כוונה לרישומים לא תקינים או שפג תוקפם:
UNREGISTERED(HTTP 404)INVALID_ARGUMENT(HTTP 400)
אם אתם בטוחים שהמטען הייעודי (payload) של ההודעה תקין ואתם מקבלים את אחת מהתגובות האלה לרישום ממוקד, אתם יכולים למחוק את הרשומה של הרישום הזה, כי הוא לא יהיה תקין יותר. לדוגמה, כדי למחוק רישומים לא חוקיים מ-Cloud Firestore, אפשר לפרוס ולהריץ פונקציה כמו זו:
// Firebase Installation ID comes from the client FCM SDKs
const firebaseInstallationId = 'YOUR_FIREBASE_INSTALLATION_ID';
const message = {
data: {
// Information you want to send inside of notification
},
fid: firebaseInstallationId
};
// Send message to device with provided Firebase Installation ID
getMessaging().send(message)
.then((response) => {
// Response is a message ID string.
})
.catch((error) => {
// Delete registration for user if error code is UNREGISTERED or INVALID_ARGUMENT.
if (error.errorCode == "messaging/registration-token-not-registered") {
// If you're running your own server, call API to delete the registration for the user
// Example shown uses Firestore
// Get user ID from Firebase Auth or your own server
Firebase.firestore.collection("fcmRegistrations").document(user.uid).delete()
}
});
FCM מחזיר תגובה לא תקפה אם הרישום של מכשיר Android פג אחרי 270 ימים של חוסר פעילות, או אם לקוח ביטל את הרישום באופן מפורש. אם אתם צריכים לעקוב אחרי נתונים ישנים בצורה מדויקת יותר בהתאם להגדרות שלכם, אתם יכולים להסיר מראש רישומים ישנים.
עדכון הרישומים באופן קבוע
לא משנה אם הרישומים מבוססים על מזהי FID או על אסימוני רישום מדור קודם, השרת תמיד צריך לעדכן את חותמת הזמן של הרישום במסד הנתונים בכל בקשת העלאה. חותמת הזמן הזו משמשת כאות להתקנת האפליקציה, ומאפשרת ללקוח לפתוח את האפליקציה בהצלחה ולסנכרן אותה עם הקצה העורפי של FCM. בהתאם לממשקי ה-API שבהם אתם משתמשים, צריך להטמיע את האסטרטגיה המתאימה:
ממשקי ה-API של מזהה ההתקנה ב-Firebase (מומלץ)
באפליקציות לקוח שמשתמשות בממשקי ה-API של ה-FID, לא צריך לתזמן משימות רקע תקופתיות באפליקציית הלקוח כדי לאחזר או לרענן את הרישומים. ערכת ה-SDK מטפלת באופן אוטומטי ברענונים במסגרת האתחול האוטומטי, ומספקת באופן קבוע את ה-FID הנוכחי הנכון לקריאה החוזרת (callback) של onRegistered() בסנכרונים שגרתיים במהלך הפעלות של האפליקציה.
כדי שהשרת יישאר מעודכן, צריך להטמיע את אסטרטגיות ההעלאה בזמן ההפעלה שמפורטות במאמר אחזור ואחסון של מזהי התקנות של Firebase:
- הפעלה אוטומטית מופעלת: ה-SDK מוודא אוטומטית שמזהה ה-FID העדכני ביותר נשלח לשרת שלכם בסנכרונים שגרתיים במהלך הפעלת האפליקציה.
- ההפעלה האוטומטית מושבתת או לא נתמכת: צריך להפעיל את
register()בזמן הפעלת האפליקציה (לדוגמה, ב-Android, בפעילות הראשיתonCreate()) כדי לאלץ את רצף הרישום ולהפעיל את העברת ה-FID אל פונקציית ה-callback שלonRegistered().
האסטרטגיות האלה מבטיחות שלשרת תמיד יהיה FID פעיל עדכני, והוא יוכל להתאושש מהעלאות שנכשלו באופן אוטומטי, מה שהופך את האפליקציה לעמידה מאוד.
ממשקי ה-API של טוקן הרישום שהוצאו משימוש
אם אתם משתמשים באסימוני רישום מדור קודם, ה-SDK של הלקוח לא מנהל באופן אוטומטי את הרענונים בסנכרונים שגרתיים. לכן מומלץ לאחזר ולעדכן מדי פעם את כל אסימוני הרישום בשרת. כדי לעשות את זה, צריך:
- מוסיפים לוגיקה של אפליקציה באפליקציית הלקוח כדי לאחזר את הטוקן הנוכחי באמצעות הקריאה המתאימה ל-API (למשל
token(completion):לפלטפורמות של אפל אוgetToken()ל-Android), ואז שולחים את הטוקן הנוכחי לשרת האפליקציה לאחסון (עם חותמת זמן). יכול להיות שמדובר בעבודה חודשית שהוגדרה כך שתכסה את כל הלקוחות או הטוקנים. - מוסיפים לוגיקה של שרת כדי לעדכן את חותמת הזמן של הטוקן במרווחי זמן קבועים, גם אם הטוקן לא השתנה.
דוגמה ללוגיקה של Android לעדכון טוקנים מדור קודם באמצעות WorkManager מופיעה במאמר ניהול טוקנים של העברת הודעות בענן בבלוג של Firebase.
לא משנה באיזה דפוס תזמון תבחרו, חשוב לעדכן את האסימונים מדי פעם. תדירות עדכון של פעם בחודש מאזנת היטב בין ההשפעה על הסוללה לבין זיהוי אסימוני רישום לא פעילים. בנוסף, הרענון הזה מבטיח שכל מכשיר שיהפוך ללא פעיל ירענן את הרישום שלו כשהוא יחזור להיות פעיל. אין טעם לרענן את הנתונים בתדירות גבוהה יותר מפעם בשבוע.
הסרת רישומים לא עדכניים
לפני ששולחים הודעות למכשיר, צריך לוודא שחותמת הזמן של רישום המכשיר נמצאת בטווח של חלון הזמן שנקבע. לדוגמה, אפשר להטמיע את Cloud Functions for Firebase כדי להריץ בדיקה יומית ולוודא שחותמת הזמן נמצאת בתוך חלון זמן מוגדר של נתונים לא עדכניים, כמו const
EXPIRATION_TIME = 1000 * 60 * 60 * 24 * 30;, ואז להסיר רישומים לא עדכניים:
exports.pruneRegistrations = functions.pubsub.schedule('every 24 hours').onRun(async (context) => {
// Get all documents where the timestamp exceeds is not within the past month
const staleRegistrationsResult = await admin.firestore().collection('fcmRegistrations')
.where("timestamp", "<", Date.now() - EXPIRATION_TIME)
.get();
// Delete devices with stale registrations
staleRegistrationsResult.forEach(function(doc) { doc.ref.delete(); });
});
ביטול הרשמות לא פעילות לנושאים
אם אתם משתמשים בנושאים, יכול להיות שתרצו גם לבטל את ההרשמה של רישומים לא פעילים לנושאים שהם רשומים אליהם. התהליך כולל שני שלבים:
- האפליקציה צריכה להירשם מחדש לנושאים בכל פעם שמזהה ההתקנה ב-Firebase (FID) משתנה. כך המינויים יופיעו מחדש באופן אוטומטי כשהאפליקציה תהיה פעילה שוב.
- אם מופע של אפליקציה לא פעיל במשך חודש (או חלון הזמן שלכם לנתונים ישנים), צריך לבטל את ההרשמה שלו לנושאים באמצעות Firebase Admin SDK כדי למחוק את המיפוי של מזהה ההתקנה של Firebase לנושא מהקצה העורפי של FCM.
היתרון בשני השלבים האלה הוא שההפצה תתבצע מהר יותר כי יש פחות רישומים לא עדכניים להפצה, והמופעים הלא עדכניים של האפליקציה יירשמו מחדש באופן אוטומטי כשהם יהיו פעילים שוב.
מדידת הצלחת המסירה
כדי לקבל את התמונה המדויקת ביותר של מסירת ההודעות, מומלץ לשלוח הודעות רק למופעי אפליקציה שנמצאים בשימוש פעיל. זה חשוב במיוחד אם אתם שולחים הודעות באופן קבוע לנושאים עם מספר גדול של מנויים. אם חלק מהמנויים האלה לא פעילים, ההשפעה על נתוני המסירה שלכם יכולה להיות משמעותית לאורך זמן.
לפני שמטרגטים הודעות למופע של אפליקציה, כדאי להביא בחשבון את הדברים הבאים:
- האם נתוני Google Analytics, נתונים שמתועדים ב-BigQuery או אותות מעקב אחרים מצביעים על כך שההרשמה פעילה?
- האם ניסיונות המסירה הקודמים נכשלו באופן עקבי לאורך זמן?
- האם מזהה ההתקנה של Firebase עודכן בשרתים שלכם בחודש האחרון?
- במכשירי Android, האם ב-FCM Data API מדווח על אחוז גבוה של כשלים במסירת הודעות בגלל
droppedDeviceInactive?
למידע נוסף על מסירה, ראו הסבר על מסירת הודעות.