Firebase FCM force onTokenRefresh () will be called

I am moving my application from GCM to FCM.

When a new user installs my application, onTokenRefresh() is automatically called. The problem is that the user is not logged in yet (no user ID).

How can I run onTokenRefresh() after a user logs in?

+104
android
May 26 '16 at 7:40
source share
8 answers

The onTokenRefresh() method will be called whenever a new token is generated. After installing the application, it will be generated immediately (as you have already discovered). It will also be called when the token changes.

According to FirebaseCloudMessaging guidelines:

You can send notifications to one specific device. Initial When you launch your application, the FCM SDK generates a registration token for the client application instance.

Screenshothot

Source Link: https://firebase.google.com/docs/notifications/android/console-device#access_the_registration_token

This means that token registration is done per application. It looks like you would like to use the token after the user is logged in. I would suggest that you save the token in the onTokenRefresh() method in the internal storage or in the general settings. Then, retrieve the token from the store after the user logs in, and if necessary, register the token on your server.

If you want to manually run onTokenRefresh() , you can create an IntentService and delete the token instance. Then, when you call getToken, the onTokenRefresh() method will be called again.

Code example:

 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); } } 

EDIT

FirebaseInstanceIdService

public class FirebaseInstanceIdService extends service

This class is deprecated. In favor of overriding onNewToken in FirebaseMessagingService. Once this was this service can be safely removed.

onTokenRefresh () is deprecated . Use onNewToken() in 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); } } 
+165
Jun 01 '16 at 22:36
source share

Try implementing FirebaseInstanceIdService to get the update token.

Access to registration token:

You can access the token value by extending FirebaseInstanceIdService . Make sure you add the service to your manifest , then call getToken in the context of the onTokenRefresh and onTokenRefresh value, as shown:

  @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 servers. sendRegistrationToServer(refreshedToken); } 

Full code:

  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 servers. sendRegistrationToServer(refreshedToken); } // [END refresh_token] /** * Persist token to third-party servers. * * Modify this method to associate the user 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. } } 

See my answer here .

edits:

You should not start FirebaseInstanceIdService yourself.

Called when the system determines that tokens need to be updated. The application should call getToken () and send tokens to all application servers.

This will not be called very often, it is necessary to rotate the key and to process changes to the instance ID due to:

  • Application removes instance id
  • The application has been restored to the new device. User
  • uninstalls / reinstalls the application
  • User cleans application data

The system will adjust the update event on all devices to avoid overloading application servers with token updates.

Try below method :

You should call FirebaseInstanceID.getToken () anywhere outside the main thread (whether it is a service, AsyncTask, etc.), store the returned token locally and send it to your server. Then, whenever onTokenRefresh() , you again call FirebaseInstanceID.getToken () , get a new token and send it to the server (possibly including the old token so that your server can delete it, replacing it with a new one).

+16
May 29 '16 at 12:12
source share

I support one flag in a shared pref that indicates whether a gcm token is sent to the server or not. In the Splash window, every time I call one sendDevicetokenToServer method. This method checks if the user ID is empty and gcm send the status, and then send the token to the server.

 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()); } }); } 

}

In class 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
Sep 29 '16 at 12:55
source share

Guys have a very simple solution

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

Note. If your application used tokens that were deleted using deleteInstanceID, your application will need to create replacement tokens.

Instead of removing the instance id, remove only the token:

 String authorizedEntity = PROJECT_ID; String scope = "GCM"; InstanceID.getInstance(context).deleteToken(authorizedEntity,scope); 
+2
Feb 13 '17 at 20:43
source share

This happens in RxJava2 in a scenario when one user logs out of your application and other users log in (The same application) To re-register and call in the system (if the user device did not have an Internet connection earlier during the start of activity, and we need to send token to api login)

 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())); 

Log in

 @FormUrlEncoded @POST(Site.LOGIN) Single<ResponseSimple> login(@Field("username") String username, @Field("password") String pass, @Field("token") String token ); 
+1
Jun 21 '18 at 10:05
source share

This response does not destroy the instance id; instead, it can get the current one. It also keeps updated in general preferences.

strings.xml

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

Utility.java (any class where you want to set / get settings)

 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 (extends 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); .... 

}

Android 2.0 and above onCreate service is not called when it starts automatically ( source ). Instead, onStartCommand overridden and used. But in the real FirebaseInstanceIdService, it is declared as final and cannot be overridden. However, when we start the service using startService (), if the service is already running, the original instance is used (which is good). Our onCreate () (defined above) is also called !.

Use this at the beginning of MainActivity or whichever you think you need an instance id for.

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

And finally

 Utility.getFirebaseInstanceId(getApplicationContext()) 

Note that you can improve this by trying to move the startervice () code into the getFirebaseInstanceId method.

0
Aug 23 '16 at 19:45
source share
  [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
Feb 18 '19 at 10:26
source share

FirebaseInstanceIdService

This class is deprecated. In favor of overriding onNewToken in FirebaseMessagingService. Once this is implemented, this service can be safely removed.

A new way to do this is to override the onNewToken method from 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); } } 

Also do not forget to add the service to Manifest.xml

 <service android:name=".MyFirebaseMessagingService" android:stopWithTask="false"> <intent-filter> <action android:name="com.google.firebase.MESSAGING_EVENT" /> </intent-filter> </service> 
0
Jun 14 '19 at 7:41
source share



All Articles