أفضل الممارسات لإدارة التسجيل في FCM

إذا كنت تستخدم واجهات برمجة التطبيقات FCM لإنشاء طلبات الإرسال آليًا، قد تلاحظ بمرور الوقت أنّك تهدر الموارد من خلال إرسال الرسائل إلى الأجهزة غير النشطة التي تتضمّن عمليات تسجيل قديمة. يمكن أن يؤثّر هذا الموقف في بيانات عرض الرسائل المسجّلة في Firebase أو البيانات التي تم تصديرها إلى BigQuery، ما يؤدي إلى انخفاض كبير (ولكن غير صالح في الواقع) في معدّلات العرض. يناقش هذا الدليل بعض الإجراءات التي يمكنك اتّخاذها للمساعدة في ضمان استهداف الرسائل بكفاءة وإعداد تقارير صحيحة عن التسليم.

عمليات التسجيل القديمة والمنتهية الصلاحية

تكون عمليات التسجيل القديمة مرتبطة بأجهزة غير نشطة لم تتصل بحساب FCM لأكثر من شهر. ومع مرور الوقت، يصبح من غير المرجّح أن يتصل الجهاز بشبكة FCM مرة أخرى. ومن غير المحتمل أن يتم تسليم الرسائل وعمليات التوزيع على نطاق واسع للمواضيع الخاصة بعمليات التسجيل القديمة هذه.

هناك عدة أسباب قد تؤدي إلى انتهاء صلاحية عملية التسجيل. على سبيل المثال، قد يتم فقدان الجهاز المرتبط بالتسجيل أو إتلافه أو تخزينه ونسيانه.

في نظام التشغيل Android، عندما يكون التسجيل غير نشط لمدة 270 يومًا، يعتبره FCM منتهي الصلاحية ويتم جمع البيانات غير الضرورية. بعد انتهاء صلاحية عملية التسجيل، يضع FCM علامة على عملية التسجيل باعتبارها غير صالحة ويرفض إرسال الرسائل إليها. يُرجى العِلم أنّ خدمة Firebase Installations (FIS) هي التي تدير معرّفات عمليات التثبيت في Firebase (FIDs)، وليس خدمة FCM. في حالات نادرة، إذا اتصل جهاز مرة أخرى وتم فتح التطبيق بعد أن تم جمع البيانات غير الضرورية الخاصة بتسجيله، سيسجّل تطبيق العميل مرة أخرى باستخدام FCM، وذلك باستخدام معرّف التثبيت الذي تم استرداده من FIS. يُرجى العِلم بأنّ معرّف FID قد يتغيّر، راجِع مقالة إدارة عمليات تثبيت Firebase للحصول على تفاصيل حول الحالات التي يتم فيها إعادة إصدار معرّفات FID.

بالنسبة إلى المنصات الأخرى، مثل iOS، يعتمد FCM على خدمة الإشعارات الفورية الأساسية (مثل APNs)، التي لا تتضمّن مدة انتهاء صلاحية مماثلة تستند إلى عدم النشاط لمدة 270 يومًا. ننصحك بالحفاظ على صلاحية التسجيل وإزالة التسجيلات القديمة بشكل استباقي.

أفضل الممارسات الأساسية

هناك بعض الممارسات الأساسية التي يجب اتّباعها في أي تطبيق يستخدم واجهات برمجة التطبيقات لإنشاء طلبات الإرسال آليًا.FCM في ما يلي أفضل الممارسات الرئيسية:

  • استرداد أرقام تعريف عمليات التثبيت على Firebase (FIDs) من FCM وتخزينها على خادم تطبيقك يتمثّل أحد الأدوار المهمة للخادم في تتبُّع رقم تعريف كل عميل مسجَّل في Firebase، والحفاظ على قائمة محدَّثة بأرقام التعريف النشطة. ننصحك بشدة بتنفيذ طابع زمني للتسجيل في قاعدة البيانات وتعديله كلما تم تحميل تسجيل.
  • الحفاظ على تحديث التسجيلات وإزالة التسجيلات القديمة: بالإضافة إلى إزالة عمليات التسجيل التي لم يعُد يعتبرها FCM صالحة، يمكنك تتبُّع المؤشرات الأخرى التي تدل على أنّ عمليات التسجيل أصبحت قديمة وإزالتها بشكل استباقي. يناقش هذا الدليل بعض الخيارات المتاحة لك لتحقيق ذلك.

استرداد أرقام تعريف عمليات التثبيت في Firebase وتخزينها

عند بدء تشغيل تطبيقك لأول مرة، تسجِّل حزمة تطوير البرامج (SDK) FCM نسخة التطبيق مع FCM وتعرض معرّف تثبيت Firebase (FID). هذا هو المعرّف الذي يجب تضمينه في طلبات الإرسال المستهدَفة من واجهة برمجة التطبيقات، أو استخدامه للاشتراك في المواضيع.

ننصحك بشدة بحفظ معرّف FID على خادم تطبيقك مع طابع زمني كلما تم تحميله. من خلال تعديل الطابع الزمني في كل طلب تحميل، يعرف الخادم متى تم فتح مثيل التطبيق آخر مرة ومزامنته بنجاح مع الخلفية FCM.

