אם אתם משתמשים ב-FCM APIs כדי ליצור בקשות לשליחה באופן פרוגרמטי, יכול להיות שבמהלך הזמן תגלו שאתם מבזבזים משאבים בשליחת הודעות למכשירים לא פעילים עם רישומים לא עדכניים. המצב הזה יכול להשפיע על נתוני מסירת ההודעות שמדווחים בFirebaseמסוףBigQuery או על נתונים שמיוצאים ל-BigQuery, ויוצג כירידה דרמטית (אבל לא תקפה בפועל) בשיעורי המסירה. במדריך הזה נסביר על כמה אמצעים שאפשר לנקוט כדי לוודא שהודעות יפנו לקהלים הרלוונטיים ושהדיווח על מסירת ההודעות יהיה מדויק.
רישומים לא עדכניים ורישומים שתוקפם פג
רישומים לא עדכניים משויכים למכשירים לא פעילים שלא התחברו אל FCM במשך יותר מחודש. ככל שעובר הזמן, הסיכוי שהמכשיר יתחבר שוב אל FCM הולך ופוחת. סביר להניח שהודעות שיישלחו והודעות שיישלחו לכל המשתמשים בנושאים האלה לא יגיעו אף פעם לרישומים האלה שכבר לא פעילים.
יש כמה סיבות לכך שרישום יכול להיות לא עדכני. לדוגמה, יכול להיות שהמכשיר שאליו משויך הרישום אבד, נהרס או אוחסן ונשכח.
ב-Android, אם הרישום לא פעיל במשך 270 ימים, FCM הוא נחשב כרישום שתוקפו פג והמערכת מבצעת איסוף אשפה שלו. אחרי שההרשמה פגה, FCM מסמן אותה כלא תקפה ודוחה שליחות אליה. חשוב לדעת שמזהי ההתקנה (FID) של Firebase מנוהלים על ידי שירות ההתקנות (FIS) של Firebase, ולא על ידי FCM. במקרים נדירים שבהם מכשיר מתחבר מחדש והאפליקציה נפתחת אחרי שהרישום שלה נאסף על ידי איסוף אשפה, אפליקציית הלקוח נרשמת מחדש ב-FCM באמצעות ה-FID שאוחזר מ-FIS. שימו לב: יכול להיות שמזהה ה-FID ישתנה. לפרטים על המקרים שבהם מונפק מחדש מזהה FID, אפשר לעיין במאמר בנושא ניהול התקנות של Firebase.
בפלטפורמות אחרות כמו iOS, FCM מסתמך על שירות הפוש הבסיסי (לדוגמה, APNs), שלא חל עליו אותו תוקף של 270 ימים שמבוסס על חוסר פעילות. מומלץ לשמור על עדכניות הרישום ולהסיר רישומים לא עדכניים באופן יזום.
שיטות מומלצות בסיסיות
יש כמה שיטות בסיסיות שמומלץ לפעול לפיהן בכל אפליקציה שמשתמשת בממשקי FCM API כדי ליצור בקשות שליחה באופן פרוגרמטי. השיטות המומלצות העיקריות הן:
- מאחזרים מ-FCM את מזהי ההתקנה (FID) של Firebase ושומרים אותם בשרת האפליקציה. תפקיד חשוב של השרת הוא לעקוב אחרי מזהה ה-FID הרשום של כל לקוח ולשמור רשימה מעודכנת של מזהי FID פעילים. מומלץ מאוד להטמיע חותמת זמן של הרשמה במסד הנתונים שלכם, ולעדכן אותה בכל פעם שמעלים הרשמה.
- לשמור על עדכניות הרישום ולהסיר רישומים לא פעילים. בנוסף להסרת רישומים ש-FCM כבר לא נחשבים תקפים, כדאי לעקוב אחרי סימנים אחרים לכך שרישומים הפכו ללא פעילים ולהסיר אותם באופן יזום. במדריך הזה מפורטות כמה אפשרויות להשגת המטרה הזו.
אחזור ואחסון של מזהי התקנה של Firebase
בהפעלה הראשונית של האפליקציה, FCM SDK רושם את מופע האפליקציה ב-FCM ומחזיר מזהה התקנה של Firebase (FID). זהו המזהה שצריך לכלול בבקשות לשליחה ממוקדת מ-API, או להשתמש בו להרשמה לנושאים.
מומלץ מאוד לשמור את מזהה ה-FID בשרת האפליקציה לצד חותמת זמן בכל פעם שהוא מועלה. על ידי עדכון חותמת הזמן בכל בקשת העלאה, השרת יודע מתי המופע של האפליקציה נפתח לאחרונה וסונכרן בהצלחה עם קצה העורפי של FCM.
בהתאם להגדרה של הפעלה או השבתה של אתחול אוטומטי (כולל אם הוא לא נתמך), צריך לטפל ברישום ובעדכונים באופן הבא:
- (מומלץ) כשההפעלה האוטומטית מופעלת: ה-SDK דואג שהרישום יהיה עדכני ועוקב אחרי השינויים באופן אוטומטי. הקריאה החוזרת (callback) של
onRegistered()מופעלת באופן קבוע בסנכרונים שגרתיים במהלך הפעלת האפליקציה, וגם כשמתרחשים שינויים ב-FID. פשוט מטמיעים את הקריאה החוזרת הזו כדי להעלות את ה-FID לשרת ולשמור את חותמת הזמן הנוכחית. - כשההפעלה האוטומטית מושבתת: הקריאה החוזרת (callback) של
onRegistered()לא תופעל אוטומטית בהתחלה. כדי לעקוב אחרי הרשמות ולשמור אותן עדכניות, צריך להתקשר אלregister()בהפעלת האפליקציה. לדוגמה, ב-Android, ב-onCreate()של הפעילות הראשית. שיחה מוצלחת מפעילה את תהליך הרישום FCM באמצעות ה-FID ומעבירה אותו לקריאה החוזרת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 מחשיב רישום כמיושן אם מופע האפליקציה שלו לא התחבר במשך חודש. כל רישום שגילו יותר מחודש הוא כנראה מכשיר לא פעיל. מכשיר פעיל היה מרענן את הרישום שלו.
בהתאם לתרחיש השימוש, יכול להיות שחודש אחד יהיה קצר מדי או ארוך מדי, ולכן אתם צריכים לקבוע את הקריטריונים שמתאימים לכם.
זיהוי תגובות לא חוקיות מהקצה העורפי FCM
חשוב לזהות תשובות פסולות מ-FCM ולהגיב על ידי מחיקת רישומים מהמערכת שלכם שידוע שהם פסולים או שתוקפם פג. בממשק ה-API של HTTP v1, הודעות השגיאה האלה עשויות להצביע על כך שבקשת השליחה שלכם כוונה לרישומים לא תקינים או שפג תוקפם:
UNREGISTERED(HTTP 404)-
INVALID_ARGUMENT(HTTP 400)
אם אתם בטוחים שהמטען הייעודי של ההודעה תקין ואתם מקבלים אחת מהתשובות האלה לרישום ממוקד, אפשר למחוק את הרשומה של הרישום הזה, כי היא לא תהיה תקפה יותר. לדוגמה, כדי למחוק רישומים לא תקינים מ-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 הנוכחי הנכון לקריאה החוזרת onRegistered() במהלך הפעלת האפליקציה.
כדי שהשרת שלכם יהיה מעודכן, צריך להטמיע את אסטרטגיות ההעלאה של ההפעלה שמפורטות במאמר אחזור ואחסון של מזהי התקנה של Firebase:
- הפעלה אוטומטית מופעלת: ה-SDK מוודא אוטומטית שמזהה ה-FID העדכני ביותר נשלח לשרת שלכם בסנכרונים שגרתיים במהלך הפעלת האפליקציה.
- ההפעלה האוטומטית מושבתת או לא נתמכת: צריך להתקשר אל
register()בהפעלת האפליקציה (לדוגמה, ב-Android, ב-onCreate()של הפעילות הראשית) כדי לכפות את רצף הרישום ולהפעיל את מסירת ה-FID אל הקריאה החוזרת (callback) שלonRegistered().
האסטרטגיות האלה מבטיחות שלשרת תמיד יהיה ה-FID הפעיל העדכני ביותר, והוא יוכל להתאושש מהעלאות שנכשלו באופן אוטומטי, מה שהופך את האפליקציה לעמידה מאוד.
ממשקי ה-API של טוקן הרישום שהוצאו משימוש
אם אתם משתמשים באסימוני רישום מדור קודם, ה-SDK של הלקוח לא מנהל באופן אוטומטי רענונים בסנכרונים שגרתיים. לכן מומלץ לאחזר ולעדכן מעת לעת את כל טוקני הרישום בשרת. כדי לעשות את זה, צריך:
- מוסיפים לאפליקציית הלקוח לוגיקה לאחזור הטוקן הנוכחי באמצעות קריאת ה-API המתאימה (למשל,
token(completion):לפלטפורמות של Apple אוgetToken()ל-Android), ואז שולחים את הטוקן הנוכחי לשרת האפליקציה לאחסון (עם חותמת זמן). יכול להיות שמדובר בעבודה חודשית שהוגדרה כך שתכלול את כל הלקוחות או האסימונים. - מוסיפים לוגיקה של שרת כדי לעדכן את חותמת הזמן של האסימון במרווחי זמן קבועים, בלי קשר לשאלה אם האסימון השתנה או לא.
במאמר ניהול טוקנים של העברת הודעות בענן בבלוג של Firebase יש דוגמה ללוגיקה של Android לעדכון טוקנים מדור קודם באמצעות WorkManager.
לא משנה באיזה דפוס תזמון תבחרו, חשוב לעדכן את האסימונים באופן קבוע. תדירות עדכון של פעם בחודש מאפשרת איזון טוב בין ההשפעה על הסוללה לבין זיהוי של טוקנים לא פעילים של רישום. בביצוע הרענון הזה, אתם גם מוודאים שכל מכשיר שהופך ללא פעיל ירענן את הרישום שלו כשהוא יהפוך שוב לפעיל. אין יתרון לרענון בתדירות גבוהה יותר משבועית.
הסרת רישומים לא פעילים
לפני ששולחים הודעות למכשיר, צריך לוודא שחותמת הזמן של הרישום של המכשיר נמצאת בתוך חלון הזמן של תקופת ההתיישנות. לדוגמה, אפשר להטמיע את 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(); });
});
ביטול הרשמות לא פעילות לנושאים
אם אתם משתמשים בנושאים, כדאי גם לבטל את ההרשמה של רישומים לא פעילים לנושאים שהם רשומים אליהם. התהליך כולל שני שלבים:
- האפליקציה צריכה להירשם מחדש לנושאים בכל פעם שמזהה ההתקנה (FID) של Firebase משתנה. כך המינויים יופיעו מחדש באופן אוטומטי כשאפליקציה תהפוך שוב לפעילה.
- אם מופעלת באפליקציה תקופה של חוסר פעילות למשך חודש (או תקופה אחרת שהגדרתם), צריך לבטל את ההרשמה של האפליקציה לנושאים באמצעות Firebase Admin SDK כדי למחוק את המיפוי של מזהה ההתקנה של Firebase לנושא מהקצה העורפי FCM.
היתרון בשני השלבים האלה הוא שההפצה תתבצע מהר יותר, כי יהיו פחות רישומים לא פעילים להפצה, והמופעים הלא פעילים של האפליקציה יירשמו מחדש באופן אוטומטי כשהם יופעלו שוב.
מדידת הצלחת המסירה
כדי לקבל תמונה מדויקת ככל האפשר של מסירת ההודעות, מומלץ לשלוח הודעות רק למופעים של אפליקציות שנמצאים בשימוש פעיל. זה חשוב במיוחד אם אתם שולחים הודעות באופן קבוע לנושאים עם מספר גדול של מנויים. אם חלק מהמנויים האלה לא פעילים, ההשפעה על נתוני המסירה יכולה להיות משמעותית לאורך זמן.
לפני שמטרגטים הודעות למופע של אפליקציה, כדאי לשקול את הנקודות הבאות:
- האם נתוני Google Analytics, נתונים שנאספו ב-BigQuery או אותות מעקב אחרים מצביעים על כך שההרשמה פעילה?
- האם ניסיונות המסירה הקודמים נכשלו באופן עקבי לאורך תקופה מסוימת?
- האם מזהה ההתקנה של Firebase עודכן בשרתים שלך בחודש האחרון?
- במכשירי Android, האם FCM Data API מדווח על אחוז גבוה של הודעות שלא נמסרו בגלל
droppedDeviceInactive?
מידע נוסף על מסירה זמין במאמר הסבר על מסירת הודעות.