title: How to refresh registration token in GCM that expired after a while?
body: <p>this is my first question in here, sorry in advance if something is not ok in my question!</p>
  
  <p>I'm currently using <code>Xamarin</code> in <code>Visual Studio 2013</code> on a MacBook, I created a PCL project and I created all the things necessary to make the push notifications work for <code>iOS</code> and <code>Android</code>. Using a simulator and also a real device I can achieve both with a server side program where I use the device token created from the client side. Everything worked fine for a couple of hours but after a while both the tokens were expired.
  I know that because this is the response I gave from the server side.</p>
  
  <p>Device RegistrationId Expired: {e_bSR1SFBzg:APA91bHEQUEFvjn_mblu26MeKhAkcKRtXRLtaHOKYIsDTMDvJT3jmBDb4O6-hhu00ZhEcuAkpfaK-GKicbH1o5gtr3J9Sj9jyf-DVuikTd6DOBM0Tw70KFNcf3a2arMVLlHOy5QctQSn}</p>
  
  <p>And also if I try it from that link
  <a href="http://1-dot-sigma-freedom-752.appspot.com/gcmpusher.jsp" rel="nofollow">http://1-dot-sigma-freedom-752.appspot.com/gcmpusher.jsp</a></p>
  
  <p>To make it works again I deleted the app from the device and also from the emulator and after a restart a new device token was created and it worked for a while, after a couple of hours same problem.
  My doubt is about the </p>
  
  <blockquote>
    <p>InstanceIDListenerService</p>
  </blockquote>
  
  <p>file that maybe is not configured in the good way. Below part of my code, so if someone can give me any advice, since I am facing this problem for the last two days and I don't know what to do anymore.</p>
  
  <p>My <code>AndroidManifest.xml</code> file:</p>
  
  <pre><code>&lt;?xml version="1.0" encoding="utf-8"?&gt;
  &lt;manifest xmlns:android="http://schemas.android.com/apk/res/android" package="MY.PACKAGE.NAME" android:installLocation="auto" android:versionCode="1" android:versionName="1.0.0"&gt;
        &lt;uses-sdk android:minSdkVersion="14" /&gt;
        &lt;uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /&gt;
        &lt;uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /&gt;
        &lt;uses-permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" /&gt;
        &lt;uses-permission android:name="android.permission.ACCESS_MOCK_LOCATION" /&gt;
        &lt;uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /&gt;
        &lt;uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /&gt;
        &lt;uses-permission android:name="android.permission.INTERNET" /&gt;
        &lt;uses-permission android:name="android.permission.WAKE_LOCK" /&gt;
        &lt;uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" /&gt;
        &lt;uses-permission android:name="MY.PACKAGE.NAME.permission.C2D_MESSAGE" /&gt;
        &lt;permission android:name="MY.PACKAGE.NAME.permission.C2D_MESSAGE" android:protectionLevel="signature" /&gt;
        &lt;!--&lt;application android:label="TruckMe" android:icon="@drawable/ic_launcher"&gt;--&gt;
        &lt;application android:label="TruckMe" android:icon="@drawable/ic_launcher"&gt;
              &lt;meta-data android:name="com.google.android.maps.v2.API_KEY" android:value="KEY_FOR-MAPS" /&gt;
              &lt;receiver android:name="com.google.android.gms.gcm.GcmReceiver" android:exported="true" android:permission="com.google.android.c2dm.permission.SEND"&gt;
                    &lt;intent-filter&gt;
                          &lt;action android:name="com.google.android.c2dm.intent.RECEIVE" /&gt;
                          &lt;action android:name="com.google.android.c2dm.intent.REGISTRATION" /&gt;
                          &lt;category android:name="MY.PACKAGE.NAME" /&gt;
                    &lt;/intent-filter&gt;
              &lt;/receiver&gt;
        &lt;/application&gt;
  &lt;/manifest&gt;
  </code></pre>
  
  <p>Where of course I subsituted my real package name with that word and same thing for the Api_KEY.
  The <code>RegistrationIntentService.cs</code> file:</p>
  
  <pre><code>using System;
  using Android.App;
  using Android.Content;
  using Android.Util;
  using Android.Gms.Gcm;
  using Android.Gms.Gcm.Iid;
  
  
  namespace TruckMe.Droid.Infrastructure.Notifications
  {
      [Service(Exported = false)]
      public class RegistrationIntentService : IntentService
      {
          private const string SENDER_ID = "my_sender_num";
          static object locker = new object();
  
          public RegistrationIntentService() : base("RegistrationIntentService") { }
  
          protected override void OnHandleIntent(Intent intent)
          {
              try
              {
                  Log.Info("RegistrationIntentService", "Calling InstanceID.GetToken");
                  lock (locker)
                  {
                      // Initially this call goes out to the network to retrieve the token, subsequent calls are local.
                      var instanceID = InstanceID.GetInstance(this);
  
                      // See https://developers.google.com/cloud-messaging/android/start for details on this file.
                      var token = instanceID.GetToken(SENDER_ID, GoogleCloudMessaging.InstanceIdScope, null);
  
                      //Log.Info("RegistrationIntentService", "GCM Registration Token: " + token);
                      Console.WriteLine("RegistrationIntentService - GCM Token: " + token);
                      SendRegistrationToAppServer(token);
                      Subscribe(token);
                      //unSubscribe(token);
                  }
              }
              catch (Exception ex)
              {
                  Log.Debug("RegistrationIntentService", "Failed to get a registration token. Ex: " + ex.Message);
                  return;
              }
          }
  
          void SendRegistrationToAppServer(string token)
          {
              // Add custom implementation here as needed.
              //Console.WriteLine("RegistrationIntentService - GCM Token: " + token);
  
              // save the value to send it to our server to manage the notifications
              App.UserPreferences.SetString("DeviceToken", token);
          }
  
          void Subscribe(string token)
          {
              var pubSub = GcmPubSub.GetInstance(this);
              // subscribe to a topic group
              pubSub.Subscribe(token, "/topics/global", null); // working
  
          }
  
      }
  }
  </code></pre>
  
  <p>Then the <code>InstanceIDListenerService</code> file:</p>
  
  <pre><code>using Android.App;
  using Android.Content;
  using Android.Gms.Gcm.Iid;
  
  
  namespace TruckMe.Droid.Infrastructure.Notifications
  {
      [Service(Exported = false), IntentFilter(new[] { "com.google.android.gms.iid.InstanceID" })]
      public class MyInstanceIdListenerService : InstanceIDListenerService
      {
          /**
           * Called if InstanceID token is updated. This may occur if the security of the previous token had been compromised. 
           * This call is initiated by the InstanceID provider.
          */
          public override void OnTokenRefresh()
          {
              // Fetch updated Instance ID token and notify our app's server of any changes (if applicable).
              var intent = new Intent(this, typeof(RegistrationIntentService));
              StartService(intent);
          }
      }
  }
  </code></pre>
  
  <p>Let me know if the code to understand and analyze the problem is enough, thanks in advance</p>
  
  <p>[Edit]
  I forgot to add also the 'MainActivity' file where the registration service is called:</p>
  
  <pre><code>using System;
  using Android.App;
  using Android.Content;
  using Android.Content.PM;
  using Android.Gms.Common;
  using Android.Graphics.Drawables;
  using Android.Views;
  using Android.OS;
  using Xamarin;
  using TruckMe.Droid.Infrastructure;
  using TruckMe.Droid.Infrastructure.Notifications;
  
  
  namespace TruckMe.Droid
  {
      [Activity(Label = "TruckMe",
            MainLauncher = false,
            ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation,
            WindowSoftInputMode = SoftInput.AdjustPan)]
      public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsApplicationActivity
      {
  
          protected override void OnCreate(Bundle bundle)
          {
              base.OnCreate(bundle);
  
              if (IsPlayServicesAvailable())
              {
                  var intent = new Intent(this, typeof(RegistrationIntentService));
                  StartService(intent);
              }
  
              global::Xamarin.Forms.Forms.Init(this, bundle);
  
              FormsMaps.Init(this, bundle);
  
              //Forms.SetTitleBarVisibility(AndroidTitleBarVisibility.Never);
              LoadApplication(new App());
  
              // below the code to remove the icon from android navigation bar
              ActionBar.SetIcon(new ColorDrawable(Android.Graphics.Color.Transparent)); 
  
              App.Init(new AndroidUserPreferences());
          }
  
  
          public bool IsPlayServicesAvailable()
          {
              int resultCode = GoogleApiAvailability.Instance.IsGooglePlayServicesAvailable(this);
              if (resultCode != ConnectionResult.Success)
              {
                  if (GoogleApiAvailability.Instance.IsUserResolvableError(resultCode))
                      Console.WriteLine(GoogleApiAvailability.Instance.GetErrorString(resultCode));
                  else
                  {
                      Console.WriteLine("Sorry, this device is not supported");
                      Finish();
                  }
                  return false;
              }
              else
              {
                  Console.WriteLine("Google Play Services is available.");
                  return true;
              }
          }
  
      }
  }
  </code></pre>