Firebase FCM बल onTokenRefresh () कहा जाता है


111

मैं अपने ऐप को GCM से FCM में माइग्रेट कर रहा हूं।

जब कोई नया उपयोगकर्ता मेरा ऐप इंस्टॉल करता है, तो onTokenRefresh()स्वचालित रूप से कॉल किया जा रहा है। समस्या यह है कि उपयोगकर्ता अभी तक लॉग इन नहीं हुआ है (नो यूजर आईडी)।

onTokenRefresh()उपयोगकर्ता लॉग-इन करने के बाद मैं कैसे ट्रिगर कर सकता हूं ?


1
नीचे दिए गए लिंक में एक बहुत ही समान प्रश्न पहले से ही पूछा गया है। जांच करें कि क्या उत्तर आपके लिए उपयोगी है: stackoverflow.com/questions/37517254/…
डिएगो जियोर्जिनी

जवाबों:


172

onTokenRefresh()विधि जब भी नया टोकन उत्पन्न होता है के नाम से जाना जा रहा है। ऐप इंस्टॉल होने पर, यह तुरंत जेनरेट हो जाएगा (जैसा कि आपने मामला पाया है)। यह भी कहा जाएगा कि टोकन कब बदल गया है।

FirebaseCloudMessagingगाइड के अनुसार :

आप एकल, विशिष्ट डिवाइस पर सूचनाओं को लक्षित कर सकते हैं। आपके ऐप के शुरुआती स्टार्टअप पर, FCM SDK क्लाइंट ऐप इंस्टेंट के लिए पंजीकरण टोकन बनाता है।

स्क्रीनशॉट

स्रोत लिंक: https://firebase.google.com/docs/notifications/android/console-device#access_the_registration_token

इसका मतलब है कि टोकन पंजीकरण प्रति ऐप है। ऐसा लगता है कि उपयोगकर्ता द्वारा लॉग इन करने के बाद आप टोकन का उपयोग करना चाहते हैं। मेरा सुझाव है कि आप टोकन onTokenRefresh()को आंतरिक संग्रहण या साझा प्राथमिकताओं में सहेज सकते हैं। फिर, उपयोगकर्ता द्वारा लॉग इन करने के बाद भंडारण से टोकन को पुनः प्राप्त करें और आवश्यकतानुसार अपने सर्वर से टोकन को पंजीकृत करें।

यदि आप मैन्युअल रूप से बाध्य करना चाहते हैं onTokenRefresh(), तो आप एक IntentService बना सकते हैं और टोकन इंस्टेंस को हटा सकते हैं। फिर, जब आप getToken को कॉल करते हैं, तो onTokenRefresh()विधि फिर से कॉल की जाएगी।

उदाहरण कोड:

public class DeleteTokenService extends IntentService
{
    public static final String TAG = DeleteTokenService.class.getSimpleName();

    public DeleteTokenService()
    {
        super(TAG);
    }

    @Override
    protected void onHandleIntent(Intent intent)
    {
        try
        {
            // Check for current token
            String originalToken = getTokenFromPrefs();
            Log.d(TAG, "Token before deletion: " + originalToken);

            // Resets Instance ID and revokes all tokens.
            FirebaseInstanceId.getInstance().deleteInstanceId();

            // Clear current saved token
            saveTokenToPrefs("");

            // Check for success of empty token
            String tokenCheck = getTokenFromPrefs();
            Log.d(TAG, "Token deleted. Proof: " + tokenCheck);

            // Now manually call onTokenRefresh()
            Log.d(TAG, "Getting new token");
            FirebaseInstanceId.getInstance().getToken();
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }
    }

    private void saveTokenToPrefs(String _token)
    {
        // Access Shared Preferences
        SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
        SharedPreferences.Editor editor = preferences.edit();

        // Save to SharedPreferences
        editor.putString("registration_id", _token);
        editor.apply();
    }

    private String getTokenFromPrefs()
    {
        SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
        return preferences.getString("registration_id", null);
    }
}

संपादित करें

FirebaseInstanceIdService

