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.
Related
I am using FCM in my project and my application is register with two FCM project (two sender ID).
Now i want to handle token refresh.And as per document i will get below call back
#Override
public void onNewToken(String token) {
Log.d(TAG, "Refreshed token: " + token);
}
but have may i know which token is updated ?
token updated for sender_id_1 or token updated for sender_id_2 ?
Question 2 : If i receive onNewToken call back with newToken value and if i do not pass that value to server and server try to send push on older token, then what will happen ? what error i will received from FCM ?
Thanks
Looking at the docs for onNewToken() (emphasis mine):
Called when a new token for the default Firebase project is generated.
This is invoked after app install when a token is first generated, and again if the token changes.
Default project points to the first project.
Sending to an expired token would result to a NotRegistered error
I'm using this well known code to save a new firebase token on my server (from: Retrieve the current registration token):
#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);
}
The problem is, that if the user installs the app on some other device, the same code will be executed and the former firebase token will be overridden by the new one.
So I have to distinguish between the devices, but how can I do it? Device name is for sure not unique enough for this.
EDIT: unfortunately, the suggestion by Bob Snyder did not work. The FirebaseInstanceId#getId() is always different if I remove the App data (cache) or reinstall the app.
The token is unique to each device and includes the app instance ID. The 11-character instance ID, which is the same one returned by FirebaseInstanceId.getInstance().getId(), appears first, followed by a colon, and the remainder of the token. Example:
eiURDSe_P4q:APA91bFvtCzK...LRpzvQOSdNKioklO
You can use the instance ID as a unique key to store the token on the server.
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.
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
I'm using GCM on Android.
I use InstanceID.getInstance(...).getToken(...) to receive a push token, but in some cases (after application updates or re-install) I receive an invalid token.
When the server returns a NotRegistered error, I've connected with a debugger and called InstanceID.getInstance(...).getToken(...). But this token is not valid (I've tried to send push via curl -s "https://android.googleapis.com/gcm/send" ... using this token), I receive NotRegistered error.
Why instanceID could return invalid token?
It shouldn't give invalid token.
Have you applied all procedures?
InstanceIDListenerService: When the token changes via the app
updates, etc.
RegistrationIntentService: When the token changes, you receive it via InstanceIDListenerService and call this intent to get a new
token.
Finally, I found a solution.
I worked with instanceID from two different threads. I called getToken(...) two times simultaneously. If instance doesn't have a cache, it get token from network. I think, it sends two requests in my case and there is no guarantee of it's order. So instanceID cached one token, but google cloud another one.