32

With the last changes to Android GCM now a InstanceIDListenerService is provided to be able to listen to token refreshes by overriding the onTokenRefresh method.

But when will this method be called? And is there any way to test it manually?

Eylen
  • 2,617
  • 4
  • 27
  • 42
  • 3
    There is no easy way to to test it manually, but from [the Instance ID Lifecycle page](https://developers.google.com/instance-id/#instance_id_lifecycle), it states that `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`. So you might want to try reinstall your app during device restoration. – ztan Jun 04 '15 at 18:05

2 Answers2

42

To test it manually from the command line run:

adb shell am startservice -a com.google.android.gms.iid.InstanceID --es "CMD" "RST" -n your.package.name/your.own.MyInstanceIDListenerService

where:

  • Your app's package is your.package.name
  • The class name of your InstanceIDListenerService implementation is your.own.MyInstanceIDListenerService

This will send an intent to the service with the extras expected by the base class.

For this to work, the service needs to be set to exported temporarily:

<service
    android:name="your.own.MyInstanceIDListenerService"
    android:exported="true">
    <intent-filter>
        <action android:name="com.google.android.gms.iid.InstanceID"/>
    </intent-filter>
</service>

Note: this should only be done temporarily and never be exported in production or else other apps could access your service.

Patrick
  • 33,984
  • 10
  • 106
  • 126
Hermit
  • 1,214
  • 13
  • 24
  • 13
    If someone gets `Error: Requires permission not exported from uid` - you will need **temporary** to change in your manifest `android:exported="true"` for your service (and don't forget to change it back after finished testing). – Ognyan Aug 29 '15 at 08:00
  • For gradle : your.package.name must be the Application ID as mentioned in the build.gradle file of your application module, not the "package" property mentioned in the android manifest. (If they are different, which they can be) – Vinay W Dec 11 '15 at 09:39
  • great answer.. +1. I'm very curious about where you found this, though. – Vinay W Dec 11 '15 at 10:22
  • 1
    @VinayWadhwa I went through a decompiled InstanceIDListenerService class to see what it does. The code is obfuscated, but at least Android Studio makes the process painless. – Hermit Dec 11 '15 at 14:43
  • Interesting, it worked for me, I have one question, I'm using GCM topic subscription, after token changed, do I need to resubscribe all topics again ? – davidcoder Dec 13 '15 at 17:07
  • Better open a separate question about topic resubscription (if one doesn't already exist) – Hermit Dec 15 '15 at 12:27
  • 8
    got an exception : Error: Not Found; no service started :/ – Nininea Feb 18 '16 at 10:29
  • This method of testing works well for me. I used it with a Xamarin.Droid project. Remember if you are using Xamarin, you must locate the generated java namespace for your ID Listener service class in the acw-map.txt rather than attempt to use the C# namespace to correctly locate it when using adb. – Gavin Jul 14 '16 at 21:44
  • 3
    If you find Error: Not Found; no service started. Then just do `adb shell am startservice -a com.google.android.gms.iid.InstanceID --es "CMD" "RST" your.package.name` – Muhammad Riyaz Dec 12 '16 at 15:32
  • Your adb command was working with GCM but did you tried to fire the intent but for Firebase (FCM)? I tried and it is executed without error nor warnings but the onTokenRefresh() is never called. Any ideas? `adb shell am startservice -a com.google.firebase.INSTANCE_ID_EVENT --es "CMD" "RST" -n com.my.package/com.my.package.InstanceIDListenerService` – Tano Mar 21 '18 at 13:40
  • Should we also handle the case when service is not in foreground? I.e., should we call startforeground inside the InstanceIDListenerService by ourself? Or it is ensured that the service must be started when app is in foreground only? – Derekyy Nov 20 '18 at 02:58
2

onTokenRefresh() would be called if the token for your application has been updated by the Instance ID service. The main reason for onTokenRefresh() being called is to allow you to update your app server with the new token so it can send messages to your app.

You should not have to test the token value manually. The token is used mainly by your application server to send messages to your app. Thus when your application first runs you should call InstanceID.getToken() and send the token to your server. Then later if the token is updated you call InstanceID.getToken() again and send the new value to your server again.

Check here for an example.

bbarke
  • 309
  • 1
  • 14
Arthur Thompson
  • 9,087
  • 4
  • 29
  • 33
  • 6
    "You should not have to test " - for sure you should. – sstn May 03 '16 at 08:43
  • 1
    Also disagree with 'not needing to test'. You certainly should manually test triggering the onTokenRefresh() since this is your custom code. Otherwise, you cannot be certain the real GCM server refresh request will work in the future! – Gavin Jul 14 '16 at 21:43
  • 1
    Yeah, I see the need to test the code that you have in onTokenRefresh, what I meant here was that there is no way to invalidate an existing token which would then result in the onTokenRefresh callback. But there is nothing stopping you from testing the code within onTokenRefresh. – Arthur Thompson Jul 14 '16 at 21:51