روال‌های مطلوب برای مدیریت ثبت FCM

اگر از FCM API برای ساختن درخواست‌های ارسال به‌صورت برنامه‌ریزی‌شده استفاده می‌کنید، ممکن است متوجه شوید که با گذشت زمان، با ارسال پیام به دستگاه‌های غیرفعال با ثبت‌های قدیمی، منابع را هدر می‌دهید. این وضعیت می‌تواند بر داده‌های ارسال پیام گزارش‌شده در کنسول Firebase یا داده‌های صادرشده به BigQuery تأثیر بگذارد و به‌صورت کاهش چشمگیر (اما درواقع نامعتبر) در نرخ‌های ارسال نشان داده شود. این راهنما درباره برخی‌از اقداماتی که می‌توانید برای کمک به اطمینان از هدف‌یابی کارآمد پیام و گزارش‌دهی تحویل معتبر انجام دهید بحث می‌کند.

ثبت‌های قدیمی و منقضی‌شده

ثبت‌های قدیمی با دستگاه‌های غیرفعالی که بیش‌از یک ماه به FCM متصل نشده‌اند مرتبط هستند. با گذشت زمان، احتمال اینکه دستگاه دوباره به FCM متصل شود کمتر و کمتر می‌شود. پیام‌های ارسالی و توزیع طرفداران موضوع برای این ثبت‌های قدیمی احتمالاً هرگز تحویل داده نمی‌شوند.

چند دلیل وجود دارد که چرا ثبت‌نام می‌تواند قدیمی شود. برای مثال، ممکن است دستگاهی که ثبت با آن مرتبط است گم شود، ازبین برود، یا در انبار گذاشته شود و فراموش شود.

برای Android، وقتی ثبت‌نامی به‌مدت ۲۷۰ روز غیرفعال باشد، FCM آن را منقضی‌شده درنظر می‌گیرد و آن را جمع‌آوری می‌کند. وقتی ثبت‌نامی منقضی می‌شود، FCM آن را به‌عنوان نامعتبر علامت‌گذاری می‌کند و ارسال به آن را رد می‌کند. توجه داشته باشید که شناسه‌های نصب Firebase (FID) خودشان توسط سرویس نصب Firebase (FIS) مدیریت می‌شوند، نه توسط FCM. در موارد نادری که دستگاه دوباره متصل می‌شود و برنامه پس‌از جمع‌آوری زباله ثبت آن باز می‌شود، برنامه مشتری بااستفاده از FID بازیابی‌شده از FIS دوباره با FCM ثبت می‌شود. توجه داشته باشید که FID ممکن است تغییر کند؛ برای جزئیات مربوط به زمان صدور مجدد FID، به مدیریت نصب‌های Firebase مراجعه کنید.

برای پلاتفرم‌های دیگر مثل iOS،‏ FCM به سرویس پوش زیربنایی (برای نمونه، APNs) متکی است که انقضای مبتنی بر عدم فعالیت ۲۷۰ روزه یکسان را ندارد. توصیه می‌کنیم که به‌صورت پیش‌دستانه ثبت‌های خود را به‌روز نگه دارید و ثبت‌های قدیمی را حذف کنید.

روال‌های مطلوب پایه

چند رویه اساسی وجود دارد که باید در هر برنامه‌ای که از FCM API برای ساختن درخواست‌های ارسال به‌صورت برنامه‌ریزی‌شده استفاده می‌کند دنبال کنید. روال‌های مطلوب اصلی عبارت‌اند از:

  • شناسه‌های نصب Firebase (FID) را از FCM بازیابی کنید و آن‌ها را در سرور برنامه‌تان ذخیره کنید. نقش مهم سرور این است که FID ثبت‌شده هر کارخواه را پیگیری کند و فهرست به‌روزی از FIDهای فعال داشته باشد. به‌شدت توصیه می‌کنیم یک مهر زمان ثبت در پایگاه داده خود پیاده‌سازی کنید و هر زمان که ثبتی بارگذاری می‌شود آن را به‌روز کنید.
  • ثبت‌نام‌های قدیمی را حذف کنید و ثبت‌نام‌های جدید را حفظ کنید. علاوه‌بر برداشتن ثبت‌هایی که FCM دیگر آن‌ها را معتبر نمی‌داند، ممکن است بخواهید نشانه‌های دیگری را که نشان می‌دهد ثبت‌ها قدیمی شده‌اند پایش کنید و آن‌ها را به‌صورت پیش‌دستانه بردارید. این راهنما درباره برخی‌از گزینه‌های شما برای دستیابی به این هدف بحث می‌کند.

