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

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

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

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

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

برای اندروید، وقتی توکن‌های قدیمی به ۲۷۰ روز عدم فعالیت می‌رسند، FCM آنها را منقضی شده در نظر می‌گیرد. پس از انقضای یک توکن، FCM آن را نامعتبر علامت‌گذاری کرده و ارسال‌ها به آن را رد می‌کند. با این حال، FCM در موارد نادری که دستگاه دوباره متصل می‌شود و برنامه باز می‌شود، یک توکن جدید برای نمونه برنامه صادر می‌کند.

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

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

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

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

بازیابی و ذخیره توکن‌های ثبت نام

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

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

همچنین، مهم است که توکن را در سرور ذخیره کنید و هر زمان که تغییر کرد، برچسب زمانی را به‌روزرسانی کنید، مانند زمانی که:

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

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

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

    /**
     * Persist token to third-party servers.
     *
     * Modify this method to associate the user's FCM registration token with any server-side account
     * maintained by your application.
     *
     * @param token The new token.
     */
    private fun sendTokenToServer(token: String?) {
        // If you're running your own server, call API to send token and today's date for the user

        // Example shown below with Firestore
        // Add token and timestamp to Firestore for this user
        val deviceToken = hashMapOf(
            "token" to token,
            "timestamp" to FieldValue.serverTimestamp(),
        )
        // Get user ID from Firebase Auth or your own server
        Firebase.firestore.collection("fcmTokens").document("myuserid")
            .set(deviceToken)
    }

هر زمان که یک توکن بازیابی می‌شود، با فراخوانی sendTokenToServer در Cloud Firestore ذخیره می‌شود:

    /**
     * Called if the FCM registration token is updated. This may occur if the security of
     * the previous token had been compromised. Note that this is called when the
     * FCM registration token is initially generated so this is where you would retrieve the token.
     */
    override fun onNewToken(token: String) {
        Log.d(TAG, "Refreshed token: $token")

        // If you want to send messages to this application instance or
        // manage this apps subscriptions on the server side, send the
        // FCM registration token to your app server.
        sendTokenToServer(token)
    }
        var token = Firebase.messaging.token.await()

        // Check whether the retrieved token matches the one on your server for this user's device
        val preferences = this.getPreferences(Context.MODE_PRIVATE)
        val tokenStored = preferences.getString("deviceToken", "")
        lifecycleScope.launch {
            if (tokenStored == "" || tokenStored != token)
            {
                // If you have your own server, call API to send the above token and Date() for this user's device

                // Example shown below with Firestore
                // Add token and timestamp to Firestore for this user
                val deviceToken = hashMapOf(
                    "token" to token,
                    "timestamp" to FieldValue.serverTimestamp(),
                )

                // Get user ID from Firebase Auth or your own server
                Firebase.firestore.collection("fcmTokens").document("myuserid")
                    .set(deviceToken).await()
            }
        }

حفظ تازگی توکن‌ها و حذف توکن‌های قدیمی

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

بسته به مورد استفاده شما، یک ماه ممکن است خیلی کوتاه یا خیلی طولانی باشد، بنابراین تعیین معیارهایی که برای شما مناسب است به شما بستگی دارد.

تشخیص پاسخ‌های توکن نامعتبر از بک‌اند FCM

مطمئن شوید که پاسخ‌های توکن نامعتبر از FCM را شناسایی کرده و با حذف هرگونه توکن ثبت نام که نامعتبر یا منقضی شده هستند از سیستم خود، به آنها پاسخ دهید. با API HTTP v1، این پیام‌های خطا ممکن است نشان دهند که درخواست ارسالی شما توکن‌های نامعتبر یا منقضی شده را هدف قرار داده است:

  • UNREGISTERED (HTTP 404)
  • INVALID_ARGUMENT (HTTP 400)

اگر مطمئن هستید که بار داده پیام معتبر است و هر یک از این پاسخ‌ها را برای یک توکن هدفمند دریافت می‌کنید، می‌توانید رکورد این توکن را با خیال راحت حذف کنید، زیرا دیگر هرگز معتبر نخواهد بود. به عنوان مثال، برای حذف توکن‌های نامعتبر از Cloud Firestore ، می‌توانید تابعی مانند زیر را پیاده‌سازی و اجرا کنید:

    // Registration token comes from the client FCM SDKs
    const registrationToken = 'YOUR_REGISTRATION_TOKEN';

    const message = {
    data: {
        // Information you want to send inside of notification
    },
    token: registrationToken
    };

    // Send message to device with provided registration token
    getMessaging().send(message)
    .then((response) => {
        // Response is a message ID string.
    })
    .catch((error) => {
        // Delete token 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
            token for the user

            // Example shown below with Firestore
            // Get user ID from Firebase Auth or your own server
            Firebase.firestore.collection("fcmTokens").document(user.uid).delete()
        }
    });

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

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

توصیه می‌کنیم که به صورت دوره‌ای تمام توکن‌های ثبت‌نام را روی سرور خود بازیابی و به‌روزرسانی کنید. این امر مستلزم آن است که:

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

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

صرف نظر از الگوی زمان‌بندی که دنبال می‌کنید، حتماً توکن‌ها را به صورت دوره‌ای به‌روزرسانی کنید. فرکانس به‌روزرسانی ماهی یک بار، تعادل خوبی بین تأثیر باتری و شناسایی توکن‌های ثبت‌نام غیرفعال ایجاد می‌کند. با انجام این به‌روزرسانی، همچنین اطمینان حاصل می‌کنید که هر دستگاهی که غیرفعال می‌شود، هنگام فعال شدن مجدد، ثبت‌نام خود را به‌روزرسانی می‌کند. انجام به‌روزرسانی بیشتر از هفتگی هیچ فایده‌ای ندارد.

توکن‌های ثبت‌نام قدیمی را حذف کنید

قبل از ارسال پیام به یک دستگاه، مطمئن شوید که مهر زمانی توکن ثبت دستگاه در بازه زمانی پنجره‌ی استهلاک شما قرار دارد. برای مثال، می‌توانید Cloud Functions for Firebase پیاده‌سازی کنید تا یک بررسی روزانه انجام شود تا مطمئن شوید که مهر زمانی در یک بازه زمانی پنجره‌ی استهلاک تعریف‌شده مانند const EXPIRATION_TIME = 1000 * 60 * 60 * 24 * 30; و سپس توکن‌های استهلاک را حذف کنید:

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. برنامه شما باید ماهی یک بار و هر زمان که توکن ثبت نام تغییر می‌کند، در موضوعات جدید مشترک شود. این یک راه حل خود ترمیمی است که در آن، اشتراک‌ها به طور خودکار با فعال شدن مجدد برنامه، دوباره ظاهر می‌شوند.
  2. اگر یک نمونه برنامه به مدت یک ماه (یا به مدت یک ماه) غیرفعال باشد، باید با استفاده از Firebase Admin SDK، اشتراک آن را از موضوعات لغو کنید تا نگاشت توکن به موضوع از بک‌اند FCM حذف شود.

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

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

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

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

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

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