सार्वजनिक वर्ग FirebaseInstanceIdService सेवा प्रदान करता है

यह वर्ग पदावनत है। FirebaseMessagingService में onNewToken को ओवरराइड करने के पक्ष में। एक बार लागू होने के बाद, इस सेवा को सुरक्षित रूप से हटाया जा सकता है।

onTokenRefresh () पदावनत है । का प्रयोग करें onNewToken()मेंMyFirebaseMessagingService

public class MyFirebaseMessagingService extends FirebaseMessagingService {

@Override
public void onNewToken(String s) {
    super.onNewToken(s);
    Log.e("NEW_TOKEN",s);
    }

@Override
public void onMessageReceived(RemoteMessage remoteMessage) {
    super.onMessageReceived(remoteMessage);
    }
} 

27
भले ही onTokenRefresh () उपयोगकर्ता को लॉग इन करने से पहले कहा जाता है, इसे स्थानीय रूप से संग्रहीत करने का काम करने के बजाय, जब उपयोगकर्ता लॉग इन करता है, तो आप FirebaseInstanceId.getInstance ()। GetToken () का उपयोग करके टोकन पुनः प्राप्त कर सकते हैं और इसे सर्वर पर भेज सकते हैं। पंजीकरण कराना। (जब तक आप इसे अपने सर्वर से एक पुराने टोकन को हटाने के लिए स्थानीय रूप से संग्रहीत नहीं करना चाहते हैं)
geekoraul

10
FireBase चतुर है और यह onTokenRefresh () विधि को कॉल करेगा, केवल अगर वहाँ टोकन नहीं है (इसे हटा दिया गया है या इसे पहली बार कहा जाता है) या कुछ और होता है और टोकन बदल दिया गया है। अगर कोई onTokenRefresh पर कॉल करना चाहता है तो टोकन को हटा सकता है और फिर FirebaseInstanceId.getInstance ()। GetToken () को कॉल कर सकता है। ऑपरेशन FirebaseInstanceId.getInstance ()। DeleteInstanceId () को AsyncTask या नए थ्रेड में होने की आवश्यकता है, यह MainThread पर नहीं हो सकता है !!!
स्टॉयचो एंड्रीव

3
क्यों नहीं बस FirebaseInstanceId.getToken को कॉल करें?
esong

1
अच्छी तरह से, IntentService में कॉल करते समय पूरी तरह से काम किया, और Prefs में टोकन को बचाने की कोई आवश्यकता नहीं है, मुझे लगता है। चूंकि FirebaseInstanceId.getInstance () हटाएं। valueInstanceId () तक मान नहीं बदलता है; कहा जाता है। किंडा ने मेरा दिन बचाया। :)
डिटॉक्सिक-सोल

5
साझा प्राथमिकताओं के लिए टोकन को क्यों बचाएं - यदि आप इसकी कीमत पाने के लिए किसी भी समय FirebaseInstanceId.getInstance ()। GetToken () कॉल कर सकते हैं
अलेक्जेंडर फरबर

18

FirebaseInstanceIdServiceताज़ा टोकन प्राप्त करने के लिए कार्यान्वित करने का प्रयास करें।

पंजीकरण टोकन एक्सेस करें:

आप FirebaseInstanceIdService को बढ़ाकर टोकन के मूल्य तक पहुँच सकते हैं । सुनिश्चित करें कि आपने सेवा को अपने मेनिफ़ेस्ट में शामिल कर लिया है , फिर उसके getTokenसंदर्भ में कॉल करें onTokenRefreshऔर दिखाए अनुसार मान लॉग करें:

     @Override
public void onTokenRefresh() {
    // Get updated InstanceID token.
    String refreshedToken = FirebaseInstanceId.getInstance().getToken();
    Log.d(TAG, "Refreshed token: " + refreshedToken);

    // TODO: Implement this method to send any registration to your app's servers.
    sendRegistrationToServer(refreshedToken);
}

पूर्ण कोड:

   import android.util.Log;

