As I read from documentation and other sources it is advised to call FirebaseInstanceId.getInstance().getToken(); inside onTokenRefresh() to make sure that we get the updated token
what I tried was to call it every time the app is opened and its returning value always, and I am wondering is that a thing to trust ?(is it guaranteed to generate the token every time its called? ) or is there any case it might return null ?
since I don't want users logged in to multiple devices with the same account I am hoping to use it as unique identifier.
As per my knowledge and experience I will try to resolve your doubts:
Is it guaranteed to generate the token every time its called?
No it will not generate token every time you call this method. It will just return current token.
Is there any case it might return null ?
Yes it returns null if your token is not yet generated.
I am hoping to use it as unique identifier
Yes you can use it as a unique identifier for each device not for each account. Every device has its unique token.
This is from the official doc:
Retrieve the current registration token
When you need to retrieve the current token, call
FirebaseInstanceId.getInstance().getToken(). This method returns null
if the token has not yet been generated.
For more information refer this link.
Related
My app sends notifications using Firebase Cloud Messaging FCM. For every user, I'm storing the device token in database and I fetch it when I want to notify him. I'm using FirebaseMessagingService with the overridden method onNewToken that updates my database with new tokens. I suppose that this method is called every 1 hour to check token's update, but I was expecting it to be also called when the service is initialized for the first time (after installing and running the app on device). However this is not the case. To remedy this, I could call onNewToken each time the user log in But I would like to know if this is an acceptable way or there is a better one.
To avoid abuse, I leave here extra information on my case :
I run my app on Android Studio emulator and I check the stored token in database, let's call it TOKEN-1.
Now I install the app on my phone and I show the token with String token = FirebaseInstanceId.getInstance().getToken(); Toast.makeText(MainActivity.this, token, Toast.LENGTH_LONG).show();
The token is different that the first one TOKEN-1, and TOKEN-1 is still stored in my database. This means that I can receive notifications only on emulator and not my phone.
Sorry for my long text and looking forward to reading your suggestions.
The FCM SDK and server work together to manage the token in the background, and listening to onNewToken ensures that you get notified when the token changes. For this reason you should always be listening to onNewToken, and update it in your own database whenever it changes.
There is no guarantee that your FCM token will be refreshed every hour (or even ever) though, as you seem to expect. Given the 1 hour interval, you might be thinking of Firebase Authentication ID tokens, which are short-lived and are indeed refreshed every hour.
Finally: the token doesn't get refreshed when you attach a listener. In fact: if the token was already generated before you attach a listener, your listener won't be called. For this reason, you'll typically also want to grab the current token in your main activity when the app starts, and store it in the database at that point.
This last code is mostly necessary during development, as that's where you're most likely to have the scenario where the token gets generated when you don't have an onNewToken listener yet. So instead of putting code in the main activity, you can also uninstall/reinstall the app after adding your onNewToken listener, as FCM will generate a new token upon installing the app in that case - and thus call your onNewToken with this initial token.
From where and when is the token retrieved and when is it available?
Is it a synchronous call to the Firebase server? If I call it too soon in the app lifecycle, might it not have been populated yet?
From where and when is the token retrieved and when is it available?
The token is generated by the FCM Instance ID service in the background, which starts as soon as your app runs. The details on how the token gets generated is unclear, but how I see it is that the device needs a decent connection to the internet in order for it to communicate with the FCM servers for the token.
Is it a synchronous call to the Firebase server?
Technically speaking, no. As mentioned in the docs:
FirebaseInstanceID.getToken() returns null if the token has not yet been generated.
At this time, if the token is null, you should expect a trigger in your onNewToken() where you could then call getToken() which should now contain the token.
If I call it too soon in the app lifecycle, might it not have been populated yet?
It's usually okay to call getToken() as soon as possible -- in your app's MainActivity -- in most cases, by the time your app reaches that point, it already has a value. But then again, you should still handle it properly if it is null.
I have checked the class SyncUser and the definition for the method currentUser() is: Returns the current user that is logged in and still valid.
What I want to know is, what exactly is delivered, when this method is executed? How reliable is the delivered value and what is the limitation regarding the definition of "current user".
Thanks for any information!
SyncUser.currentUser() is just a convenience method for retrieving a single SyncUser that have logged in on that particular device using either SyncUser.login() or SyncUser.loginAsync(). It only works if a single user is logged in, otherwise, you need to use SyncUser.allUsers().
This is commonly needed when the app is restarted. You can then check if the SyncUser already exists and thus there is no need for them to log in again. This can be useful in the case when the device is offline and logging in is not possible.
The SyncUser is represented by what is called an access token, which has a default lifetime of 10 years, so valid in this context just means "Access token granted by the Server that has not expired yet".
Of course, that information cannot be fully validated on the client, e.g if the Server was restored from a backup losing information about a particular token, then the Client might think the token is valid while the server will reject it. In that case, you will receive a callback on the SyncConfiguration.Builder.errorHandler(..) with an event you can react to and log the user in again.
You can see an example of this in practice in this example here: https://github.com/realm/realm-java/tree/master/examples/objectServerExample
Our business logic requires us to instantiate Firebase during runtime. We fetch the Firebase credentials (App ID, API key etc.) from a default Firebase location after knowing the user's public key and create a Firebase instance using those credentials.
This means that there are two Firebase instances used within the app:
The default "index" Firebase that gives us credentials for the
second
The actual Firebase that we intend to use from that point
forward
The second Firebase is initialised like this:
FirebaseApp app = FirebaseApp.initializeApp(<context>, <options>, <app_label>);
Our problem is that the traditional method of retrieving the FCM token using the FirebaseInstanceIdService and onTokenRefresh() fails since the onTokenRefresh() method is called only by the first Firebase instance.
Directly calling String token = FirebaseInstanceId.getInstance(app).getToken(); returns null as it is never ready when called. We have even tried polling this to test if a token is generated at some point. No luck.
How can we generate an FCM token reliably from a Firebase instance instantiated during runtime?
In general, only the traditional method of getting the token (getToken()) is the only one that refers to the main Firebase Instance. This can be called almost anywhere in your app (but is often called in the initial activity). This will return the token associated to the Sender ID that is seen in your google-services.json. It is also possible for this to return null if the token is still being generated. In cases like that, onTokenRefresh() is triggered upon generation.
However, if you intend to generate a FCM registration token for a different Firebase Project, you'll have to make use FirebaseIntsanceId.getInstance.getToken(String authorizedEntity, String scope), where authorizedEntity is the Sender ID of that different Firebase Project and scope is "FCM" (you can use FirebaseMessaging.INSTANCE_ID_SCOPE as default).
In short, you don't need to specify the Firebase Instance when generating a token.
Also see my answers here and here.
I think that instead of saving the token I get from onTokenRefresh() to another place, why not let Firebase keep it and then I query it directly by using this whenever needed:
String refreshedToken = FirebaseInstanceId.getInstance().getToken();
This way, I should be able to get the token from the most reliable source.
But I tried to search it and did not find anything which suggests this use outside the service. I tried to implement it and found that it indeed returns the correct token if onTokenRefresh() is already called, otherwise it returns null. I think this will be the same wherever I manually save the token.
So is there any instruction which discourages the use in this manner?
You can safely call FirebaseInstanceId.getInstance().getToken() from anywhere and it will give you the current token.
The problem is that there are a few situations you won't catch if you only call it in your MainActivity:
the token may not have been created yet, in which return getToken() returns null.
the token may get recycled after you call getToken(), in which case your code is working with an outdated token.
To ensure you catch both these situations, you should implement FirebaseInstanceId.onTokenRefresh().