استنادًا إلى ما إذا كان التفعيل التلقائي مفعّلاً أو غير مفعّل (بما في ذلك الحالات التي لا يكون فيها التفعيل التلقائي متاحًا)، عليك التعامل مع التسجيل والتحديثات على النحو التالي:

  • (يُنصح به) عند تفعيل ميزة "بدء التشغيل التلقائي": تعمل حزمة SDK تلقائيًا على إبقاء التسجيل محدّثًا وتتبُّع التغييرات. يتم استدعاء onRegistered() بانتظام عند إجراء عمليات مزامنة روتينية أثناء بدء تشغيل التطبيق، وكذلك عند حدوث تغييرات في معرّف FID. ما عليك سوى تنفيذ دالة معاودة الاتصال هذه لتحميل معرّف FID إلى الخادم وحفظ الطابع الزمني الحالي.
  • عند إيقاف ميزة الإعداد التلقائي: لن يتم استدعاء onRegistered() تلقائيًا عند بدء التشغيل. لتتبُّع عمليات التسجيل وإبقائها محدّثة، استدعِ الدالة register() عند بدء تشغيل التطبيق، مثلاً في نظام التشغيل Android، في الدالة onCreate() الخاصة بالنشاط الرئيسي. يؤدي إجراء مكالمة ناجحة إلى بدء عملية التسجيل في FCM باستخدام معرّف FID وإرساله إلى دالة معاودة الاتصال onRegistered()، ما يتيح لتطبيقك تحميل معرّف FID وتعديل الطابع الزمني على خادمك.

مثال: تخزين أرقام التعريف الخاصة بالمتجر والطوابع الزمنية في Cloud Firestore

على سبيل المثال، يمكنك استخدام Cloud Firestore لتخزين معرّفات المستندات في مجموعة باسم 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 بنجاح، يتم استدعاء 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 والرد عليها من خلال حذف أي عمليات تسجيل معروف أنّها غير صالحة أو منتهية الصلاحية من نظامك. باستخدام واجهة برمجة التطبيقات HTTP الإصدار 1، قد تشير رسائل الخطأ هذه إلى أنّ طلب الإرسال يستهدف عمليات تسجيل غير صالحة أو منتهية الصلاحية:

  • 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. اعتمادًا على واجهات برمجة التطبيقات التي تستخدمها، اتّبِع الاستراتيجية المناسبة:

بالنسبة إلى تطبيقات العميل التي تستخدم واجهات برمجة التطبيقات الخاصة بمعرّف FID، ليس عليك جدولة مهام دورية في الخلفية في تطبيق العميل لاسترداد عمليات التسجيل أو إعادة تحميلها. تتولّى حزمة SDK تلقائيًا عمليات إعادة التحميل في إطار عملية التهيئة التلقائية، وتوفّر بانتظام المعرّف الصحيح الحالي للتثبيت (FID) إلى دالة onRegistered() الاستدعاء في عمليات المزامنة الروتينية أثناء بدء تشغيل التطبيق.

للحفاظ على تحديث الخادم، عليك تنفيذ استراتيجيات التحميل عند بدء التشغيل الموضّحة في مقالة استرداد أرقام تعريف عمليات تثبيت Firebase وتخزينها:

  • تفعيل الإعداد التلقائي: تضمن حزمة SDK تلقائيًا إرسال أحدث معرّف FID إلى الخادم عند إجراء عمليات المزامنة الروتينية أثناء بدء تشغيل التطبيق.
  • تم إيقاف ميزة "بدء التشغيل التلقائي" أو أنّها غير متاحة: استدعِ الدالة register() عند بدء تشغيل التطبيق (على سبيل المثال، في Android، في onCreate() للنشاط الرئيسي) لفرض تسلسل التسجيل وتفعيل إرسال معرّف FID إلى دالة onRegistered() الردّ.

تضمن هذه الاستراتيجيات حصول خادمك دائمًا على أحدث معرّف نشط لجهاز Android، ويمكنه استرداد البيانات تلقائيًا في حال تعذّر تحميلها، ما يجعل التطبيق مرنًا للغاية.

واجهات برمجة التطبيقات المتوقّفة للرموز المميزة للتسجيل

إذا كنت تستخدم رموز تسجيل قديمة، لن تدير حزمة تطوير البرامج (SDK) للعميل عمليات إعادة التحميل تلقائيًا عند إجراء عمليات المزامنة الروتينية. لذلك، ننصحك باسترداد جميع رموز التسجيل وتعديلها بشكل دوري على الخادم. يتطلّب ذلك منك ما يلي:

  • أضِف منطق التطبيق في تطبيق العميل لاسترداد الرمز المميّز الحالي باستخدام طلب البيانات من واجهة برمجة التطبيقات المناسب (مثل token(completion): لمنصات Apple أو 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" أو البيانات التي يتم تسجيلها في BigQuery أو إشارات التتبُّع الأخرى إلى أنّ التسجيل نشط؟
  • هل تعذّر إجراء عمليات التسليم السابقة بشكل متكرّر على مدار فترة زمنية؟
  • هل تم تعديل رقم تعريف عملية التثبيت في Firebase على خوادمك خلال الشهر الماضي؟
  • بالنسبة إلى أجهزة Android، هل تسجّل FCM Data API نسبة عالية من حالات تعذُّر تسليم الرسائل بسبب droppedDeviceInactive؟

لمزيد من المعلومات حول التسليم، يُرجى الاطّلاع على فهم عملية تسليم الرسائل.