import com.google.firebase.iid.FirebaseInstanceId;
import com.google.firebase.iid.FirebaseInstanceIdService;


public class MyFirebaseInstanceIDService extends FirebaseInstanceIdService {

    private static final String TAG = "MyFirebaseIIDService";

    /**
     * Called if InstanceID token is updated. This may occur if the security of
     * the previous token had been compromised. Note that this is called when the InstanceID token
     * is initially generated so this is where you would retrieve the token.
     */
    // [START refresh_token]
    @Override
    public void onTokenRefresh() {
        // Get updated InstanceID token.
        String refreshedToken = FirebaseInstanceId.getInstance().getToken();
        Log.d(TAG, "Refreshed token: " + refreshedToken);

        // TODO: Implement this method to send any registration to your app's servers.
        sendRegistrationToServer(refreshedToken);
    }
    // [END refresh_token]

    /**
     * Persist token to third-party servers.
     *
     * Modify this method to associate the user's FCM InstanceID token with any server-side account
     * maintained by your application.
     *
     * @param token The new token.
     */
    private void sendRegistrationToServer(String token) {
        // Add custom implementation, as needed.
    }
}

मेरा जवाब यहां देखें ।

संपादन:

आपको अपने आप से एक FirebaseInstanceIdService शुरू नहीं करना चाहिए ।

इसे कॉल किया जाएगा जब सिस्टम निर्धारित करता है कि टोकन को ताज़ा करने की आवश्यकता है। एप्लिकेशन को getToken () को कॉल करना चाहिए और सभी एप्लिकेशन सर्वरों को टोकन भेजना चाहिए।

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

  • ऐप इंस्टेंस आईडी को हटाता है
  • ऐप को एक नए डिवाइस पर बहाल किया गया है
  • एप्लिकेशन को अनइंस्टॉल / पुनर्स्थापित करें
  • उपयोगकर्ता एप्लिकेशन डेटा को साफ़ करता है

सिस्टम टोकन अपडेट के साथ ओवरलोडिंग एप्लिकेशन सर्वर से बचने के लिए सभी डिवाइसों में रिफ्रेश इवेंट को थ्रॉटल कर देगा।

नीचे दिए गए तरीके आज़माएँ :

आप अपने मुख्य थ्रेड (चाहे वह एक सेवा, AsyncTask, आदि हो ) से कहीं भी FirebaseInstanceID.getToken () कॉल करेंगे, स्थानीय रूप से लौटे टोकन को स्टोर करें और इसे अपने सर्वर पर भेजें। फिर जब भी onTokenRefresh()बुलाया जाता है, तो आप FirebaseInstanceID.getToken () को फिर से कॉल करेंगे , एक नया टोकन प्राप्त करेंगे, और उस सर्वर को भेजेंगे (शायद पुराने टोकन के साथ-साथ आपका सर्वर भी इसे हटा सकता है, इसे नए के साथ बदल सकता है) ।


2
मैंने FirebaseInstanceIdService को लागू किया है, समस्या onTokenRefresh है () उपयोगकर्ता द्वारा ऐप इंस्टॉल किए जाने के लगभग तुरंत बाद कहा जा रहा है। मुझे लॉगिन / साइनअप करने के बाद इसे कॉल करने की आवश्यकता है
TareK Khoury

1
तो FirebaseInstanceId को हटाने से टोकन ताज़ा हो जाएगा, धन्यवाद!
लुई कैड

GCM के बाद FCM, FirebaseInstanceId.getInstance ()। getToken (); हमेशा अशक्त रहो। कोई भी समाधान?
गोविंदा पालीवाल

@TareKhoury आप इस विधि को कॉल कर सकते हैं जहाँ कभी टोकन प्राप्त करना आवश्यक है। । FirebaseInstanceId.getInstance () getToken ();
sssvrock

क्लाइंट ऐप अपडेट के मामले में @pRaNaY किसे onTokenRefresh()कहा जाएगा ?
पीयूष कुकडिय़ा

2

