FCM रजिस्ट्रेशन टोकन को मैनेज करने के सबसे सही तरीके

अगर प्रोग्राम के ज़रिए, मैसेज भेजने के अनुरोध बनाने के लिए FCM एपीआई का इस्तेमाल किया जाता है, तो हो सकता है कि समय के साथ-साथ, इस्तेमाल न किए जा रहे डिवाइसों को मैसेज भेजकर, संसाधनों को बर्बाद किया जा रहा हो. ऐसा इसलिए, क्योंकि इन डिवाइसों के रजिस्ट्रेशन टोकन पुराने हो चुके होते हैं. इस स्थिति से, मैसेज डिलीवरी के डेटा पर असर पड़ सकता है. यह डेटा Firebase कंसोल में रिपोर्ट किया गया है या BigQuery पर एक्सपोर्ट किया गया है. इससे डिलीवरी रेट में अचानक (लेकिन असल में मान्य नहीं) गिरावट दिख सकती है. इस गाइड में, कुछ ऐसे मेज़रमेंट के बारे में बताया गया है जिनकी मदद से, मैसेज को सही लोगों तक पहुंचाने और डिलीवरी की मान्य रिपोर्टिंग पक्का की जा सकती है.

पुराने और समयसीमा खत्म हो चुके रजिस्ट्रेशन टोकन

पुराने रजिस्ट्रेशन टोकन, इस्तेमाल न किए जा रहे डिवाइसों से जुड़े टोकन होते हैं. इन डिवाइसों ने एक महीने से ज़्यादा समय से FCM से कनेक्ट नहीं किया होता. समय बीतने के साथ-साथ, इस बात की संभावना कम होती जाती है कि डिवाइस कभी FCM से दोबारा कनेक्ट होगा. इन पुराने टोकन के लिए भेजे गए मैसेज और विषय के फ़ैनआउट कभी डिलीवर नहीं हो पाएंगे.

किसी टोकन के पुराना होने की कई वजहें हो सकती हैं. उदाहरण के लिए, हो सकता है कि टोकन से जुड़ा डिवाइस खो गया हो, खराब हो गया हो या उसे स्टोरेज में रखकर भूल गए हों.

Android के लिए, जब पुराने टोकन 270 दिनों तक इस्तेमाल नहीं किए जाते हैं, तो FCM उन्हें समयसीमा खत्म हो चुके मानता है. किसी टोकन की समयसीमा खत्म होने के बाद, FCM उसे अमान्य के तौर पर मार्क करता है और उस पर मैसेज भेजने के अनुरोधों को अस्वीकार कर देता है. हालांकि, FCM अगर डिवाइस दोबारा कनेक्ट होता है और ऐप्लिकेशन खोला जाता है, तो FCM, ऐप्लिकेशन इंस्टेंस के लिए नया टोकन जारी करता है. ऐसा बहुत कम होता है.

iOS जैसे अन्य प्लैटफ़ॉर्म के लिए, FCM, पुश सेवा (जैसे, APNs) पर निर्भर करता है. इसमें, 270 दिनों तक इस्तेमाल न किए जाने पर टोकन की समयसीमा खत्म होने की सुविधा नहीं होती. इसलिए, हमारा सुझाव है कि टोकन को अप-टू-डेट रखें और पुराने रजिस्ट्रेशन टोकन हटाएं.

बुनियादी सबसे सही तरीके

आपको उन सभी ऐप्लिकेशन में कुछ बुनियादी तरीकों का पालन करना चाहिए जो प्रोग्राम के ज़रिए, मैसेज भेजने के अनुरोध बनाने के लिए FCM एपीआई का इस्तेमाल करते हैं. सबसे सही तरीके ये हैं:

  • FCM से रजिस्ट्रेशन टोकन वापस पाएं और उन्हें अपने सर्वर पर सेव करें.FCM सर्वर की एक अहम भूमिका यह है कि वह हर क्लाइंट के टोकन को ट्रैक करे और ऐक्टिव टोकन की अपडेट की गई सूची को बनाए रखे. हमारा सुझाव है कि अपने कोड और सर्वर में टोकन टाइमस्टैंप लागू करें. साथ ही, इस टाइमस्टैंप को नियमित अंतराल पर अपडेट करें.
  • टोकन को अप-टू-डेट रखें और पुराने टोकन हटाएं. FCM अब जिन टोकन को मान्य नहीं मानता उन्हें हटाने के अलावा, आपको उन अन्य संकेतों पर भी नज़र रखनी चाहिए जिनसे पता चलता है कि टोकन पुराने हो गए हैं. साथ ही, उन्हें पहले से ही हटा देना चाहिए.FCM इस गाइड में, ऐसा करने के कुछ विकल्पों के बारे में बताया गया है.

