Notification Token using GCM - android

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.

Related

How to manage multiple tokens according to device

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.

Store multiple pair token/device for push notifications

I'm working on a new app and I want to give the possibility to my user to use more then one device.
The app can receive push notification, my question is how to save more device/token for each user, this for send push notification to all the user's devices.
My idea is to retrive "some device ID" and then store a id/token for each device but I don't know which device ID I can use...
Another idea is to create a random id the first time and then send this id with token, this work (partially) until the user clear application data...in this case I need to resend a new id (no problem) but I can't know if I can remove the old id/token
any solution?
You don't need "some device ID"; the push token is the device ID. You need to ensure that your backend database can associate more than one push token with a given user account. This is typically through a one->many relationship between user "users" table and your "installations" table.
You can't rely on your app to tell your backend to remove an old token, since the user may simply delete your app and it doesn't get a chance to communicate with your back-end.
The APNS service will deliver feedback as to which push tokens were invalid (I assume that the equivalent Android service also has something like this). You use this feedback to purge invalid installations from your installations table.

Firebase Cloud Messaging device groups leak

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.

Implementation of GCM app server with multiple devices per user

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.

Multiple Notification is getting from (GCM)Google Notification Server?

I have multiple different deviceids in my database table pointing to same a device because google will send me different device id when a device reinstall/install. Due to which devices getting multiple notifications which is hurting me and my users very much. Is there is a way to tell google that only send one notification to single device? or is there a way to check the id is new or old before sending request? Anyone experience with this weird issue? BTW, I am using PushSharp/ASP.NET in backend.
Update: I am now relying on native device id. So, I will remove/replace the old registration ids from my database table where native device id is same.
I think you need to remove the device id from your database once you get unregistered error code.
Unregistered Device
An existing registration ID may cease to be valid in a number of scenarios, including:
If the application manually unregisters by issuing a com.google.android.c2dm.intent.UNREGISTER intent.
If the application is automatically unregistered, which can happen (but is not guaranteed) if the user uninstalls the application.
If the registration ID expires. Google might decide to refresh registration IDs.
If the application is updated but the new version does not have a broadcast receiver configured to receive com.google.android.c2dm.intent.RECEIVE intents.
For all these cases, you should remove this registration ID from the 3rd-party server and stop using it to send messages.
Happens when error code is NotRegistered.
I recommend you to handle error codes when you send a message to a device.
http://developer.android.com/google/gcm/gcm.html
Please read role of 3rd party server. You would get more details.

Categories

Resources