Storing FCM token - android

I have an Android app which receives push notifications. I was wondering if there was a more straightforward method to store a FCM token and user ID on a external db given that right now I'm writing my own FirebaseInstanceIdService. sendRegistrationToServer method. Like this
public class TokenRegistrationService extends FirebaseInstanceIdService {
#Override
public void onTokenRefresh() {
// My custom manager
}
private void sendRegistrationToServer(final String FCMToken) {
// Here I can send FCMToken to my db
}
}
Is there any other way for me to get the token and send it?

I'm assuming you mean a more straightforward way than extending FirebaseInstanceIdService. If so then you should note that the token is generated whether or not you extend this class.
To retrieve the token you can simply get an instance of InstanceID and call getToken.
String token = InstanceID.getInstance().getToken();
Also note that if you are not requesting the token in the FirebaseInstanceIdService onTokenRefresh callback, getToken will return null if the token retrieval process has not yet completed and will return the token once it has been retrieved.
The token retrieval happens as soon as your application starts so if you don't need the token very early on first run, calling getToken will likely be sufficient. If you need the token or refreshed versions as soon as they are available then you would need to extend FirebaseInstanceIdService and override onTokenRefresh.

Is there any other way for me to get the token and send it?
For generating the registration token, I'm pretty sure there is no other way than just using the FirebaseInstanceID service.
For when sending the token to your server.. I'm not sure what the question is here. Isn't sending the token directly to your app server after it was generated straightforward enough? Or am I missing something? Do expound.

Related

Firebase Cloud Messaging : Expiration of FCM token

I understand that the FCM token renews itself if one of the following happens.
-The app deletes Instance ID
-The app is restored on a new device
-The user uninstalls/reinstall the app
-The user clears app data.
The following can be used at the App side to monitor Token renewal.
Monitor token generation
The onTokenRefreshcallback fires whenever a new token is generated, so
calling getToken in its context ensures that you are accessing a
current, available registration token. Make sure you have added the
service to your manifest, then call getToken in the context of
onTokenRefresh, and log the value as shown:
#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.
sendRegistrationToServer(refreshedToken);
}
My question is, when the app is terminated, the token expires and there is no way for the FCM server to know what the new token is for the device (if exist). So when I send a notification/data message to this device, the server fails to send it to the device as it doesn't know where to send it to (as there is no valid token). How do I make sure that in such situations I can notify the device ? I dont do a customer token generation. So the it seems to refresh the token now and then. How do I increase the validity of my token ?
You will need to check for an error when sending the message, and pay attention to the error codes, as listed in the documentation. You should stop using the token if you get the error messaging/registration-token-not-registered.

Behavior of calling FirebaseInstanceId.getToken

