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

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

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

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

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

Android के लिए, अगर कोई रजिस्ट्रेशन 270 दिनों तक चालू नहीं रहता है, तो FCM उसे एक्सपायर मान लेता है और उसे मिटा देता है. रजिस्ट्रेशन की समयसीमा खत्म होने के बाद, FCM इसे अमान्य के तौर पर मार्क करता है और इस पर भेजे जाने वाले ईमेल अस्वीकार कर देता है. ध्यान दें कि Firebase इंस्टॉलेशन आईडी (FID), Firebase इंस्टॉलेशन सेवा (एफ़आईएस) से मैनेज किए जाते हैं, न कि एफ़सीएम से. अगर कोई डिवाइस फिर से कनेक्ट होता है और ऐप्लिकेशन को उसके रजिस्ट्रेशन के डेटा को मिटाने के बाद खोला जाता है, तो क्लाइंट ऐप्लिकेशन, FCM के साथ फिर से रजिस्टर करता है. इसके लिए, वह FIS से मिले FID का इस्तेमाल करता है. ध्यान दें कि एफ़आईडी में बदलाव हो सकता है. एफ़आईडी को फिर से जारी करने के बारे में ज़्यादा जानने के लिए, Firebase इंस्टॉलेशन मैनेज करना लेख पढ़ें.

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

सबसे सही तरीके

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

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

Firebase इंस्टॉलेशन आईडी को वापस पाना और सेव करना

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

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

अपने-आप चालू होने की सुविधा चालू है या बंद है (इसमें सुविधा काम न करने की स्थिति भी शामिल है), इसके आधार पर आपको रजिस्ट्रेशन और अपडेट को इस तरह मैनेज करना चाहिए:

  • (सुझाया गया) जब ऑटो-इनिशियलाइज़ेशन की सुविधा चालू होती है, तब: एसडीके, रजिस्ट्रेशन को अपने-आप अपडेट करता रहता है और बदलावों पर नज़र रखता है. onRegistered() कॉलबैक को ऐप्लिकेशन के स्टार्टअप के दौरान रूटीन सिंक पर नियमित रूप से शुरू किया जाता है. साथ ही, एफ़आईडी में बदलाव होने पर भी इसे शुरू किया जाता है. अपने सर्वर पर FID अपलोड करने और मौजूदा टाइमस्टैंप सेव करने के लिए, इस कॉलबैक को लागू करें.
  • अपने-आप शुरू होने की सुविधा बंद होने पर: onRegistered() कॉलबैक, शुरुआत में अपने-आप शुरू नहीं होगा. रजिस्ट्रेशन को ट्रैक करने और उन्हें अपडेट रखने के लिए, ऐप्लिकेशन के स्टार्टअप पर register() को कॉल करें. उदाहरण के लिए, Android पर मुख्य गतिविधि के onCreate() में. कॉल पूरा होने पर, एफ़आईडी का इस्तेमाल करके FCM रजिस्ट्रेशन की प्रोसेस ट्रिगर होती है. साथ ही, इसे आपके onRegistered() कॉलबैक पर डिलीवर किया जाता है. इससे आपका ऐप्लिकेशन, एफ़आईडी अपलोड कर पाता है और आपके सर्वर पर टाइमस्टैंप अपडेट कर पाता है.

उदाहरण: Cloud Firestore में एफ़आईडी और टाइमस्टैंप सेव करना

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

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

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

नियमित तौर पर रजिस्ट्रेशन अपडेट करना

चाहे आपके रजिस्ट्रेशन, एफ़आईडी पर आधारित हों या लेगसी रजिस्ट्रेशन टोकन पर, आपके सर्वर को हर अपलोड अनुरोध पर, आपके डेटाबेस में रजिस्ट्रेशन का टाइमस्टैंप हमेशा अपडेट करना चाहिए. यह टाइमस्टैंप, ऐप्लिकेशन इंस्टॉल करने के सिग्नल के तौर पर काम करता है. इससे क्लाइंट को पता चलता है कि ऐप्लिकेशन को सही तरीके से खोला गया है और FCM बैकएंड के साथ सिंक किया गया है. इस्तेमाल किए जा रहे एपीआई के हिसाब से, सही रणनीति लागू करें:

FID एपीआई का इस्तेमाल करने वाले क्लाइंट ऐप्लिकेशन के लिए, आपको रजिस्ट्रेशन वापस पाने या उन्हें रीफ़्रेश करने के लिए, क्लाइंट ऐप्लिकेशन में समय-समय पर बैकग्राउंड जॉब शेड्यूल करने की ज़रूरत नहीं है. एसडीके, अपने-आप शुरू होने की सुविधा के तहत, रीफ़्रेश होने की प्रोसेस को अपने-आप मैनेज करता है. साथ ही, ऐप्लिकेशन के स्टार्टअप के दौरान रूटीन सिंक पर आपके onRegistered() कॉलबैक को नियमित तौर पर सही मौजूदा एफ़आईडी डिलीवर करता है.

अपने सर्वर को अपडेट रखने के लिए, स्टार्टअप अपलोड की रणनीतियां लागू करें. इनके बारे में, Firebase इंस्टॉलेशन आईडी को वापस पाना और उन्हें सेव करना लेख में बताया गया है:

  • अपने-आप शुरू होने की सुविधा चालू है: SDK टूल यह पक्का करता है कि ऐप्लिकेशन शुरू होने के दौरान, रूटीन सिंक होने पर आपके सर्वर को नया एफ़आईडी अपने-आप भेजा जाए.
  • ऑटो-इनिशियलाइज़ेशन की सुविधा बंद है या काम नहीं कर रही है: ऐप्लिकेशन के शुरू होने पर register() को कॉल करें. उदाहरण के लिए, Android पर, मुख्य ऐक्टिविटी के onCreate() में. इससे रजिस्ट्रेशन सीक्वेंस को फ़ोर्स किया जा सकेगा और आपके onRegistered() कॉलबैक को FID डिलीवर किया जा सकेगा.

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

रजिस्ट्रेशन टोकन के लिए इस्तेमाल किए जाने वाले पुराने एपीआई

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

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

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

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

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

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

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

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

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