shellström
shellström

Reputation: 1437

Properly handling when FirebaseInstanceId.getInstance().getToken() is null

What is a proper, solid way of having getToken() return with a token id?

I have seen a couple of attempts using

The while loop seem really risky in terms of ANRs and having a loop running indefinitely.

The local BroadcastReceiver isn't readily applicable to my application, because even though there is a main activity in my app, there is nothing forcing the user to interact with it. Users can accomplish tasks in the app without going through that main activity.

The timer seem fragile. How long do you have to wait for? Seconds, minutes, hours?

The Firebase quickstart sample code does not provide an example to handle the situation when getToken() is null, and I don't see what a proper and solid implementation would be to ensure there's a token being returned, without any of the nasty side effects of the above mentioned implementations would bring.

Having a callback method to hook onto would've made this a non-issue, but since that isn't available, I just have to run this through StackOverflow to get an idea of how people resolve this issue.

Note: I have implemented onTokenRefresh() and that works for the specific situations stated in the docs, but I can't use that alone, because the app is only upgraded on a lot of devices, and this method isn't called during an app upgrade. I have the null issues on (Nexus) hardware devices, I am not using the emulator at all and don't intend to use it.

Upvotes: 1

Views: 1012

Answers (1)

shellström
shellström

Reputation: 1437

As it seems there is noone adding other approaches, than the ones I mentioned before, I'm now going to answer my own question.

The "solution" I have implemented to having a token being generated so that you can handle it more consistently, and store it for later reference, is this;

The following class follows the quickstart almost to the letter. But instead of sending the token away to a server, at the exact time it is accessible, I instead store it for later use:

public class FirebaseIdService extends FirebaseInstanceIdService {

@Override
public void onTokenRefresh() {
    // Get updated InstanceID token.
    String refreshedToken = FirebaseInstanceId.getInstance().getToken();
    if(refreshedToken != null) {
        Log.d("TOKENTAG", "Refreshed token: " + refreshedToken);
        SharedPreferences prefs = getApplicationContext().getSharedPreferences("pref_id", 0);
        prefs.edit().putString("share_pref_token", refreshedToken).apply();
    }
}

}

When I want/need to send the token I check if there's already one available in the SharedPreferences and if not, I simply delete the Firebase instance, and call getToken(), to have another one generated. What this essentially does is to tell Firebase that "I want to invalidate the current instance", and then, by calling getToken() afterwards, have it generate a new one, essentially making onTokenRefresh() to be called, whenever a token has been generated and is available:

SharedPreferences prefs = getApplicationContext().getSharedPreferences("pref_id", 0);
if(prefs.getString("share_pref_token", "").isEmpty()) {
    Log.d("TOKENTAG", "token not available, so let's force one to be generated");
    try {
        FirebaseInstanceId.getInstance().deleteInstanceId();
    } catch (IOException e) {
        e.printStackTrace();
    }
    FirebaseInstanceId.getInstance().getToken();
}

I am pretty sure this is a sub optimal solution, and I'm welcoming suggestions to make this suggestion better, but at this point this is basically the only way that seem to cover the bases of combining onTokenRefresh() and getToken() to more consistently get a token without any of the afformentioned drawbacks.

Upvotes: 1

Related Questions