I have two types of questions around FirebaseInstanceId.getToken(String authorizedEntity, String scope), one around calling this method multiple times and one around whether calling this method triggers FirebaseMessagingService.onNewToken(String token).
1) Calling multiple times:
According to this documentation one would call getToken(String authorizedEntity, String scope) multiple times, each time with a different sender id, in order to be able to receive messages from multiple senders. My question is, will each call return a different token, or will each call return the same token but now the token will work also for multiple senders? If we call this method with a sender id that we've previously used before, will that return the existing token or generate a new one?
So, say I have this order of operation
Call getToken("senderId1", "FCM") and get token A
Call getToken("senderId2", "FCM"). Will I get A or a different token B?
Call getToken("senderId2", "FCM"). Will I get A, B, or yet another different one C?
2) Will onNewToken be called?
This documentation states that the method will be invoked if the token changes. So does this mean that if getToken returns a different token than before then onNewToken will be invoked as well? If we're going to be calling getToken multiple times to allow for receiving from different senders, and each call returns a different token, then onNewToken will keep getting invoked.
Since it is advised that we update our server when onNewToken is triggered, I want to understand the expected behavior and avoid generally updating the server on each invocation of onNewToken.
My question is, will each call return a different token, or will each call return the same token but now the token will work also for multiple senders?
getToken() / getToken(String, String) will return the same token until such time that the corresponding token expires. Note that by same token, I mean the same token that they return for each sender. i.e.:
getToken() returns the registration token for the default project (e.g. tokenDefaultSenderId)
getToken(String, String) returns the registration token for the sender it is associated to (e.g. tokenSenderId2)
If we call this method with a sender id that we've previously used before, will that return the existing token or generate a new one?
Okay.
You will get token B.
You will get token B again.
A token is tied to the sender it is associated to.
Will onNewToken be called? ... So does this mean that if getToken returns a different token than before then onNewToken will be invoked as well?
onNewToken() will only return the token for the default sender (emphasis mine):
Called when a new token for the default Firebase project is generated.
The thing about onNewToken() is that it triggers only when the previous token has expired -- the thing to ask is, if the token for the default sender expires, what more for the other senders? So the best workaround here is to call getToken() for each of the sender that you have, like so:
public void onNewToken(String token){
String default = token;
String sender2 = getToken("senderId2", "FCM");
// and so on for each of your sender, then save the tokens as needed
}
The token is unique for every sender id. Different sender ids have different tokens.
Default sender is the one defined in your google-services.json (related to the firebase project that the app is connected to)
OnNewToken is called when token for the default sender is changed. There are no callbacks triggered when a token for a specific sender (other than default) is changed.
As mentioned by #sNash who contacted firebase support:
I contacted firebase support team and got an answer. Answer summary : Different sender id's token will not be automatically managed by firebase cloud messaging. So developer is responsible for it's management. You guys have to check it's validity manually with your own method.
How to determine if token needs to be refreshed in case of multiple sender id?
Managing tokens for specific sender ids (other than default):
One simple solution for managing tokens for specific sender ids (other than default) is through storing all sender ids with their tokens in SharedPreferences or in db. When app starts, check if the token changed for each sender by comparing the stored token with the token returned by
FirebaseInstanceId.getInstance().getToken(SENDER_ID, "FCM");
Moreover, do the same check in onNewToken method. There is a chance that tokens other than the default may be changed when the default token is changed.

Getting Registration Tokens GCM vs FCM

