I'm going to develop an app that uses device groups feature. As I understand I need to first send current registration token I get on Android client in method onTokenRefresh to the server and then add this registration token to proper device group (or create it if it doesn't exist) via HTTP request. I see, however, a potential for leaking registration tokens, as Android app user may for example wipe app's data multiple times. How to prevent it? What happens when a limit of 20 members is exceeded? And is it possible to check whether some group already exists or not?
I see, however, a potential for leaking registration tokens, as Android app user may for example wipe app's data multiple times. How to prevent it?
If by preventing you mean disabling Clear Data for your app in the App Manager, you should refer to this post. The accepted answer states that it isn't possible.
However, Jakar's answer provides a workaround where instead of Clear Data, Manage Spaces will show up instead. Haven't tried it out yet, so I can't say for sure. The upvotes speak for itself though.
But, if ever the app's data is wiped/cleared by the user, you should refer with what is stated in the FirebaseInstanceId docs:
Instance ID is stable except when:
App deletes Instance ID
App is restored on a new device
User uninstalls/reinstall the app
User clears app data
In the above cases a new Instance ID is generated and the application needs to recreate the authorization tokens previously generated implementing onTokenRefresh().
What happens when a limit of 20 members is exceeded?
Not sure what the question is here.. But if you are pertaining to adding devices to a Device Group more than the maximum...
Wasn't able to find it clearly stated in the FCM: Device Group Messaging docs, but if you refer to the Add to group section, it states:
A successful operation returns a notification_key.
So from that, I think if you ever try to add another device to an already maxed out device group, the operation will fail.
I suggest using Topics instead, if you think you're going more than 20. But I don't really know what your use-case is, so.. your call.
And is it possible to check whether some group already exists or not?
For this, you should make use of the notification_key and notification_key_name. As per the docs:
The notification_key_name is a name or identifier (e.g., it can be a username) that is unique to a given group. The notification_key_name and notification_key are unique to a group of registration tokens. It is important that notification_key_name is unique per client app if you have multiple client apps for the same sender ID. This ensures that messages only go to the intended target app.
And emphasizing on the statement:
Basic management of device groups — creating and removing groups, and adding or removing devices — is usually performed via the app server.
The keys and names should be on your server, so that you can check if it already exists or not.
I am currently doing the following with some success but not fully tested or scaled yet.
App uses firebase as the backend and I am adding FCM to implement push notifications.
I need groups to handle when a user could be on different devices or several devices.
I store the returned notification_key value and the registration_id (token) for each device with the profile i.e
profiles
-profile_id
-FCM
-notification_key:value
-registration_ids
-device_1_uuid:token_for_device_1
-device_2_uuid:token_for_device_2
When a user first signs on there is no data under the FCM node i.e. no notification_key and no registration_ids
Each time a user signs in they hook up to their profile_id.
I get the FCM token and then
If there is no notification_key (i.e. first time on any device) I create the group using the profile_id as the notification_key_name and store the notification_key that comes back.
If there is a notification_key (return sign-in or first sign-in on a new device) I see if there is a registration_id for the current device and if not (first sign-in on new device), add the device_uuid:token pair to the registration_ids.
If there is (return sign-on) I remove the stored token from the FCM group and replace the old token in my stored registration_ids with the token I just got.
I can now message all of the devices used by that user (profile) by sending to their profile_id, and I shouldn't be leaking tokens because I delete the old ones.
However, I have no way of knowing because there doesn't seem to be API to just read the group and the tokens so that the groups could be cleaned every now and again.
Also, my early code bugged and I didn't capture the notification_key so now I can't add, remove or do anything to one of my groups. I hate the idea that I'll have to leave burned groups lying around in the firebase cloud for ever and ever.
I think FCM should provide more API access to help us keep the place tidy.
Related
I'm a beginner in fcm and stuck in one issue. After getting reference from several source I'm able to implement it successfully. But now I'm trapped in a strange issue.
As fcm creates unique tokens per device so notifications can be sent to that device using that unique token only . So, after the token is generated I'm saving that token into mongodb for that particular user and the notification is sent to that device without any problem.
Now let's assume a scenario : Let a and b be two users having different device so they'll have unique tokens in their mongodb documents . Now if a will try to logging in into his account from b's device then how can I send notification to a's account in b's device as the mongo-document of a containing token for a's device which can't be used for the current i.e b's device
Please do excuse me if my question is silly.
You need to always make sure you update tokens when a user signs up or logs into a new device. If the user has give permission before, this shouldn't notify the user again and if not, user will be prompted to give permission and you can save the new token then.
It is usually good to keep the tokens in format of an array so you can send notifcation to all the tokens inside that array at any given time, i.e, all the devices that user is logged into.
Here's an example which you can see the token being saved in an array.
I know this has been discussed before, but the only solution I found (canonical IDs) don't work in my scenario.
Scenario:
User installs App and registers with his user account A
User gets push notifications meant to be delivered to this specific user account A
User uninstalls the app
User reinstalls the app
User registers with a different user account B
Now notifications are delivered for both user accounts. From my understanding, using cannonical GCM Reg IDs would only consolidate those IDs and prevent sending duplicate notifications. In this case the App gets notifications for a different user that shouldn't be delivered at all.
Is there any fix for that? Only thing I can think of would be actively deregistering when uninstalling the app, but in another thread I read, it's not possible to execute code on deinstallation.
From my understanding, using cannonical GCM Reg IDs would only consolidate those IDs and prevent sending duplicate notifications.
That's one way of looking at it, but on a simpler note, Canonical IDs are like saying "old ID you used is expired, delete it (if you saved it) and use me instead".
The thing that makes this a bit odd is that, when the user uninstalls the app, the InstanceID should be invalidated. (see the docs here).
What I think you can do to make sure that tokens are deleted, you can call deleteInstanceId() to revoke all tokens, then re-register.
But to make sure that the message is for the intended user, you can refer to what is stated in the docs (first one similar to what #Ak9637 said):
To make sure that messages go to the intended user:
The app server can maintain a mapping between the current user and the registration token.
The client app can then check to ensure that messages it receives match the logged in user.
You can simply check ,when registering in your tokens database,when u receive token of user B , just check if it is already associated with any user or not, if it is simply nullify that field and save the new token to new user.
As token identifies the device not the user.
If you wish to take total autonomy and control of notifications related to your app, You should use data notifications instead of message notifications , this will avoid the OS handling the notifications instead of your app
I'm a bit confused about how to manage registration ids for all app installations.
In the app server database I have a User table and a UserDevice table. Every User may have many UserDevices. Each UserDevice have a registration id. So when a user should be notified I send the message to all the registration id's for all the devices of the user.
But when the application is reinstalled, Android is updated or something else happens that causes the registration id to change, the app will send a new registration id to our app server. But I have no way to know if this is a new device or if an existing UserDevice should be updated with the new registration id.
How is this supposed to be handled? My first thought is to send a persistent hardware ID as well as the registration ID, but perhaps there is a better way?
You don't have to worry about this. If the user does reinstall the app and the token is refreshed just add it to the users list of tokens (keeping the old one for now).
next time you send a notification to this user it will fail on the token that is no longer used. Now all you have to do when you get the fail reply from google is remove that token from your devices table.
Remember if you fail to send to a token for reasons such as invalidRegID or NotRegistered then the GCM will/has unregistered that token so it is no good so it needs to be removed from your list otherwise you will get in googles bad books for repeatedly sending to the same failed token. So remove ones that fail.
when my apps start i always check to see if the device is registered if it is I send the same token to my app server just incase it somehow got deleted.
Hope this helps
You could take a look at GCM's Device Group feature, which is explicitly intended for the "one user, many devices" problem:
https://developers.google.com/cloud-messaging/notifications
I use PushSharp and there I can use the different event handlers that are defined to handle subscription changes or expirations. The source code is available on github https://github.com/Redth/PushSharp/blob/master/PushSharp.Android/Gcm/GcmPushChannel.cs
You can probably apply the same logic to your application.
I'm implementing a GCM handler on my server. Does Google issue a new Registration ID per device or per user? I know they issue a new ID per App version and user, but does that extend to each device the user has the app installed on?
Ultimately, I ask because I want to know how I should store a Registration ID a user's app sends me server-side.
Right now I have it implemented such that the most recently sent ID is the user's only Registration ID, but I am unsure if this is an incorrect way to model how GCM handles registration IDs. I'm leaning towards it being incorrect and that I'd have to keep a record of many IDs based on some criteria.
Any input would be appreciated.
Basically, GCM issues a new registration ID per device with the app installed. To answer your question, 1 registration ID per device.
GCM does not know anything about your own users, so it is up to you to implement the logic of how to sift through messages intended for User X and Y, if both of them use the same device.
Here's something from the docs:
A registration ID isn't associated with a particular logged in user. If you unregister and then re-register, GCM may return the same ID or a different ID—there's no guarantee either way.
To make sure that messages go to the intended user:
Your app server can maintain a mapping between the current user and the registration ID.
The app can then check to ensure that messages it receives match the logged in user.
The whole "matching" concept in the last bullet is what I meant by sifting through.
It is issuing an ID that depends on both. If the user changes on a specific device, the ID will change and vice versa. Also a user can have more devices and on each device the ID differs. But you should know that google has a limitation of how many devices each user can have, last time I checked it was 10.
You should also be checking the result the GCM server returns, it will tell you if the ID is dead and you can remove it from your database.
I have developed android where I am using GCM to send notification.
I am facing one problem that i will explain by taking an example.
Let's say user A logging in my app. So I generate token for that user let's say that is "AA1" using GCM and storing it our database. But then if user uninstall app and install it again. Then I am generating token again (Lets say AA2) and storing in our server.
If both tokens are same then it will not cause any issue as I am comparing before inserting a token. But as GCM tokens for same device can differ. Right ?
Later, When I want to send a notification to that user. That user will get notification twice as his previous token is still working. I tried to search but found nothing related to this. It may that I am missing something or none have thought like this.
Doesn't matter which but I think there must a way to solve this issue.
Question
Is there a way to check both the notification tokens belongs to same device or not?
Is there a way to remove notification token from our database when user uninstall apps ?
Please guide me.
What i think is this problem can be solved this way.
When you are storing Token value to application server, you should map it with users device id. therefore when this token is re-generated (with different value), your application server can update the token for that user as in both cases device id was same.
Is there a way to check both the notification tokens belongs to same device or not?
Not in a unique way. You could make an IP comparison when the user registers and store both the GCM id and their IP address, this way when they connect again you can check whether you already have a registration with that IP address and delete the previous. However, this is not a good 100% solution as there are countries that assign the same IP address to several devices. I think the best approach here is implementing a timeout mechanism. In my apps, when the user registers, they have to send a "keepalive" HTTP POST signal every 30 seconds to say "hey, I'm still here". If that keepalive doesn't arrive in a reasonable amount of time, I consider it a timeout and remove it from the database.
This is, however (now I mean unistallation), one of the cases where you should call the GoogleCloudMessaging.unregister() method and send it also to the third-party server.
Is there a way to remove notification token from our database when user uninstall apps ?
Seems that there's not (Perform a task on uninstall in android). But however, with the above approach, you wouldn't have any further issues as this user would stop sending the "keepalive" notifications and he would be timed-out.
Agree with you. But still there is a solution. what you can do is, you can use device IMEI number as device id and use it. This IMEI number will never change even if on factory reset.
How to get unique device hardware id in Android?
TelephonyManager telephonyManager = (TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE);
telephonyManager.getDeviceId();
Also add the below manifest permission.
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
What we do is generate a unique ID (in our server) for each application instance. The application gets that ID by making an API call after first being installed on the device. We store that ID in external storage (that doesn't get wiped when the app is uninstalled). The registration ID of the device is associated in our DB with our unique ID.
This way, when the app is installed again on the same device, we get that identifier from the external storage (if available) and re-use it, and even if the registration ID is changed, we know it belongs to the same device.
In addition to this strategy, your server should handle the following scenarios :
If you get a canonical registration ID in the response from GCM, delete the old registration ID (if the canonical ID already exists in your DB) or change it to the new canonical ID. This would prevent duplicate messages from being sent again to this device.
If you get NotRegistered error in the response from GCM, delete the registration ID you attempted to send from the DB. This means the application was uninstalled. There is no other way to detect that the user uninstalled the app.
One Solution I think would be to send a pushnotification key with every notification. Handle this on your client side by keeping a last pushnotification key used in shared prefs. If you get the same notification key again drop it.