मैं साझा झंडे में एक झंडे को बनाए रख रहा हूं जो बताता है कि क्या जीसीएम टोकन को सर्वर पर भेजा गया है या नहीं। हर बार स्प्लैश स्क्रीन में मैं एक विधि sendDevicetokenToServer कह रहा हूं। यह विधि जांचती है कि क्या यूजर आईडी खाली नहीं है और जीसीएम स्थिति भेज देता है तो सर्वर को टोकन भेजें।

public static void  sendRegistrationToServer(final Context context) {

if(Common.getBooleanPerf(context,Constants.isTokenSentToServer,false) ||
        Common.getStringPref(context,Constants.userId,"").isEmpty()){

    return;
}

String token =  FirebaseInstanceId.getInstance().getToken();
String userId = Common.getUserId(context);
if(!userId.isEmpty()) {
    HashMap<String, Object> reqJson = new HashMap<>();
    reqJson.put("deviceToken", token);
    ApiInterface apiService =
            ApiClient.getClient().create(ApiInterface.class);

    Call<JsonElement> call = apiService.updateDeviceToken(reqJson,Common.getUserId(context),Common.getAccessToken(context));
    call.enqueue(new Callback<JsonElement>() {
        @Override
        public void onResponse(Call<JsonElement> call, Response<JsonElement> serverResponse) {

            try {
                JsonElement jsonElement = serverResponse.body();
                JSONObject response = new JSONObject(jsonElement.toString());
                if(context == null ){
                    return;
                }
                if(response.getString(Constants.statusCode).equalsIgnoreCase(Constants.responseStatusSuccess)) {

                    Common.saveBooleanPref(context,Constants.isTokenSentToServer,true);
                }
            }catch (Exception e){
                e.printStackTrace();
            }
        }

        @Override
        public void onFailure(Call<JsonElement> call, Throwable throwable) {

            Log.d("", "RetroFit2.0 :getAppVersion: " + "eroorrrrrrrrrrrr");
            Log.e("eroooooooorr", throwable.toString());
        }
    });

}

}

MyFirebaseInstanceIDService वर्ग में

    @Override
public void onTokenRefresh() {
    // Get updated InstanceID token.
    String refreshedToken = FirebaseInstanceId.getInstance().getToken();
    Log.d(TAG, "Refreshed token: " + refreshedToken);

    // If you want to send messages to this application instance or
    // manage this apps subscriptions on the server side, send the
    // Instance ID token to your app server.
    Common.saveBooleanPref(this,Constants.isTokenSentToServer,false);
    Common.sendRegistrationToServer(this);
    FirebaseMessaging.getInstance().subscribeToTopic("bloodRequest");
}

2

दोस्तों इसका बहुत ही सरल उपाय है

https://developers.google.com/instance-id/guides/android-implementation#generate_a_token

नोट: यदि आपके ऐप ने टोकन का उपयोग किया था जिसे deleteInstanceID द्वारा हटा दिया गया था, तो आपके ऐप को प्रतिस्थापन टोकन उत्पन्न करना होगा।

उदाहरण आईडी हटाने के बजाय, केवल टोकन हटाएं:

String authorizedEntity = PROJECT_ID;
String scope = "GCM";
InstanceID.getInstance(context).deleteToken(authorizedEntity,scope);

2
मेरे लिए काम नहीं किया। DeleteToken () को कॉल करने के बाद, getToken () पहले की तरह ही टोकन देता है और onTokenRefresh नहीं कहा जाता था।
लैरा

1

यह RxJava2 परिदृश्य में है जब एक उपयोगकर्ता आपके ऐप से लॉगआउट करता है और अन्य उपयोगकर्ता लॉगिन (एक ही ऐप) लॉग इन करते हैं और लॉगिन करने के लिए कॉल करते हैं (यदि गतिविधि शुरू होने के समय उपयोगकर्ता का डिवाइस पहले इंटरनेट कनेक्शन नहीं था और हमें टोकन भेजने की आवश्यकता है लॉगिन एपीआई)

