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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

उदाहरण के लिए, fcmTokens नाम के कलेक्शन में टोकन स्टोर करने के लिए, Cloud Firestore का इस्तेमाल किया जा सकता है. कलेक्शन में मौजूद हर दस्तावेज़ आईडी एक यूज़र आईडी से जुड़ा होता है. दस्तावेज़ में मौजूदा रजिस्ट्रेशन टोकन और आखिरी बार अपडेट किया गया टाइमस्टैंप सेव होता है. set फ़ंक्शन का इस्तेमाल करें, जैसा कि Kotlin के इस उदाहरण में दिखाया गया है:

    /**
     * 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 से मिले अमान्य टोकन रिस्पॉन्स का पता लगाना न भूलें. साथ ही, ऐसे सभी रजिस्ट्रेशन टोकन को अपने सिस्टम से मिटा दें जिन्हें अमान्य माना जाता है या जिनकी समयसीमा खत्म हो चुकी है. एचटीटीपी v1 API का इस्तेमाल करने पर, गड़बड़ी के ये मैसेज दिख सकते हैं कि ईमेल भेजने के आपके अनुरोध में, अमान्य या ऐसे टोकन शामिल हैं जिनकी समयसीमा खत्म हो चुकी है:

  • UNREGISTERED (एचटीटीपी 404)
  • INVALID_ARGUMENT (एचटीटीपी 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 (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 सिर्फ़ तब अमान्य टोकन रिस्पॉन्स दिखाएगा, जब टोकन की समयसीमा 270 दिनों के बाद खत्म हो गई हो या किसी क्लाइंट का रजिस्ट्रेशन साफ़ तौर पर रद्द कर दिया गया हो. अगर आपको अपनी परिभाषाओं के मुताबिक पुरानी जानकारी को सटीक तरीके से ट्रैक करना है, तो पुराने रजिस्ट्रेशन टोकन हटाए जा सकते हैं.

टोकन को समय-समय पर अपडेट करें

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

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

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

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

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

किसी डिवाइस पर मैसेज भेजने से पहले, पक्का करें कि डिवाइस के रजिस्ट्रेशन टोकन का टाइमस्टैंप, पुराने वर्शन की समयसीमा के अंदर हो. उदाहरण के लिए, हर दिन जांच करने के लिए 'Firebase के लिए Cloud Functions' लागू किया जा सकता है. इससे यह पक्का किया जा सकता है कि टाइमस्टैंप, पुरानी जानकारी वाली विंडो की अवधि के अंदर है, जैसे कि 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 एडमिन SDK का इस्तेमाल करने वाले विषयों से उसकी सदस्यता छोड़ देनी चाहिए. इससे FCM बैकएंड से विषय मैपिंग का टोकन मिटाया जा सकता है.

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

डिलीवरी की सफलता का आकलन करना

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

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

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

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