5

In my app, once I register a device, it's stored as persistent data in order to check whether the device is already registered.

On the server side I store them in a database along with a user_id which is a unique id for a user.

[user_id] [gcm_registration_id]

Now I am unable to tackle this case:

If the User logs out:

  1. The registration_id which is stored in SharedPreferences must be cleared because another user might log in the next time the app is launched.

  2. In addition, I have to delete the row corresponding to that registration_id from my database because that device (which has no currently logged in user) must not receive any more notifications.

The problem is that my database gets updated using the canonical_ids or say the latest registration_ids I get when calling

https://android.googleapis.com/gcm/send

So, there is a chance that I cannot find the old registration_id of the logged out user to delete, which still allows sending notifications to a non logged in user.

Also I cannot delete a row my DB matching the user_id because a user might have logged out from only 1 device and there are few more devices on which he/she is still logged in.

How will I know that for this particular user and device, the registration id is changed?

Should I store all the old registration ids and their corresponding canonical_ids in my database?

Eran
  • 387,369
  • 54
  • 702
  • 768
user1537779
  • 2,311
  • 5
  • 28
  • 45
  • 1
    Hey.. you are on wrong track.. you should not clear or unregistered the device when user logs out. reg_id is device specific not the user_specific. In DB logic it must be single value for all users.. like one_to_many relation... – Pankaj Kumar May 31 '13 at 07:24
  • What you should do is.. you should track a flag for current loggedin user.. and send an identification of user from server into message. when you will get message from server you need to check that identification with flag and show message. – Pankaj Kumar May 31 '13 at 07:29
  • `reg_id is device specific not the user_specific` True. But server side I will have notification for a user(ie. user_id) using which I will get a registration_id from the db and send the notification. – user1537779 May 31 '13 at 08:19
  • thats true.. so no need to clear reg_id. See my second comment.. and tell me what is confusion here – Pankaj Kumar May 31 '13 at 08:23
  • If the user_1 logged out and I didn't clear the reg_id, later user_2 logs in and the app checks if reg_id is present and doesn't register this user_2 with the current/new reg_id. Which mean I will not have a db entry for user_2 and he will never receive a notification. – user1537779 May 31 '13 at 08:26
  • But I can do one thing: clear reg_id, but don't delete it from db, which will send a notification and device will receive it but checks if_loggedin and then only displays. But this isn't the best solution since I am using the whole service and just not displaying it. – user1537779 May 31 '13 at 08:28
  • Then you should add a flag on server for user status.. if status is logged in then only send notification.. – Pankaj Kumar May 31 '13 at 08:37

2 Answers2

5

You have two options :

  1. As suggested in the comments - keep the registration ID of the user that logged-out in your DB, but mark it with a flag that indicates it's a logged-out user. Your server won't send notifications to registrations IDs marked as logged-out.

  2. When a user logs out from your app on a device, the app on that device will un-register from GCM and send a log-out request to your server with the user-id and the registration ID. The server will delete that user-id/registration-id combination from the DB. Even if for some reason your server contains a newer registration ID for that device (causing the delete attempt to fail), you won't be able to send notifications to the device with that registration ID, since the app unregistered the device from the GCM service. But this case is not likely to happen anyway, since whenever GCM changes the registration ID for a given app on a given device, is sends that registration ID to the app, and the app should send in to your server. Only failing to do so may cause the situation in which your server sends a notification with an old registration ID and gets a new canonical registration ID in the response.

Eran
  • 387,369
  • 54
  • 702
  • 768
  • **Going by your 1st option:** I register a device for my app and I get a reg_id `x_id` which is stored as a persistent data on the device. Now after sometime the reg_id is changed to `y_id`(canonical_id), which only the server knows. Now If user logs out and I tell the server to `mark the user_id with reg_id = x_id as logged out` even then I end up sending notifications to the same device using `y_id` because I cannot makeout that `x_id` must be replaced by its canonical_id `y_id`. Or should I send the canonical_id to my android app along with the notification message? ToUpdatePersistentData? – user1537779 Jun 03 '13 at 05:19
  • @user1537779 If Google changes the reg_id from `x_id` to `y_id`, that info is sent to your app, which should change the value stored on the device and send it to your server (which should replace `x_id` with `y_id`). That's why when the user logs out, you should be able to tell your server to mark the user_id with `y_id` as logged out. If your Android app fails to do that, you can do what you suggest (send the canonical id to your app in order to update its persistent data), but that should only be done as a fail-safe measure, since it shouldn't happen if you handle reg-id changes correctly. – Eran Jun 03 '13 at 12:50
  • `that info is sent to your app` can you please tell how and when this is sent to the app. So far I thought only my server can track than by receiving canonical_id. – user1537779 Jun 03 '13 at 12:59
  • `Note that Google may periodically refresh the registration ID, so you should design your Android application with the understanding that the com.google.android.c2dm.intent.REGISTRATION intent may be called multiple times. Your Android application needs to be able to respond accordingly`. Your app should handle that intent, which contains the new Registration ID. If you get a canoncial_id in your server as a response from GCM Server, that means your app failed to deliver the new registration ID to your server. – Eran Jun 03 '13 at 13:03
  • I am not using intent. I use: `String regid = (GoogleCloudMessaging.getInstance(this)).register("My_Sender_ID");`. – user1537779 Jun 03 '13 at 13:06
  • Google don't say in their docs how to get the updated registration ID in the app when you use the new registration method (which is the one that you use). That either means that you still have to use the intent in order to receive these updates, or that they are not going to refresh the registration ID while your app is installed on a device and is registered to GCM. Until they update their docs your guess is as good as mine regarding how to handle this possibility and whether you should handle it at all. – Eran Jun 03 '13 at 13:21
  • can you help here: http://www.stackoverflow.com/questions/16916126/android-gcm-will-unregistering-the-app-from-gcm-remove-the-queued-messages – user1537779 Jun 04 '13 at 11:10
  • 1
    A little late here, but you should update your registration ID in the same BroadcastReceiver that you handle the `com.google.android.c2dm.intent.RECEIVE` in. For example, `if (intent.getAction().equals("com.google.android.c2dm.intent.REGISTRATION")) { mPrefs.edit().putString(Constants.Preferences.DEVICE_ID, intent.getStringExtra("registration_id")).apply(); } else if (intent.getAction().equals("com.google.android.c2dm.intent.RECEIVE")) { sendPushNotification(intent); }` – ashishduh Sep 22 '14 at 15:45
-1

private String android_id = Secure.getString(getContext().getContentResolver(),Secure.ANDROID_ID); This line will return an unique android_id for any device (thx) For any user you could store an array of devices, when logging send a message from the client or check every several minutes. Hope

Community
  • 1
  • 1
Neron T
  • 369
  • 2
  • 8