रजिस्ट्रेशन टोकन वापस पाना और सेव करना

आपके ऐप्लिकेशन के पहली बार शुरू होने पर, FCM SDK, क्लाइंट ऐप्लिकेशन इंस्टेंस के लिए रजिस्ट्रेशन टोकन जनरेट करता है. यह वह टोकन है जिसे आपको एपीआई से भेजे जाने वाले टारगेट किए गए अनुरोधों में शामिल करना होगा. इसके अलावा, इसे विषयों को टारगेट करने के लिए, विषय की सदस्यताओं में जोड़ना होगा.

हमारा सुझाव है कि आपका ऐप्लिकेशन, पहली बार शुरू होने पर इस टोकन को वापस पाए और इसे अपने ऐप्लिकेशन सर्वर पर टाइमस्टैंप के साथ सेव करे. इस टाइमस्टैंप को आपके कोड और सर्वर से लागू किया जाना चाहिए, क्योंकि यह FCM SDK टूल से नहीं मिलता.

इसके अलावा, टोकन को सर्वर पर सेव करना और जब भी यह बदलता है, तब टाइमस्टैंप को अपडेट करना ज़रूरी है. जैसे, इन स्थितियों में:

  • ऐप्लिकेशन को नए डिवाइस पर रीस्टोर किया गया हो
  • उपयोगकर्ता ने ऐप्लिकेशन को अनइंस्टॉल या फिर से इंस्टॉल किया हो
  • उपयोगकर्ता ने ऐप्लिकेशन का डेटा मिटाया हो
  • FCM ने मौजूदा टोकन की समयसीमा खत्म कर दी हो और ऐप्लिकेशन फिर से ऐक्टिव हो गया हो

उदाहरण: Cloud Firestore में टोकन और टाइमस्टैंप सेव करना

उदाहरण के लिए, Cloud Firestore नाम के कलेक्शन में टोकन सेव करने के लिए, का इस्तेमाल किया जा सकता है.fcmTokens कलेक्शन में मौजूद हर दस्तावेज़ का आईडी, उपयोगकर्ता के आईडी से मेल खाता है. साथ ही, दस्तावेज़ में मौजूदा रजिस्ट्रेशन टोकन और उसके अपडेट होने का आखिरी टाइमस्टैंप सेव होता है. यहां दिए गए Kotlin के उदाहरण में दिखाए गए तरीके से, 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)
    }

