4

I am trying to understand the code behind Google's GCM quickstart example. Specifically, I don't understand how the code checks whether registration is already done.

MainActivity:

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ...
        if (checkPlayServices()) {
            // Start IntentService to register this application with GCM.
            Intent intent = new Intent(this, RegistrationIntentService.class);
            startService(intent); 
        }
    }

RegistrationIntentService:

@Override
protected void onHandleIntent(Intent intent)
{
    SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);

    try {
        // [START register_for_gcm]
        // Initially this call goes out to the network to retrieve the token, subsequent calls
        // are local.
        // [START get_token]
        InstanceID instanceID = InstanceID.getInstance(this);
        // R.string.gcm_defaultSenderId (the Sender ID) is typically derived from google-services.json.
        // See https://developers.google.com/cloud-messaging/android/start for details on this file.
        String token = instanceID.getToken(getString(R.string.gcm_defaultSenderId),
                GoogleCloudMessaging.INSTANCE_ID_SCOPE, null);
        // [END get_token]
        Log.i(TAG, "GCM Registration Token: " + token);

        // TODO: Implement this method to send any registration to your app's servers.
        sendRegistrationToServer(token);

        // You should store a boolean that indicates whether the generated token has been
        // sent to your server. If the boolean is false, send the token to your server,
        // otherwise your server should have already received the token.
        sharedPreferences.edit().putBoolean(AppSharedPreferences.SENT_TOKEN_TO_SERVER, true).apply();
        // [END register_for_gcm]
    } catch (Exception e) {
        Log.d(TAG, "Failed to complete token refresh", e);
        // If an exception happens while fetching the new token or updating our registration data
        // on a third-party server, this ensures that we'll attempt the update at a later time.
        sharedPreferences.edit().putBoolean(AppSharedPreferences.SENT_TOKEN_TO_SERVER, false).apply();
    }
    // Notify UI that registration has completed, so the progress indicator can be hidden.
    Intent registrationComplete = new Intent(QuickstartPreferences.REGISTRATION_COMPLETE);
    LocalBroadcastManager.getInstance(this).sendBroadcast(registrationComplete);
}

In RegistrationIntentService, the comments say that initially the call goes to retrieve the token, but subsequent calls are local. Does this mean that it will simply check to see if the app already has the token and not make the call anymore? I really don't understand this portion and I don't see anywhere in this example code where it checks for the existence of the token.

mrQWERTY
  • 4,039
  • 13
  • 43
  • 91

2 Answers2

4

For that logic, you can refer to my working sample code:

public class MainActivity extends AppCompatActivity {

private final Context mContext = this;
private final String SENDER_ID = "425...."; // Project Number at https://console.developers.google.com/project/....
private final String SHARD_PREF = "com.example.gcmclient_preferences";
private final String GCM_TOKEN = "gcmtoken";
private final String LOG_TAG = "GCM";
public static TextView mTextView;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    SharedPreferences appPrefs = mContext.getSharedPreferences(SHARD_PREF, Context.MODE_PRIVATE);
    String token = appPrefs.getString(GCM_TOKEN, "");
    if (token.isEmpty()) {
        try {
            getGCMToken();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    mTextView = (TextView) findViewById(R.id.textView);
}    

private void getGCMToken() {
    new AsyncTask<Void, Void, Void>() {
        @Override
        protected Void doInBackground(Void... params) {
            try {
                InstanceID instanceID = InstanceID.getInstance(mContext);
                String token = instanceID.getToken(SENDER_ID, GoogleCloudMessaging.INSTANCE_ID_SCOPE, null);
                if (token != null && !token.isEmpty()) {
                    SharedPreferences appPrefs = mContext.getSharedPreferences(SHARD_PREF, Context.MODE_PRIVATE);
                    SharedPreferences.Editor prefsEditor = appPrefs.edit();
                    prefsEditor.putString(GCM_TOKEN, token);
                    prefsEditor.apply();
                }
                Log.i(LOG_TAG, token);
            } catch (IOException e) {
                e.printStackTrace();
            }
            return null;
        }
    }.execute();
}
}

You can read my answer at the following for more information

Adding Google Cloud Messagin (GCM) for Android - Registration process

Hope this helps!

Community
  • 1
  • 1
BNK
  • 23,994
  • 8
  • 77
  • 87
  • `R.string.gcm_defaultSenderId (the Sender ID) is typically derived from google-services.json.` Do you happen to know that how is this being done??? I mean how does the gcm sdk read `json` and load it into `R.string` – Weishi Z Aug 05 '16 at 22:34
  • @WeishiZeng sorry I don't know, however, perhaps you can find more info at http://stackoverflow.com/questions/31597953/what-does-google-services-json-really-do – BNK Aug 06 '16 at 06:06
1

InstanceID which is part of the Google Play Services library will check if there is a cached token and return that when getToken is called. If there is no cached token then it will go out to the network to retrieve a new token and return that.

Thus your application has to handle the possibility of that calling InstanceID.getToken will result in a network call. Hence the reason it is called in an IntentService.

Arthur Thompson
  • 9,087
  • 4
  • 29
  • 33