I am reading the documentation on this page under the heading "Retrieve the current registration token." I am confused by what it says.
The initial paragraph is very simple. It says we simply have to call...
FirebaseInstanceId.getInstance().getToken
That sounds very easy until I read the next paragraph that says I need to implement MyFirebaseInstanceIDService.java...
public class MyFirebaseInstanceIDService extends FirebaseInstanceIdService
{
#Override
public void onTokenRefresh() {
// Get updated InstanceID token.
String refreshedToken = FirebaseInstanceId.getInstance().getToken();
}
So the first paragraph seems to say can make the call anyplace when I want to but the second paragraph has me wraping the call inside an onTokenRefresh().
So this begs the question WHEN does onTokenRefresh get called? With GCM I was able to choose WHEN I made the call asking for the token. With FCM it appears that we wait for onTokenRefresh to be called somewhere in time.
From the same linked document:
The registration token may change when:
The app deletes Instance ID
The app is restored on a new device
The user uninstalls/reinstall the app
The user clears app data.
It is strongly recommended that onTokenRefresh() is handled since there is a (rare) possibility that calling getToken() would (from the same docs):
This method returns null if the token has not yet been generated.
I think my answer here has a bit more explanation.
With all that said, calling getToken() would (most of the time) give you a token immediately, but in a case that it doesn't, onTokenRefresh() is there.
from this post
The onTokenRefresh() method is going to be called whenever a new token
is generated. Upon app install, it will be generated immediately (as
you have found to be the case). It will also be called when the token
has changed.
Just like an onEdit() function is called when an edit is made or onOpen() is called when the app is opened.

Firebase Cloud Messaging - Are GCM canonical IDs still necessary?

I've been reading on canonical IDs in GCM and how they help to rectify sending duplicate push notifications and with security. But now with Firebase Cloud Messaging (FCM), does this issue still exist?
I am the registration part has been taken away from the developer now and we just wait for a token refresh as per below:
public class MyFirebaseInstanceIDService extends FirebaseInstanceIdService {
#Override
public void onTokenRefresh() {
// Get updated registration ID
String refreshedToken = FirebaseInstanceId.getInstance().getToken();
Logger.d("Refreshed FCM token: " + refreshedToken);
}
}
Some info on canonical IDs can be found here.
Update:
I recently revisited this topic on Canonical IDs and have concluded the following.
In FCM, it seems the Canonical IDs are no longer used (or at the very least extremely rarely) because of the way the Instance ID service works. To put it simply, the service works that there would only be one valid token per App Instance.
If the older token expires (for whichever reason), FCM triggers a tokenRefresh event where you would get a new registration token, and where you must also handle it accordingly (in onTokenRefresh()).
Short answer, Yes. It's still necessary.
The onTokenRefresh() method is expected to trigger whenever the token is actually refreshed. From there, it's the developer's responsibility to send the registration token towards an App Server.
BUT in an event where you weren't able to get a hold of the new registration token (e.g. forgot to save it, deleted it and only have the previous registration token, etc.), it may result to you (the developer) to send towards a supposed to be no longer valid registration token. That's when Canonical IDs come in.
I guess you can treat Canonical IDs as another safety measure so that developers can still get a hold of the valid registration token. Details about Canonical IDs (how it is handled and stuff) are mentioned in the FCM docs here.

In what period does the firebase's app token changes and how to manage it?

I am new to firebase I am learning it like a toddler learning to walk. So far I have managed to send a message to my own phone using a token generated for my phone by firebase framework. Now here's where it gets tricky (in my opinion). There is a method called onTokenRefresh() in the FirebaseInstanceIdService extended service. Since it is called refresh, Then I am assuming that it will change. I want to know when this token is created and when will it be changed?
And if it changes, suppose I send a message to a device with token 'A' which is offline for now, so it will be queued. Now when the device gets online, it will "refresh" the token to 'B'. Now as the message was supposed to be delivered to token 'A', the message will never be delivered. How can I manage this situation?
The token is generated, after the app is first launched, as soon as the phone can connect to the Google servers. Due to the required connectivity this might not happen immediately, but in most of the cases it will happen in few seconds after the user open the app.
As soon as the token is generated the method onTokenRefresh() is called.
As you pointed out the token can change, in which case the onTokenRefresh() method will be called again.
The refresh event is somehow rare, don't expect to see it often at all.
When the refresh token happens, all the messages that have been "successfully" sent (the API returned you a message-id) to the old token will be delivered.
Finally, even after the refresh happened the old token will still be working for a short period, to allow the app to communicate the new token to its back-end.
On initial startup of your app, the sdk of FCM generates the registration token for the client app instance. As above said, It is a rare event. To be specific,The registration token may change when:
The app deletes Instance ID.
The app is restored on a new device
The user uninstall/reinstall the app
The user clears app data.
Instance ID provides a unique ID per instance of your apps.Instance ID provides a simple API to generate security tokens that authorize third parties to access your app's server side managed resources.The Instance ID server can even tell you when the device on which your app is installed was last used.We can use this to decide whether to keep data from the app or send a push message to re-engage with the users.
Every time the device token is changed, It is reflected in onTokenRefresh() method.For getting the device token when it is changed, we can call this method to get the refreshed token.
and to get the device token at any time we can use FirebaseInstanceId.getInstance().getToken() method to get the current device token.It takes a bit of time to get the device token.
Click here to read more about accessing device registration token.
onTokenRefresh() and FirebaseInstanceIdService are deprecated.
This call is also deprecated FirebaseInstanceId.getInstance().getToken()
Instead, You should override onNewToken(String token) in FirebaseMessagingService. This method triggered when the token is changed. Once you override this method, you can safely remove FirebaseInstanceIdService whcih contains onTokenRefresh().
When token can change?
App deletes Instance ID
App is restored on a new device
User uninstalls/reinstall the app
User clears app data
How to retrieve the current token:
by calling FirebaseInstanceId.getInstance().getInstanceId():
FirebaseInstanceId.getInstance().getInstanceId()
.addOnCompleteListener(new OnCompleteListener<InstanceIdResult>() {
#Override
public void onComplete(#NonNull Task<InstanceIdResult> task) {
if (!task.isSuccessful()) {
Log.w(TAG, "getInstanceId failed", task.getException());
return;
}
// Get new Instance ID token
String token = task.getResult().getToken();
// Log and toast
String msg = getString(R.string.msg_token_fmt, token);
Log.d(TAG, msg);
Toast.makeText(MainActivity.this, msg, Toast.LENGTH_SHORT).show();
}
});
For more info:
https://firebase.google.com/docs/cloud-messaging/android/client
For Managing tokens for specific sender id (other than the default sender id),
check here

Categories

Resources