28

Since GCM keeps getting updated, most of the resources I have searched seem outdated or unclear. Basically, I am confused over when the tokens and ID's expire. (For reference, I am working with Android.)

From what I understand (and please correct me if I'm wrong), my server has an API Key and a Sender ID. Using the Sender ID I can have my client request a Token via the InstanceID stored locally on my client. I'm already a bit confused here. The InstanceID is assigned the moment my app goes online? Does it ever change? What about when the app upgrades or is uninstalled and reinstalled (or the device is restored)? By calling InstanceID.getInstance will I always retrieve the same InstanceID, or will it eventually expire and give me a new one? Is there any value to storing the string you retrieve by calling getID()? The docs seem to indicate that you actually retrieve a new InstanceID when you call getID(), so that complicates things even more. (For reference, I'm referring to: https://developers.google.com/instance-id/)

Using the InstanceID, my client can request a Token from the GCM servers, which it then sends to my app server. My app server stores this Token, and can use this to send messages to the GCM servers, which will then send the message to the device. The device uses the stored InstanceID to actually receive these messages, I believe. So having a class that extends GcmListenerService will allow me to receive these messages with onMessageReceived? I don't have to do anything special (other than defining it in the AndroidManifest)? I don't have to actually tell it to use the InstanceID? It just magically knows?

When do these ID's and Tokens expire? Do they expire? I store the Token as a string on the server, but if at any point one of these expires, how do I know they have expired? I can always generate a new InstanceID and Token, that much seems easy, but then do the old ones stay active? How do I wipe the old tokens from the server? There seems to be an easy way to do this with APNS on the iOS side of things, where you can retrieve a list of all the expired tokens and just wipe them from your database.

B. Roth
  • 359
  • 1
  • 3
  • 12
  • I also have similar questions and discovered some answers here: https://developers.google.com/android/reference/com/google/android/gms/iid/InstanceID – Simon Aug 22 '15 at 18:23

3 Answers3

26

I've found myself asking most of these questions myself as I update my GCM implementation. After messing around with it a few days, here's my take on your questions.

From what I understand (and please correct me if I'm wrong), my server has an API Key and a Sender ID. Using the Sender ID I can have my client request a Token via the InstanceID stored locally on my client.

This is correct.

The InstanceID is assigned the moment my app goes online?

It looks like it's assigned as soon as your app launches, even if the device can't access the Internet.

Does it ever change? What about when the app upgrades or is uninstalled and reinstalled (or the device is restored)? By calling InstanceID.getInstance will I always retrieve the same InstanceID, or will it eventually expire and give me a new one?

According to the InstanceID documentation:

Instance ID is stable but may become invalid, if:

  • App deletes Instance ID
  • Device is factory reset
  • User uninstalls the app
  • User clears app data

If Instance ID has become invalid, the app can call getId() to request a new Instance ID.

I've tested uninstalling the app and clearing the data, and the results point to all of the above being true.

Is there any value to storing the string you retrieve by calling getID()?

It looks like the API handles storing this in your app's local storage for you.

Using the InstanceID, my client can request a Token from the GCM servers, which it then sends to my app server. My app server stores this Token, and can use this to send messages to the GCM servers, which will then send the message to the device. The device uses the stored InstanceID to actually receive these messages, I believe. So having a class that extends GcmListenerService will allow me to receive these messages with onMessageReceived? I don't have to do anything special (other than defining it in the AndroidManifest)? I don't have to actually tell it to use the InstanceID? It just magically knows?

As far as I can tell there wasn't any sort of InstanceId in the previous implementation, and it doesn't look like it's being explicitly used in this one either. If it is, it's being called within either GcmReceiver or GcmListenerService.

When do these ID's and Tokens expire? Do they expire?

I've already addressed ID's expiring and we can find out about Tokens expiring in the Android InstanceID implementation guide:

The Instance ID service initiates callbacks periodically (for example, every 6 months), requesting that your app refreshes its tokens. It may also initiate callbacks when:

  • There are security issues; for example, SSL or platform issues.
  • Device information is no longer valid; for example, backup and restore.
  • The Instance ID service is otherwise affected.

The guide says to subclass InstanceIDListenerService and override onTokenRefresh() to handle these scenarios.

I store the Token as a string on the server, but if at any point one of these expires, how do I know they have expired?

The guide for implementing GCM on your server says that the GCM server will respond to your server with some information about the token you used to try to send the push notification.

I can always generate a new InstanceID and Token, that much seems easy, but then do the old ones stay active?

My tests suggest that yes, they do.

How do I wipe the old tokens from the server? There seems to be an easy way to do this with APNS on the iOS side of things, where you can retrieve a list of all the expired tokens and just wipe them from your database.

I'm still looking into this and will update if I can figure something out.

Community
  • 1
  • 1
pumpkinpie65
  • 960
  • 2
  • 14
  • 16
  • 2
    According to this Guide (https://developers.google.com/cloud-messaging/registration) wiping old tokens and IDs from the GCM servers can be done with ```ÌnstanceID.deleteToken()``` and ```InstanceID.deleteInstanceID```. – degill Jan 28 '16 at 12:07
  • 1
    Also it seems that the ID handling is done on the mobile device itself (since deleteInstanceID and getID can both be called on the main thread thus not doing any network calls) whereas the token handling is connected to the gcm server (https://developers.google.com/android/reference/com/google/android/gms/iid/InstanceID.html) – degill Jan 28 '16 at 12:10
  • 1
    @degill It looks like you're right about `InstanceID.deleteToken()` and `InstanceID.deleteInstanceID()` deleting the tokens from the GCM servers, but I think what @b-roth was asking (and what I'm still curious about myself) is how can your server get a list of expired tokens from the GCM servers so that your server can delete them and stop trying to send notifications to them. Any ideas? – pumpkinpie65 Feb 08 '16 at 22:57
  • 1
    That is correct, I was trying to figure out how I can get a list of expired tokens so that I can delete them from my servers to avoid unnecessary bloat. I marked the answer as correct because it was very helpful, but I actually found a solution for this problem too. It's not super elegant or secure, but basically when the token is generated I save it on the device AND the server. Then, when the app starts on the device, I send the local copy of the token up to the server, and if it doesn't match the one on the server I erase the previous one. Hopefully this helps someone. – B. Roth Feb 27 '16 at 02:41
  • 1
    @b-roth That would only work as long as the device still has the same InstanceID, wouldn't it? So you still wouldn't delete the old tokens for devices that have been reset, had the app's data deleted, or had the app uninstalled and reinstalled. – pumpkinpie65 Mar 01 '16 at 18:14
  • 1
    @pumpkinpie65 That is true, this is only a solution assuming the app does not get reset. Our app has hardware ID's assigned to each device, but if you uninstalled and reinstalled we would lose that ID so it would be stuck in the DB. There is a way to solve that too, if you added an expiration date with my previous idea it could work. Basically, when the app starts up it sends the token, and then the DB stores the current time. If X amount of time passes and the current time has not been updated, then we wipe the token. – B. Roth Jun 01 '16 at 18:48
  • The answer is old but still **very** helpful although GCM moved to FCM. Most of this is still relevant – Sebastian Kaczmarek Apr 10 '19 at 08:45
6

Here is what I did to detect invalid tokens in my database.

There is a dry run option in GCM when sending a notification to user/list of users. When you set dry-run while sending notifications, it doesn't alert clients or show notifications to them but returns response about which tokens are valid(200) and which are not.

If you send a notification to 200 users with using dry-run option, then in the same order you will get the response from GCM.

Ersoy
  • 8,816
  • 6
  • 34
  • 48
3

What is Instance ID?

Instance ID provides a unique ID per instance of your apps. You can implement Instance ID for Android and iOS apps as well as Chrome apps/extensions.

In addition to providing unique IDs for authentication, Instance ID can generate security tokens for use with other services.

Key Features

  • Generate Security Tokens
  • Verify app authenticity
  • Confirm app device is active
  • Identify and track apps

Instance ID lifecycle

  1. 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.
  2. 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.
  3. 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.
  4. 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.

When does Instance ID become invalid?

  • App deletes Instance ID
  • Device is factory reset
  • User uninstalls the app
  • User clears app data

If Instance ID has become invalid, the app can call getId() to request a new Instance ID. To prove ownership of Instance ID and to allow servers to access data or services associated with the app, call getToken(String, String).

When to refresh tokens?

The Instance ID service initiates callbacks periodically (for example, every 6 months), requesting that your app refreshes its tokens. It may also initiate callbacks when:

There are security issues; for example, SSL or platform issues. Device information is no longer valid; for example, backup and restore. The Instance ID service is otherwise affected.

All you need to know about Instance ID can be found in the following official links:

Community
  • 1
  • 1
Darush
  • 11,403
  • 9
  • 62
  • 60