Single.fromCallable(() -> FirebaseInstanceId.getInstance().getToken())
            .flatMap( token -> Retrofit.login(userName,password,token))
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(simple -> {
                if(simple.isSuccess){
                    loginedSuccessfully();
                }
            }, throwable -> Utils.longToast(context, throwable.getLocalizedMessage()));

लॉग इन करें

@FormUrlEncoded
@POST(Site.LOGIN)
Single<ResponseSimple> login(@Field("username") String username,
                         @Field("password") String pass,
                         @Field("token") String token

);

0

यह उत्तर आवृत्ति आईडी को नष्ट नहीं करता है, इसके बजाय यह वर्तमान प्राप्त करने में सक्षम है। यह साझा वरीयताओं में एक ताज़ा भी है।

strings.xml

<string name="pref_firebase_instance_id_key">pref_firebase_instance_id</string>
<string name="pref_firebase_instance_id_default_key">default</string>

उपयोगिता.जावा (कोई भी वर्ग जहाँ आप प्राथमिकताएँ प्राप्त करना / प्राप्त करना चाहते हैं)

public static void setFirebaseInstanceId(Context context, String InstanceId) {
    SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
    SharedPreferences.Editor editor;
    editor = sharedPreferences.edit();
    editor.putString(context.getString(R.string.pref_firebase_instance_id_key),InstanceId);
    editor.apply();
}

public static String getFirebaseInstanceId(Context context) {
    SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
    String key = context.getString(R.string.pref_firebase_instance_id_key);
    String default_value = context.getString(R.string.pref_firebase_instance_id_default_key);
    return sharedPreferences.getString(key, default_value);
}

MyFirebaseInstanceIdService.java (FirebaseInstanceIdService का विस्तार)

@Override
public void onCreate()
{
    String CurrentToken = FirebaseInstanceId.getInstance().getToken();

    //Log.d(this.getClass().getSimpleName(),"Inside Instance on onCreate");
    String savedToken = Utility.getFirebaseInstanceId(getApplicationContext());
    String defaultToken = getApplication().getString(R.string.pref_firebase_instance_id_default_key);

    if(CurrentToken != null && !savedToken.equalsIgnoreCase(defaultToken))
    //currentToken is null when app is first installed and token is not available
    //also skip if token is already saved in preferences...
    {
        Utility.setFirebaseInstanceId(getApplicationContext(),CurrentToken);
    }
    super.onCreate();
}

@Override
public void onTokenRefresh() {
     .... prev code
      Utility.setFirebaseInstanceId(getApplicationContext(),refreshedToken);
     ....

}

एंड्रॉइड 2.0 और onCreateसेवा के ऊपर स्वचालित रूप से शुरू होने पर ( स्रोत ) शुरू नहीं किया जाता है । इसके बजाय onStartCommandओवरराइड और उपयोग किया जाता है। लेकिन वास्तविक FirebaseInstanceIdService में इसे अंतिम घोषित किया जाता है और इसे ओवरराइड नहीं किया जा सकता। हालांकि, जब हम स्टार्ट सर्विस () का उपयोग करके सेवा शुरू करते हैं, यदि सेवा पहले से चल रही है, तो इसका मूल उदाहरण उपयोग किया जाता है (जो अच्छा है)। हमारे onCreate () (ऊपर परिभाषित) भी आह्वान किया गया!।

MainActivity की भीख में या जो भी आपको लगता है कि आपको आईडी की आवश्यकता है, उसका उपयोग करें।

MyFirebaseInstanceIdService myFirebaseInstanceIdService = new MyFirebaseInstanceIdService();
Intent intent= new Intent(getApplicationContext(),myFirebaseInstanceIdService.getClass());
//Log.d(this.getClass().getSimpleName(),"Starting MyFirebaseInstanceIdService");
startService(intent); //invoke onCreate

और अंत में,

Utility.getFirebaseInstanceId(getApplicationContext())

ध्यान दें , आप getFirebaseInstanceId पद्धति से startervice () कोड को स्थानांतरित करने का प्रयास करके इसे बढ़ा सकते हैं।