بازیابی و ذخیره کردن «شناسه‌های نصب Firebase»

در راه‌اندازی اولیه برنامه، کیت توسعه نرم‌افزار FCM نمونه برنامه را در FCM ثبت می‌کند و «شناسه نصب Firebase» (FID) را برمی‌گرداند. این شناسه را باید در درخواست‌های ارسال هدف‌دار از API بگنجانید یا از آن برای اشتراک‌های موضوعی استفاده کنید.

اکیداً توصیه می‌کنیم که FID را همراه با مُهر زمان در سرور برنامه‌تان ذخیره کنید هرگاه بارگذاری می‌شود. با به‌روزرسانی مُهر زمان در هر درخواست بارگذاری، سرور شما متوجه می‌شود که نمونه برنامه آخرین بار چه زمانی باز شده و با زیرینه FCM باموفقیت همگام‌سازی شده است.

بسته به اینکه مقداردهی اولیه خودکار فعال یا غیرفعال باشد (ازجمله پشتیبانی‌نشده)، باید ثبت و به‌روزرسانی را به این صورت انجام دهید:

  • (توصیه‌شده) وقتی مقداردهی اولیه خودکار فعال باشد: «کیت توسعه نرم‌افزار» به‌طور خودکار ثبت را به‌روز نگه می‌دارد و تغییرات را پایش می‌کند. در همگام‌سازی‌های معمول درطول راه‌اندازی برنامه و همچنین هنگام وقوع تغییرات FID، onRegistered() بازخوانی به‌طور منظم فراخوانده می‌شود. کافی است این برگشت تماس را پیاده‌سازی کنید تا FID را در سرورتان بارگذاری کنید و مُهر زمان کنونی را ذخیره کنید.
  • وقتی مقداردهی اولیه خودکار غیرفعال باشد: onRegistered() بازخوانی در شروع به‌طور خودکار فراخوانی نمی‌شود. برای پیگیری ثبت‌ها و تازه نگه داشتن آن‌ها، register() را در زمان راه‌اندازی برنامه فراخوانی کنید؛ برای مثال، در Android، در فعالیت اصلی onCreate(). تماس موفقیت‌آمیز باعث راه‌اندازی فرایند ثبت FCM بااستفاده از FID می‌شود و آن را به onRegistered() بازخوانی شما ارائه می‌دهد و به برنامه‌تان اجازه می‌دهد FID را بارگذاری کند و مُهر زمان را در سرورتان به‌روز کند.

مثال: ذخیره کردن شناسه فایل و مُهر زمان در Cloud Firestore

برای مثال، می‌توانید از Cloud Firestore برای ذخیره کردن FIDs در مجموعه‌ای به‌نام 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 نسخه ۱»، این پیام‌های خطا ممکن است نشان دهد که درخواست ارسال شما ثبت‌های نامعتبر یا منقضی‌شده را هدف‌یابی کرده است:

  • ‫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()
            }
        });

اگر ثبت دستگاه Android پس‌از ۲۷۰ روز غیرفعال بودن منقضی شود، یا اگر کارخواه به‌طور صریح ثبت را لغو کند، FCM پاسخ نامعتبری برمی‌گرداند. اگر نیاز دارید که براساس تعاریف خودتان، کهنگی را دقیق‌تر پیگیری کنید، می‌توانید به‌صورت پیش‌دستانه ثبت‌های کهنه را بردارید.

ثبت‌نام‌ها را به‌طور منظم به‌روزرسانی کنید

صرف‌نظر از اینکه ثبت‌های شما براساس FIDs یا نشانه‌های ثبت قدیمی باشد، سرورتان باید همیشه مُهر زمان ثبت را در پایگاه داده‌تان در هر درخواست بارگذاری به‌روز کند. این مُهر زمان به‌عنوان سیگنالی برای نصب برنامه عمل می‌کند و به مشتری اطلاع می‌دهد که برنامه باموفقیت باز شده است و با زیرینه FCM همگام‌سازی شده است. بسته به میاناهای برنامه‌سازی کاربردی که استفاده می‌کنید، راهبرد مناسب را پیاده‌سازی کنید:

