שיטות מומלצות לניהול רישום ב-FCM

אם אתם משתמשים ב-FCM APIs כדי ליצור בקשות לשליחה באופן פרוגרמטי, יכול להיות שבמהלך הזמן תגלו שאתם מבזבזים משאבים בשליחת הודעות למכשירים לא פעילים עם רישומים לא עדכניים. המצב הזה יכול להשפיע על נתוני מסירת ההודעות שמדווחים בFirebaseמסוף או על נתונים שמיוצאים ל-BigQuery, ויוצג כירידה דרמטית (אבל לא תקפה בפועל) בשיעורי המסירה. במדריך הזה נסביר על כמה אמצעים שאפשר לנקוט כדי לוודא שהטירגוט של ההודעות יהיה יעיל ושהדוחות על מסירת ההודעות יהיו תקפים.

רישומים לא עדכניים ורישומים שתוקפם פג

רישומים לא עדכניים משויכים למכשירים לא פעילים שלא התחברו ל-FCM במשך יותר מחודש. ככל שעובר הזמן, הסיכוי שהמכשיר יתחבר שוב ל-FCM קטן והולך. סביר להניח שהודעות שיישלחו לרישומים לא פעילים כאלה, וגם הודעות שיישלחו לכל המשתמשים בנושאים שקשורים לרישומים האלה, לא יועברו אף פעם.

יש כמה סיבות לכך שרישום יכול להיות לא עדכני. לדוגמה, יכול להיות שהמכשיר שאליו משויך הרישום אבד, נהרס או אוחסן ונשכח.

ב-Android, אם רישום לא היה פעיל במשך 270 ימים, FCMהוא נחשב כרישום שתוקפו פג והמערכת מבצעת איסוף אשפה לגביו. אחרי שההרשמה פגה, FCM מסמן אותה כלא תקפה ודוחה שליחות אליה. חשוב לדעת שמזהי התקנה של Firebase‏ (FID) מנוהלים על ידי שירות ההתקנות של Firebase‏ (FIS), ולא על ידי FCM. במקרים נדירים שבהם מכשיר מתחבר מחדש והאפליקציה נפתחת אחרי שבוצע איסוף זבל של הרישום שלה, אפליקציית הלקוח נרשמת מחדש ב-FCM באמצעות ה-FID שאוחזר מ-FIS. שימו לב שמזהה ה-FID עשוי להשתנות. לפרטים על המקרים שבהם מונפק מחדש מזהה FID, אפשר לעיין במאמר בנושא ניהול התקנות של Firebase.

בפלטפורמות אחרות כמו iOS, ‏ FCM מסתמך על שירות הדחיפה הבסיסי (למשל, APNs), שלא כולל את אותו תוקף שמבוסס על חוסר פעילות של 270 ימים. מומלץ לשמור על עדכניות הרישום ולהסיר רישומים לא פעילים באופן יזום.

שיטות מומלצות בסיסיות

יש כמה שיטות בסיסיות שחשוב לפעול לפיהן בכל אפליקציה שמשתמשת בממשקי FCM API כדי ליצור בקשות שליחה באופן פרוגרמטי. השיטות המומלצות העיקריות הן:

  • מאחזרים מ-FCM את מזהי ההתקנה של Firebase‏ (FID) ומאחסנים אותם בשרת האפליקציה. תפקיד חשוב של השרת הוא לעקוב אחרי מזהה ה-FID הרשום של כל לקוח ולשמור רשימה מעודכנת של מזהי FID פעילים. מומלץ מאוד להטמיע חותמת זמן של הרשמה במסד הנתונים שלכם, ולעדכן אותה בכל פעם שמעלים הרשמה.
  • לשמור על עדכניות הרישומים ולהסיר רישומים לא פעילים. בנוסף להסרת רישומים ש-FCM כבר לא מחשיבה כתקפים, כדאי לעקוב אחרי סימנים אחרים לכך שהרישומים לא עדכניים ולהסיר אותם באופן יזום. במדריך הזה מפורטות כמה אפשרויות שיעזרו לכם להשיג את המטרה הזו.

