بهترین شیوه‌ها برای مدیریت ثبت FCM

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

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

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

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

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

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

بهترین شیوه‌های اساسی

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

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

بازیابی و ذخیره شناسه‌های نصب Firebase

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

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

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

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

مثال: ذخیره FIDها و مهرهای زمانی در Cloud Firestore

برای مثال، می‌توانید از Cloud Firestore برای ذخیره FIDها در مجموعه‌ای به نام fcmRegistrations استفاده کنید. هر شناسه سند در مجموعه با یک شناسه کاربر مطابقت دارد و سند، FID فعلی و آخرین مهر زمانی به‌روزرسانی‌شده آن را ذخیره می‌کند. همانطور که در این مثال کاتلین نشان داده شده است، از تابع set استفاده کنید:

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)
}

برای مواردی که مقداردهی اولیه خودکار غیرفعال است، در هنگام راه‌اندازی برنامه (مثلاً در onCreate() ) تابع register() فراخوانی کنید تا جریان ثبت‌نام و تحویل 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 پاسخ نامعتبری را برمی‌گرداند. اگر نیاز دارید که طبق تعاریف خودتان، موارد قدیمی را با دقت بیشتری ردیابی کنید، می‌توانید ثبت نام‌های قدیمی را به صورت پیشگیرانه حذف کنید .

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

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

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

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

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

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

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

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

  • منطق برنامه را در برنامه کلاینت خود اضافه کنید تا توکن فعلی را با استفاده از فراخوانی API مناسب (مانند token(completion): برای پلتفرم‌های اپل یا getToken() برای اندروید) بازیابی کند و سپس توکن فعلی را برای ذخیره‌سازی (همراه با یک مهر زمانی) به سرور برنامه خود ارسال کنید. این می‌تواند یک کار ماهانه باشد که برای پوشش همه کلاینت‌ها یا توکن‌ها پیکربندی شده است.
  • منطق سرور را طوری اضافه کنید که مهر زمانی توکن را در فواصل منظم، صرف نظر از اینکه توکن تغییر کرده است یا خیر، به‌روزرسانی کند.

برای مثالی از منطق اندروید برای به‌روزرسانی توکن‌های قدیمی با استفاده از 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('هر 24 ساعت').onRun(async (context) => { // دریافت تمام اسنادی که مقدار timestamp آنها از مقدار تعیین شده بیشتر است و مربوط به یک ماه گذشته نیست. const staleTokensResult = await admin.firestore().collection('fcmTokens') .where("timestamp", "<", Date.now() - EXPIRATION_TIME) .get(); // حذف دستگاه‌های دارای توکن‌های قدیمی staleTokensResult.forEach(function(doc) { doc.ref.delete(); }); });

لغو اشتراک ثبت نام‌های قدیمی از موضوعات

اگر از موضوعات استفاده می‌کنید، می‌توانید ثبت نام‌های قدیمی را از موضوعاتی که در آنها مشترک شده‌اند، لغو اشتراک کنید. این کار شامل دو مرحله است:

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

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

اندازه‌گیری موفقیت تحویل

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

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

  • آیا گوگل آنالیتیکس، داده‌های جمع‌آوری‌شده در بیگ‌کوئری یا سایر سیگنال‌های ردیابی، نشان‌دهنده‌ی فعال بودن ثبت‌نام هستند؟
  • آیا تلاش‌های قبلی برای تحویل کالا در یک بازه زمانی مشخص به طور مداوم شکست خورده‌اند؟
  • آیا شناسه نصب Firebase در ماه گذشته روی سرورهای شما به‌روزرسانی شده است؟
  • آیا FCM Data API برای دستگاه‌های اندروید، درصد بالایی از شکست‌های تحویل پیام را به دلیل droppedDeviceInactive گزارش می‌دهد؟

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