अगर प्रोग्राम के हिसाब से अनुरोध भेजने के लिए 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 एपीआई के साथ, गड़बड़ी के इन मैसेज से यह पता चल सकता है कि आपके भेजने के अनुरोध में अमान्य या समयसीमा खत्म हो चुके टोकन टारगेट किए गए हैं:
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 दिनों के बाद खत्म हो गई हो या क्लाइंट ने साफ़ तौर पर रजिस्टर न किया हो. अगर आपको अपनी परिभाषाओं के हिसाब से, पुराने टोक़न को ज़्यादा सटीक तरीके से ट्रैक करना है, तो आपके पास पुराने रजिस्ट्रेशन टोकन को पहले से हटाने का विकल्प है.
टोकन को नियमित तौर पर अपडेट करना
हमारा सुझाव है कि आप समय-समय पर अपने सर्वर पर सभी रजिस्ट्रेशन टोकन वापस पाएं और अपडेट करें. इसके लिए, आपको:
- अपने क्लाइंट ऐप्लिकेशन में ऐप्लिकेशन लॉजिक जोड़ें, ताकि सही एपीआई कॉल (जैसे, Apple प्लैटफ़ॉर्म के लिए
token(completion):
या Android के लिएgetToken()
) का इस्तेमाल करके, मौजूदा टोकन को वापस पाया जा सके. इसके बाद, मौजूदा टोकन को स्टोरेज के लिए अपने ऐप्लिकेशन सर्वर पर भेजें (टाइमस्टैंप के साथ). यह हर महीने की एक ऐसी जॉब हो सकती है जिसे सभी क्लाइंट या टोकन को कवर करने के लिए कॉन्फ़िगर किया गया हो. - टोकन के टाइमस्टैंप को नियमित अंतराल पर अपडेट करने के लिए, सर्वर लॉजिक जोड़ें. इससे कोई फ़र्क़ नहीं पड़ता कि टोकन बदला है या नहीं.
WorkManager का इस्तेमाल करके, टोकन अपडेट करने के लिए Android लॉजिक का उदाहरण पाने के लिए, 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(); });
});
पुराने टोकन को विषयों से अनसब्सक्राइब करना
अगर आपने विषयों का इस्तेमाल किया है, तो उन विषयों से पुराने टोकन को भी अनरजिस्टर किया जा सकता है जिनकी सदस्यता आपने ली है. इसके लिए, दो चरण पूरे करने होंगे:
- आपके ऐप्लिकेशन को हर महीने एक बार और रजिस्टरेशन टोकन बदलने पर, विषयों की फिर से सदस्यता लेनी चाहिए. इससे, ऐप्लिकेशन फिर से चालू होने पर सदस्यताएं अपने-आप फिर से दिखने लगती हैं.
- अगर कोई ऐप्लिकेशन इंस्टेंस एक महीने (या आपकी तय की गई समयसीमा) तक निष्क्रिय रहता है, तो आपको Firebase Admin SDK टूल का इस्तेमाल करके, उसे विषयों की सदस्यता से हटा देना चाहिए. ऐसा करने पर, FCM बैकएंड से टोकन को विषय की मैपिंग मिट जाएगी.
इन दो चरणों का फ़ायदा यह है कि आपके फ़ैनआउट तेज़ी से होंगे, क्योंकि फ़ैनआउट करने के लिए पुराने टोकन कम होंगे. साथ ही, आपके पुराने ऐप्लिकेशन इंस्टेंस फिर से चालू होने पर, वे अपने-आप फिर से सदस्यता ले लेंगे.
डिलीवरी की सफलता का आकलन करना
मैसेज डिलीवरी की सटीक जानकारी पाने के लिए, सिर्फ़ उन ऐप्लिकेशन इंस्टेंस पर मैसेज भेजें जिनका इस्तेमाल किया जा रहा है. यह खास तौर पर तब ज़रूरी है, जब आप अक्सर उन विषयों पर मैसेज भेजते हों जिनके लिए बड़ी संख्या में सदस्य हैं. अगर उन सदस्यों में से कुछ असल में इनऐक्टिव हैं, तो समय के साथ डिलीवरी के आंकड़ों पर काफ़ी असर पड़ सकता है.
किसी टोकन के लिए मैसेज टारगेट करने से पहले, इन बातों का ध्यान रखें:
- क्या Google Analytics, BigQuery में कैप्चर किया गया डेटा या अन्य ट्रैकिंग सिग्नल से पता चलता है कि टोकन चालू है?
- क्या डिलीवरी के पिछले प्रयासों में लगातार कुछ समय तक गड़बड़ी हुई है?
- क्या पिछले महीने आपके सर्वर पर रजिस्ट्रेशन टोकन अपडेट किया गया है?
- क्या Android डिवाइसों के लिए, FCM डेटा एपीआई,
droppedDeviceInactive
की वजह से मैसेज डिलीवरी में होने वाली गड़बड़ियों का ज़्यादा प्रतिशत बताता है?
डिलीवरी के बारे में ज़्यादा जानने के लिए, मैसेज की डिलीवरी के बारे में जानकारी देखें.