אחזור ואחסון של מזהי התקנה ב-Firebase

בהפעלה הראשונית של האפליקציה, FCM SDK רושם את מופע האפליקציה ב-FCM ומחזיר מזהה התקנה של Firebase‏ (FID). זהו המזהה שצריך לכלול בבקשות לשליחה ממוקדת מ-API, או להשתמש בו להרשמה לנושאים.

מומלץ מאוד לשמור את ה-FID בשרת האפליקציה לצד חותמת זמן בכל פעם שהוא מועלה. על ידי עדכון חותמת הזמן בכל בקשת העלאה, השרת יודע מתי מופע האפליקציה נפתח לאחרונה וסונכרן בהצלחה עם הקצה העורפי של FCM.

בהתאם למצב ההפעלה של האתחול האוטומטי (מופעל, מושבת או לא נתמך), צריך לטפל ברישום ובעדכונים באופן הבא:

  • (מומלץ) כשההפעלה האוטומטית מופעלת: ה-SDK שומר על הרענון של הרישום באופן אוטומטי ועוקב אחרי שינויים. הקריאה החוזרת (callback) של onRegistered() מופעלת באופן קבוע בסנכרונים שגרתיים במהלך הפעלת האפליקציה, וגם כשמתרחשים שינויים ב-FID. פשוט מטמיעים את הקריאה החוזרת הזו כדי להעלות את ה-FID לשרת ולשמור את חותמת הזמן הנוכחית.
  • כשההפעלה האוטומטית מושבתת: הקריאה החוזרת 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 של ה-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(); });
});
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(); }); });

ביטול הרשמות לא פעילות לנושאים

אם אתם משתמשים בנושאים, כדאי גם לבטל את ההרשמה של רישומים לא פעילים לנושאים שהם רשומים אליהם. התהליך הזה כולל שני שלבים:

  1. האפליקציה צריכה להירשם מחדש לנושאים בכל פעם שמזהה ההתקנה ב-Firebase‏ (FID) משתנה. כך המינויים יופיעו מחדש באופן אוטומטי כשהאפליקציה תהיה פעילה שוב.
  2. אם מופע של אפליקציה לא פעיל במשך חודש (או חלון הזמן שלכם לנתונים ישנים), צריך לבטל את ההרשמה שלו לנושאים באמצעות Firebase Admin SDK כדי למחוק את המיפוי של מזהה ההתקנה של Firebase לנושא מהקצה העורפי של FCM.

היתרון בשני השלבים האלה הוא שההפצה תתבצע מהר יותר כי יש פחות רישומים לא עדכניים להפצה, והמופעים הלא עדכניים של האפליקציה יירשמו מחדש באופן אוטומטי כשהם יהיו פעילים שוב.

מדידת הצלחת ההעברה

כדי לקבל תמונה מדויקת ככל האפשר של מסירת ההודעות, מומלץ לשלוח הודעות רק למופעים של אפליקציות שנמצאים בשימוש פעיל. זה חשוב במיוחד אם אתם שולחים הודעות באופן קבוע לנושאים עם מספר גדול של מנויים. אם חלק מהמנויים האלה לא פעילים, ההשפעה על נתוני המסירה יכולה להיות משמעותית לאורך זמן.

לפני שמטרגטים הודעות למופע של אפליקציה, כדאי לשקול את הנקודות הבאות:

  • האם נתוני Google Analytics, נתונים שמתועדים ב-BigQuery או אותות מעקב אחרים מצביעים על כך שההרשמה פעילה?
  • האם ניסיונות המסירה הקודמים נכשלו באופן עקבי במשך תקופה מסוימת?
  • האם מזהה ההתקנה של Firebase עודכן בשרתים שלך בחודש האחרון?
  • במכשירי Android, האם FCM Data API מדווח על אחוז גבוה של הודעות שלא נמסרו בגלל droppedDeviceInactive?

מידע נוסף על מסירה זמין במאמר הסבר על מסירת הודעות.