user1126515
user1126515

Reputation: 1163

questions about switching from C2DM to GCM

I'm converting my app from C2DM to GCM and have some questions.

I've modified the gcmquickstart example found here:

git clone https://github.com/googlesamples/google-services.git

In my class that extends Application, i've got:

public class MyApp extends Application {
    @Override
    public void onCreate() {
          super.onCreate();

      if (this.checkPlayServices()) {
            Intent intent = new Intent(this, RegistrationIntentService.class);
            startService(intent);
      }
      else{             
        Log.e(TAG,"Failed checkforGCM");
      }

     }
}

AFAIK, this starts the service and it'll run forever OR if the operating system shuts it down whereupon the operating system will restart it. Is that correct?

checkPlayServices() makes sure this is Android 2.3 or greater and Google Play Services is installed as these are the only requirements to use GCM. Is that correct?

public class RegistrationIntentService  extends IntentService{

private static final String TAG = "RegIntentService";

    public RegistrationIntentService() {
      super(TAG);
    }

    @Override
    protected void onHandleIntent(Intent intent) {

      try {
        // In the (unlikely) event that multiple refresh operations 
        // occur simultaneously,
        // ensure that they are processed sequentially.

        synchronized (TAG) {
            // [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);
            String token = instanceID.getToken(getString(R.string.googleProjectId),
                    GoogleCloudMessaging.INSTANCE_ID_SCOPE, null);

            Log.d(TAG, "GCM Registration Token: " + token);

            /* Store the token */

            // [END register_for_gcm]
        }
      } catch (Exception e) {
        Log.e(TAG, "Failed to complete token refresh", e);
      }
}

}

What "registers for GCM"? Is it this:

InstanceID instanceID = InstanceID.getInstance(this);

What "gets the token"? Is it this:

 String token = instanceID.getToken(getString(R.string.googleProjectId), GoogleCloudMessaging.INSTANCE_ID_SCOPE, null);

I'm a little troubled by the talk of refresh operations. Specifically, do I have to refresh the token periodically? If so then where, how and which one (InstanceID instanceID or String token) ?

AFAIK, GCM will send me a new token when appropriate. All I've got to do is be ready to accept it and store it at any time. Is that right?

Using RegistrationIntentService as shown above allows me to accept/store a token at any time. Is that right?

The synchronization is also a bit troubling. It seems to imply google could send me multiple registration tokens. Is there any way to trigger that so I can see the larger impact on my app?

Also what "subsequent calls are local" ? Calls to get the token I've received here and stored on the device?

public class MyInstanceIDListenerService extends InstanceIDListenerService {

    private static final String TAG = "MyInstanceIDLS";

    /**
     * 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.
     */
    // [START refresh_token]

    @Override
    public void onTokenRefresh() {
        // Fetch updated Instance ID token and notify our app's server of any changes (if applicable).
        Intent intent = new Intent(this, RegistrationIntentService.class);
        startService(intent);
    }
    // [END refresh_token]
}

This is where I am most confused. Based on reading the code, I think the idea is if the GCM server decides I need another instanceID then it will communicate the necessity to MyInstanceIDListenerService. At that point, MyInstanceIDListenerService will cause RegistrationIntentService to run and get the new instanceID and token. Is that correct?

/** Intent Service to handle each incoming GCM message */
public class MyGcmListenerService extends GcmListenerService {  
final static String TAG = "GcmService";

   /**
     * Called when message is received.
     *
     * @param from SenderID of the sender.
     * @param data Data bundle containing message data as key/value pairs.
     *             For Set of keys use data.keySet().
     */
    // [START receive_message]
    @Override
    public void onMessageReceived(String from, Bundle data) {

          //do stuff with data communicated from my server to this app
          //via the GCM registration token received in 
          //RegistrationIntentService. onHandleIntent(Intent intent)
    }
    // [END receive_message]
}

This Service is the most understandable to me. The whole point of this exercise is to have GCM assign a token to my app, my app to communicate the token to one of our servers, our server sends a message to GCM telling it "send this to the guy with this token" and it reaches my app in the above code. Is that correct?

Here's the AndroidManifest that puts it all together:

    <!-- [START gcm_receiver] -->
    <receiver
        android:name="com.google.android.gms.gcm.GcmReceiver"
        android:exported="true"
        android:permission="com.google.android.c2dm.permission.SEND" >
        <intent-filter>
            <action android:name="com.google.android.c2dm.intent.RECEIVE" />
            <category android:name="my.package" />
        </intent-filter>
    </receiver>
    <!-- [END gcm_receiver] -->

    <!-- [START gcm_listener] -->
    <service
        android:name="my.package.MyGcmListenerService"
        android:exported="false" >
        <intent-filter>
            <action android:name="com.google.android.c2dm.intent.RECEIVE" />
        </intent-filter>
    </service>
    <!-- [END gcm_listener] -->

    <service
        android:name="my.package.MyInstanceIDListenerService"
        android:exported="false">
        <intent-filter>
            <action android:name="com.google.android.gms.iid.InstanceID"/>
        </intent-filter>
    </service>

    <service
        android:name="my.package.RegistrationIntentService"
        android:exported="false">
    </service>

Why do I have to explicitly start RegistrationIntentService in MyApp with:

Intent intent = new Intent(this, RegistrationIntentService.class);
startService(intent);

but not the other services?

Upvotes: 0

Views: 114

Answers (1)

Chad Bingham
Chad Bingham

Reputation: 33856

if (this.checkPlayServices()) {
        Intent intent = new Intent(this, RegistrationIntentService.class);
        startService(intent);
}

this starts the service and it'll run forever OR if the operating system shuts it down whereupon the operating system will restart it. Is that correct?

No. An IntentService will only exist until its completed the code in onHandleIntent

checkPlayServices() makes sure this is Android 2.3 or greater and Google Play Services is installed as these are the only requirements to use GCM. Is that correct?

Yeah. And no. You also need a network connection. I like to check for network before checking Play Services.


What "registers for GCM"? Is it this:

InstanceID instanceID = InstanceID.getInstance(this);

What "gets the token"? Is it this:

 String token = instanceID.getToken(getString(R.string.googleProjectId), GoogleCloudMessaging.INSTANCE_ID_SCOPE, null);

Yes. getInstance() will register with GCM. getToken will give you the token registered to this user.


This Service is the most understandable to me. The whole point of this exercise is to have GCM assign a token to my app, my app to communicate the token to one of our servers, our server sends a message to GCM telling it "send this to the guy with this token" and it reaches my app in the above code. Is that correct?

Yeah. Pretty much.


Why do I have to explicitly start RegistrationIntentService in MyApp with:

Intent intent = new Intent(this, RegistrationIntentService.class);
startService(intent);

but not the other services?

You declare InstanceIDListenerService and GcmListenerService in your manifest because they need to run all the time. If you are not registered, then they wont do anything. The RegistrationService is not called in the manifest because you may not want it to start up immediately. For instance, if you want to have your user register with your app, then once that is authenticated you register with gcm by starting this service.

Upvotes: 0

Related Questions