यदि आप पहली बार ऐप को रीसेट / रन करते हैं, तो टोकन को रीफ्रेश करने में कुछ समय लगता है। तो आपको एक या दो मिनट के लिए स्ट्रिंग "डिफ़ॉल्ट" मिल जाएगी।
वरुण गर्ग

0
    [Service]
[IntentFilter(new[] { "com.google.firebase.INSTANCE_ID_EVENT" })]
class MyFirebaseIIDService: FirebaseInstanceIdService
{
    const string TAG = "MyFirebaseIIDService";
    NotificationHub hub;

    public override void OnTokenRefresh()
    {
        var refreshedToken = FirebaseInstanceId.Instance.Token;
        Log.Debug(TAG, "FCM token: " + refreshedToken);
        SendRegistrationToServer(refreshedToken);
    }

    void SendRegistrationToServer(string token)
    {
        // Register with Notification Hubs
        hub = new NotificationHub(Constants.NotificationHubName,
                                    Constants.ListenConnectionString, this);
        Employee employee = JsonConvert.DeserializeObject<Employee>(Settings.CurrentUser);
        //if user is not logged in 
        if (employee != null)
        {
            var tags = new List<string>() { employee.Email};
            var regID = hub.Register(token, tags.ToArray()).RegistrationId;

            Log.Debug(TAG, $"Successful registration of ID {regID}");
        }
        else
        {
            FirebaseInstanceId.GetInstance(Firebase.FirebaseApp.Instance).DeleteInstanceId();
            hub.Unregister();
        }
    }
}

0

FirebaseInstanceIdService

यह वर्ग पदावनत है। FirebaseMessagingService में onNewToken को ओवरराइड करने के पक्ष में। एक बार लागू होने के बाद, इस सेवा को सुरक्षित रूप से हटाया जा सकता है।

ऐसा करने का नया तरीका onNewTokenविधि को ओवरराइड करना होगाFirebaseMessagingService

public class MyFirebaseMessagingService extends FirebaseMessagingService {
    @Override
    public void onNewToken(String s) {
        super.onNewToken(s);
        Log.e("NEW_TOKEN",s);
    }

    @Override
    public void onMessageReceived(RemoteMessage remoteMessage) {
        super.onMessageReceived(remoteMessage);
    }
} 

इसके अलावा मैनिफेस्ट.एक्सएमएल में सेवा जोड़ना न भूलें

<service
    android:name=".MyFirebaseMessagingService"
    android:stopWithTask="false">
    <intent-filter>
        <action android:name="com.google.firebase.MESSAGING_EVENT" />
    </intent-filter>
</service>

0

मैं अपने डिवाइसटोकन को कैसे अपडेट करूं

सबसे पहले जब मैं लॉगिन करता हूं तो मैं उपयोगकर्ता संग्रह के तहत पहला डिवाइस टोकन भेजता हूं और वर्तमान उपयोगकर्ता लॉग इन करता हूं।

उसके बाद, मैं सिर्फ onNewToken(token:String)अपने में ओवरराइड करता हूं FirebaseMessagingService()और उस उपयोगकर्ता के लिए एक नया टोकन उत्पन्न होने पर उस मूल्य को अपडेट करता हूं

class MyFirebaseMessagingService: FirebaseMessagingService() {
    override fun onMessageReceived(p0: RemoteMessage) {
        super.onMessageReceived(p0)
    }

    override fun onNewToken(token: String) {
    super.onNewToken(token)
    val currentUser= FirebaseAuth.getInstance().currentUser?.uid
    if(currentUser != null){
        FirebaseFirestore.getInstance().collection("user").document(currentUser).update("deviceToken",token)
    }
 }
} 

हर बार जब आपका ऐप खुलता है तो यह एक नए टोकन के लिए जाँच करेगा, यदि उपयोगकर्ता अभी तक इसमें साइन इन नहीं है, तो यह टोकन को अपडेट नहीं करेगा, यदि उपयोगकर्ता पहले से ही लॉग इन है तो आप एक के लिए जाँच कर सकते हैं newToken

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.