برای برنامه‌های کارخواهی که از «میاناهای برنامه‌سازی کاربردی FID» استفاده می‌کنند، نیازی نیست که در برنامه کارخواه خود کارهای پس‌زمینه‌ای دوره‌ای زمان‌بندی کنید تا ثبت‌ها را بازیابی یا بازآوری کنید. «کیت توسعه نرم‌افزار» به‌طور خودکار از به‌روزرسانی‌ها درحین مقداردهی اولیه خودکار مراقبت می‌کند و به‌طور منظم «شناسه تبلیغ‌کننده» فعلی صحیح را در onRegistered() بازخوان در همگام‌سازی‌های معمول درطول راه‌اندازی‌های برنامه ارائه می‌دهد.

برای به‌روز نگه داشتن سرورتان، استراتژی‌های بارگذاری راه‌اندازی را که در بازیابی و ذخیره کردن شناسه‌های نصب Firebase توضیح داده شده است پیاده‌سازی کنید:

  • مقداردهی اولیه خودکار فعال است: کیت توسعه نرم‌افزار به‌طور خودکار تضمین می‌کند که جدیدترین FID در همگام‌سازی‌های معمول درطول شروع برنامه به سرور شما ارسال شود.
  • راه‌اندازی خودکار غیرفعال یا پشتیبانی‌نشده: در زمان راه‌اندازی برنامه (برای مثال، در Android، در فعالیت اصلی onCreate()) با فراخوانی register() ثبت توالی را اجباری کنید و ارسال FID را به بازخوان onRegistered() راه‌اندازی کنید.

این استراتژی‌ها تضمین می‌کنند که سرور شما همیشه جدیدترین FID فعال را داشته باشد و می‌تواند به‌طور خودکار از بارگذاری‌های ناموفق بازیابی کند، که باعث می‌شود برنامه بسیار انعطاف‌پذیر باشد.

میاناهای برنامه‌سازی کاربردی منسوخ‌شده ثبت کد

اگر از نشان‌های ثبت قدیمی استفاده می‌کنید، کیت توسعه نرم‌افزار کارخواه به‌طور خودکار مدیریت بازآوری‌ها را در همگام‌سازی‌های معمول انجام نمی‌دهد. بنابراین، توصیه می‌کنیم که به‌طور دوره‌ای همه نشان‌های ثبت را در سرورتان بازیابی و به‌روز کنید. برای این کار باید:

  • منطق برنامه را در برنامه مشتری‌تان اضافه کنید تا بااستفاده از فراخوانی API مناسب (مثل 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 از موضوعات لغو اشتراک کنید تا نگاشت «شناسه نصب Firebase» به موضوع را از FCM زیرینه حذف کنید.

مزیت این دو مرحله این است که توزیع‌های شما سریع‌تر انجام می‌شود زیرا ثبت‌های قدیمی کمتری برای توزیع وجود دارد و نمونه‌های برنامه قدیمی شما پس‌از فعال شدن مجدد، به‌طور خودکار دوباره مشترک می‌شوند.

سنجش موفقیت در تحویل

برای دریافت دقیق‌ترین تصویر از ارسال پیام، بهتر است فقط به نمونه‌های برنامه که به‌طور فعال استفاده می‌شوند پیام ارسال کنید. این کار به‌ویژه اگر به‌طور منظم به موضوعاتی با تعداد زیادی مشترک پیام ارسال می‌کنید مهم است؛ اگر بخشی از این مشترکان درواقع غیرفعال باشند، تأثیر آن بر آمار تحویل شما در طول زمان می‌تواند قابل‌توجه باشد.

قبل‌از هدف‌یابی پیام‌ها به نمونه برنامه، به موارد زیر توجه کنید:

  • آیا Google Analytics، داده‌های ضبط‌شده در BigQuery، یا نشان‌های ردیابی دیگر نشان می‌دهند که ثبت‌نام فعال است؟
  • آیا تلاش‌های قبلی برای ارسال به‌طور مداوم در یک دوره زمانی ناموفق بوده‌اند؟
  • آیا «شناسه نصب Firebase» در سرورهایتان در ماه گذشته به‌روز شده است؟
  • آیا برای دستگاه‌های Android، FCM Data API درصد بالایی از عدم موفقیت در ارسال پیام را به‌دلیل droppedDeviceInactive گزارش می‌کند؟

برای اطلاعات بیشتر درباره تحویل، درک تحویل پیام را ببینید.