I am following a GCM-Android integration example from the official guide.
In particular I am confused about the following lines in the above linked class:
// You should store a boolean that indicates whether the generated token has been
// sent to your server. If the boolean is false, send the token to your server,
// otherwise your server should have already received the token.
Now I call the intent service each time my main activity launches and I believe that instanceID is responsible for initiating the token refresh.
Should I check the Shared Prefs value each time I initiate this GCM registration intent from my Main Activity. However refresh will fail in this case because after initial token fetch the condition will always be true.
Should I discard the shared prefs logic - this way a fresh token will be sent to my server each time. What is the proper way of doing this? How does the token refresh worrk and when does it refresh?
Yes, you don't need to save it in sharedPreference. To protect the client app and app server from potential malicious re-use of registration tokens, you should periodically initiate token refresh from the server. When GCM registration token refresh is initiated from server side, the client app must handle a tokenRefreshed message with the GCM registration client/server handshake.
Based on the document, backing up the registration token that Google Cloud Messaging registration returned can cause unexpected behavior in notifications for the restored app. This is because when a user installs your app on a new device, the app must query the GCM API for a new registration token. If the old registration is present, because the system had backed it up and restored it, the app doesn't seek the new token. To prevent this issue from arising, exclude the registration token from the set of backed-up files.
Here's a demo app for Google Services - MyInstanceIDListenerService: https://github.com/googlesamples/google-services/blob/master/android/gcm/app/src/main/java/gcm/play/android/samples/com/gcmquickstart/MyInstanceIDListenerService.java#L38
For more information, please read the Official Google Documentation here: https://developers.google.com/cloud-messaging/registration
Related
Android firebase token refresh.
If any new token generated from firebase, it will call the onTokenRefresh and service will update the token to server.
Is there any way we check firebase directly from server to get the new tokens generated for clients with old tokens ?
If the mobile switched off for sometime and fire base tried to send the refresh token but it failed.
How fire base will send the token in that case. will it keep try until it send the new token to device ?
Thanks
If the mobile switched off for sometime and fire base tried to send the refresh token but it failed. How fire base will send the token in that case. will it keep try until it send the new token to device ?
The Firebase servers don't send fresh tokens to devices. Instead, the Firebase SDK inside the device/app requests a new token when it detects that this is required. So this will only happen when the device is turned on.
I need to know if i have an instance id when my user logs in to the app in a deterministic manner. Is there any other way to know other than trying to get an instance id and handling the possible exception? - That approach is prone to failing because the documentation only mentions an IOException, which might be raised because of a network exception or some other IO error.
I am tracking the value myself with SharedPreferences but that seems a bit fickle as the app may not be used for a bit of time and the value might get out of sync.
An Android application running on a mobile device registers to receive messages by calling the Google Cloud Messaging method register. This method registers the application for GCM and returns he registration ID.
Based from this Demo App, they refresh the registration ID by setting an expiration date on the value persisted locally by app. they load their locally stored regstration id. If it is expired they call gcm.register().
This doesn't handle the hypothetical scenario in which a registration ID is refreshed by Google for an app that hasn't been launched for a long time.
Your app can request tokens from the Instance ID service as needed using the getToken() method, and like InstanceID, your app can also store tokens on your own server. All tokens issued to your app belong to the app's InstanceID.
Tokens are unique and secure, but your app or the Instance ID service may need to refresh tokens in the event of a security issue or when a user uninstalls and reinstalls your app during device restoration. Your app must implement a listener to respond to token refresh requests from the Instance ID service.
You may check this documentation of how to do proper implementation:
https://developers.google.com/instance-id/
https://developers.google.com/instance-id/guides/android-implementation
Here's a related SO ticket, discuss how to check if the device is registered:
How to check if the device if registered with GCM because official tutorial states "regID is not guaranteed to last indefinitely"
Google Cloud Messaging - Check if device is already registered
When using InstanceID you call getToken to retrieve the token from local cache (in Google Play services) if it already exists or make a network call to retrieve a new token. So if your app already has a token then a call to getToken should return immediately since it is a local call. If you get an IOException then that is a clear signal that your app does not currently have a token.
Another option that you should consider is using the new FCM client library. It handles the token requesting and refreshing for you, so all you need is a call to FirebaseInstanceId.getToken() which will return a token if one exists or null if one does not.
I wonder what is the lifecycle of registrationId(device_token)
e.g eD3Fa1yVqx8:APA91bH5gNrC-jhUqaoRwyFLfD2ik4NXwCXohwhm_9CM5hnY9wFwUAOiO_O12Or-dm60sUqy9gN2ZW6mw5i90RyNhb-zHilvtcJczPjZoQlm_4lKNKDejC_1_xiqmYoZnSxaFfVqSA1d
How to handle the situation if it's changed?
As far as the information on the official docs goes, there is no information about the token being changed by Google. However you should change it periodically.
Quoting https://developers.google.com/cloud-messaging/registration#automatic-retry-using-exponential-back-off
Keeping the Registration State in Sync
To protect the client app and app server from potential malicious
re-use of registration tokens, you should periodically initiate token
refresh from the server. When GCM registration token refresh is
initiated from server side, the client app must handle a
tokenRefreshed message with the GCM registration client/server
handshake.
I faced some situations where Registration ID changed. But, i don't know how and when.
So, to handle these situations i updated my app to send Registration ID every time the app is launched. I sent Registration ID with device id and check my database if the registration id changed i updated it.
I created a Push Notification Server (PNS) by using Google Cloud Messaging (GCM).
With this architecture, my server has to know the token associated to a user in order to send him push notifications.
I extended the class InstanceIDListenerService which is correctly notified when a token has been refreshed (I tested it with adb). When its method onTokenRefresh() is called I take the new token and, so far, all is ok.
My problem is the following: what if I fail to send this new token to my server? (a network error, a lack of connection, a sudden device shutdown, or something else...).
Do I have to store somewhere (preferences?) that server does not know my new token and retry when possible? Is there a way to let the OS to perform this operation?
You may use GCM NetworkManager to queue, schedule, check network connections and... , its very reliable and useful, it handles all of your desired tasks.
Also you have to save your token some where is your device, may be on your shared preferences, till you make sure your server recives it. Please note that if you want to use other features of GCM like topic messaging, you have to save and use token for all topic registrations.
Your app (when it runs) should always check if the token has been sent to the server. When onTokenRefresh is called you should generate and send a new token to the server. If sending the token to the server fails then the next time your app runs it should try again.
You are correct that if you fail to send the token to the server onTokenRefresh your app will not receive notifications till it is run again and successfully sends the token to the server.
Also note that token refresh should not be a regular occurrence. It should only happen for example when the app is uninstalled and reinstalled or the token is deemed to be no longer secure.
I just wonder when GCM sends the token to my app can any other apps on the same device receive it?
And should I save it on the mob memory or request a new one each time the app is initiated?
GCM register() is deprecated. use Instance ID instead of it.
What is Instance ID?
Instance ID provides a unique ID per instance of your Android and iOS apps.
Key features
In addition to providing unique IDs for authentication, Instance ID can generate security tokens for use with other services.
Instance ID lifecycle
The Instance ID service issues an InstanceID when your app comes online.
The InstanceID is backed by a public/private key pair with the private key stored on the local device and the public key registered with the Instance ID service.
Your app can request a fresh InstanceID whenever needed using the getID() method. Your app can store it on your server if you have one that supports your app.
Your app can request tokens from the Instance ID service as needed using the getToken() method, and like InstanceID, your app can also store tokens on your own server. All tokens issued to your app belong to the app's InstanceID.
Tokens are unique and secure, but your app or the Instance ID service may need to refresh tokens in the event of a security issue or when a user uninstalls and reinstalls your app during device restoration. Your app must implement a listener to respond to token refresh requests from the Instance ID service.
Calling instanceId.getToken(...) returns a token to your app only. This should be sent to your application server to be used to send messages to the app with the particular token.
There is no need to save it, actually saving it is discouraged. If you need the token again for some reason you can always call instanceId.getToken(...) again to get the same token, once the same instance of the application exists (ie no a new installation) and the token has not been deemed compromised by Google, then you will get the same token.
What is recommended is to save a boolean indicating whether or not you have sent the token to your app server, once your app server has it you should not have to generate it again.