टोकन मिलने पर, Cloud Firestore में सेव किया जाता है. इसके लिए, sendTokenToServer को कॉल किया जाता है:

    /**
     * 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 से अमान्य टोकन के जवाबों का पता लगाया जाए. साथ ही, अपने सिस्टम से उन सभी रजिस्ट्रेशन टोकन को मिटाकर जवाब दें जो अमान्य हैं या जिनकी समयसीमा खत्म हो चुकी है. 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 अगर Android डिवाइस के लिए किसी टोकन की समयसीमा, 270 दिनों तक इस्तेमाल न किए जाने के बाद खत्म हो गई है या किसी क्लाइंट ने साफ़ तौर पर अनरजिस्टर किया है, तो अमान्य टोकन का जवाब देता है. अगर आपको अपनी परिभाषाओं के हिसाब से, पुराने टोकन को ज़्यादा सटीक तरीके से ट्रैक करना है, तो पुराने रजिस्ट्रेशन टोकन को पहले से ही हटाया जा सकता है.

टोकन को नियमित तौर पर अपडेट करना

हमारा सुझाव है कि अपने सर्वर पर मौजूद सभी रजिस्ट्रेशन टोकन को समय-समय पर वापस पाएं और अपडेट करें. इसके लिए, आपको यह करना होगा:

  • अपने क्लाइंट ऐप्लिकेशन में, ऐप्लिकेशन लॉजिक जोड़ें, ताकि मौजूदा टोकन को सही एपीआई कॉल (जैसे, token(completion): Apple प्लैटफ़ॉर्म के लिए या getToken() Android के लिए) का इस्तेमाल करके वापस पाया जा सके. इसके बाद, मौजूदा टोकन को अपने ऐप्लिकेशन सर्वर पर सेव करने के लिए भेजें. इसके साथ, टाइमस्टैंप भी भेजें. यह एक महीने में एक बार होने वाला काम हो सकता है, जिसे सभी क्लाइंट या टोकन के लिए कॉन्फ़िगर किया जा सकता है.
  • टोकन के टाइमस्टैंप को नियमित अंतराल पर अपडेट करने के लिए, सर्वर लॉजिक जोड़ें. भले ही, टोकन बदला हो या नहीं.

WorkManager का इस्तेमाल करके, टोकन अपडेट करने के लिए Android लॉजिक का उदाहरण देखने के लिए, Firebase ब्लॉग पर Cloud Messaging टोकन मैनेज करना लेख पढ़ें.

आप जिस भी टाइमिंग पैटर्न का पालन करें, पक्का करें कि टोकन को समय-समय पर अपडेट किया जाए. हर महीने में एक बार टोकन अपडेट करने से, बैटरी पर पड़ने वाले असर और इस्तेमाल न किए जा रहे रजिस्ट्रेशन टोकन का पता लगाने के बीच सही संतुलन बना रहता है. इस रीफ़्रेश से, यह भी पक्का होता है कि इस्तेमाल न किया जा रहा कोई भी डिवाइस, दोबारा ऐक्टिव होने पर अपना रजिस्ट्रेशन रीफ़्रेश करेगा. हर हफ़्ते से ज़्यादा बार रीफ़्रेश करने का कोई फ़ायदा नहीं है.

पुराने रजिस्ट्रेशन टोकन हटाना

किसी डिवाइस को मैसेज भेजने से पहले, पक्का करें कि डिवाइस के रजिस्ट्रेशन टोकन का टाइमस्टैंप, आपकी तय की गई समयसीमा के अंदर हो. उदाहरण के लिए, आप 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 बैकएंड से, टोकन से विषय की मैपिंग मिट जाती है.

इन दोनों चरणों का फ़ायदा यह है कि आपके फ़ैनआउट तेज़ी से होंगे, क्योंकि फ़ैनआउट के लिए कम पुराने टोकन होंगे. साथ ही, आपके पुराने ऐप्लिकेशन इंस्टेंस, दोबारा ऐक्टिव होने पर अपने-आप सदस्यता ले लेंगे.

डिलीवरी की सफलता मेज़र करना

मैसेज डिलीवरी की सबसे सटीक जानकारी पाने के लिए, सिर्फ़ उन ऐप्लिकेशन इंस्टेंस को मैसेज भेजें जिनका इस्तेमाल किया जा रहा है. यह तब और भी ज़रूरी है, जब विषयों को नियमित तौर पर मैसेज भेजे जाते हों और उनकी सदस्यता लेने वाले लोगों की संख्या ज़्यादा हो. अगर इनमें से कुछ लोग असल में इस्तेमाल नहीं किए जा रहे हैं, तो समय के साथ-साथ, डिलीवरी के आंकड़ों पर इसका काफ़ी असर पड़ सकता है.

किसी टोकन को टारगेट करने से पहले, इन बातों पर ध्यान दें:

  • क्या Google Analytics, BigQuery में कैप्चर किया गया डेटा या अन्य ट्रैकिंग सिग्नल से पता चलता है कि टोकन ऐक्टिव है?
  • क्या डिलीवरी की पिछली कोशिशें, कुछ समय से लगातार नाकाम रही हैं?
  • क्या पिछले महीने आपके सर्वर पर रजिस्ट्रेशन टोकन अपडेट किया गया है?
  • Android डिवाइसों के लिए, क्या FCM Data API मैसेज डिलीवरी में होने वाली गड़बड़ियों का ज़्यादा प्रतिशत रिपोर्ट करता है, जिसकी वजह है droppedDeviceInactive?

डिलीवरी के बारे में ज़्यादा जानने के लिए, मैसेज डिलीवरी को समझना लेख पढ़ें.