Home | History | Annotate | Download | only in gcm
      1 page.title=Implementing GCM Client
      2 page.tags=cloud,push,messaging
      3 @jd:body
      4 
      5 <div id="qv-wrapper">
      6 <div id="qv">
      7 
      8 
      9 <h2>In this document</h2>
     10 
     11 <ol class="toc">
     12 <li><a href="#play-services">Set Up Google Play Services</a></li>
     13 <li><a href="#manifest">Edit Your Application's Manifest</a></li>
     14 <li><a href="#app">Write Your Application</a>
     15   <ol class="toc">
     16     <li><a href="#sample-play">Check for Google Play Services APK</a></li>
     17     <li><a href="#sample-register">Register for GCM</a></li>
     18     <li><a href="#sample-send">Send a message</a></li>
     19     <li><a href="#sample-receive">Receive a message</a></li>
     20   </ol>
     21   <li><a href="#run">Running the Sample</a></li>
     22   <li><a href="#stats">Viewing Statistics</a></li>
     23 </li>
     24 
     25 </ol>
     26 
     27 <h2>See Also</h2>
     28 
     29 <ol class="toc">
     30 <li><a href="gs.html">Getting Started</a></li>
     31 <li><a href="server.html">Implementing GCM Server</a></li>
     32 </ol>
     33 
     34 </div>
     35 </div>
     36 
     37 <p>A GCM client is a GCM-enabled app that runs on an Android device. To write your
     38 client code, we recommend that you use the
     39 <a href="{@docRoot}reference/com/google/android/gms/gcm/GoogleCloudMessaging.html">
     40 {@code GoogleCloudMessaging}</a> APIs.
     41 The client helper library that was offered in previous versions of GCM still works,
     42 but it has been superseded by the more efficient
     43 <a href="{@docRoot}reference/com/google/android/gms/gcm/GoogleCloudMessaging.html">
     44 {@code GoogleCloudMessaging}</a> APIs.</p>
     45 
     46 <p>A full GCM implementation requires both a client implementation and a server
     47 implementation. For more
     48 information about implementing the server side, see <a href="server.html">
     49 Implementing GCM Server</a>.</p>
     50 
     51 <p>The following sections walk you through the steps involved in writing a GCM
     52 client-side application. Your client app can be arbitrarily complex, but at bare
     53 minimum, a GCM client app must include code to register (and thereby get a
     54 registration ID), and a broadcast receiver to receive messages sent by GCM.
     55 </p>
     56 
     57 <h2 id="play-services">Step 1: Set Up Google Play Services</h2>
     58 
     59 <p>To write your client application, use the
     60 <a href="{@docRoot}reference/com/google/android/gms/gcm/GoogleCloudMessaging.html">
     61 {@code GoogleCloudMessaging}</a> API.
     62 To use this API, you must set up your project to use the Google Play services SDK,
     63 as described in <a href="/google/play-services/setup.html">Setup Google Play
     64 Services SDK</a>.</p>
     65 
     66 <p class="note"><strong>Caution:</strong> When you add the Play Services library to
     67 your project, be sure to add it <em>with resources</em>, as described in
     68 <a href="{@docRoot}google/play-services/setup.html#Setup">
     69 Setup Google Play Services SDK</a>. The key point is that you must
     70 <em>reference</em> the library&mdash;simply adding a {@code .jar} file to
     71 your Eclipse project will not work. You must follow the directions
     72 for referencing a library, or your app won't be able to access
     73 the library's resources, and it won't run properly.
     74 If you're using Android Studio, this is the string to add to the
     75 {@code dependency} section of your application's {@code build.gradle} file:</p>
     76 
     77 <pre>dependencies {
     78   compile "com.google.android.gms:play-services:3.1.+"
     79 }
     80 </pre>
     81 
     82 
     83 <h2 id="manifest">Step 2: Edit Your Application's Manifest</h2>
     84 
     85 <p>Add the following to your application's manifest:</p>
     86 <ul>
     87   <li>The <code>com.google.android.c2dm.permission.RECEIVE</code> permission so
     88 the Android application can register and receive messages.</li>
     89   <li>The <code>android.permission.INTERNET</code> permission so the Android
     90 application can send the registration ID to the 3rd party server.</li>
     91   <li>The <code>android.permission.GET_ACCOUNTS</code> permission as GCM requires
     92 a Google account (necessary only if if the device is running a version lower than
     93 Android 4.0.4)</li>
     94   <li>The <code>android.permission.WAKE_LOCK</code> permission so the application
     95 can keep the processor from sleeping when a message is received. Optional&mdash;use
     96 only if the app wants to keep the device from sleeping.</li>
     97   <li>An <code>applicationPackage + &quot;.permission.C2D_MESSAGE&quot;</code>
     98 permission to prevent other Android applications from registering and receiving
     99 the Android application's messages. The permission name must exactly match this
    100 pattern&mdash;otherwise the Android application will not receive the messages.</li>
    101    <li>A receiver for <code>com.google.android.c2dm.intent.RECEIVE</code>, with
    102 the category set
    103 as <code>applicationPackage</code>. The receiver should require the
    104 <code>com.google.android.c2dm.SEND</code> permission, so that only the GCM
    105 Framework can send a message to it. If your app uses an {@link android.app.IntentService}
    106 (not required, but a common pattern), this receiver should be an instance of
    107 {@link android.support.v4.content.WakefulBroadcastReceiver}.
    108 A {@link android.support.v4.content.WakefulBroadcastReceiver} takes care of
    109 creating and managing a
    110 <a href="{@docRoot}reference/android/os/PowerManager.html#PARTIAL_WAKE_LOCK">
    111 partial wake lock</a> for your app.</li>
    112 
    113 <li>A {@link android.app.Service} (typically an {@link android.app.IntentService})
    114 to which the {@link android.support.v4.content.WakefulBroadcastReceiver} passes off
    115 the work of handling the GCM message, while ensuring that the device does not
    116 go back to sleep in the process. Including an {@link android.app.IntentService} is
    117 optional&mdash;you could choose to process your messages in a regular
    118 {@link android.content.BroadcastReceiver} instead, but realistically, most apps will
    119 use a {@link android.app.IntentService}.
    120 </li>
    121   <li>If the GCM feature is critical to the Android application's function, be sure to
    122 set <code>android:minSdkVersion=&quot;8&quot;</code> or higher in the manifest. This
    123 ensures that the Android application cannot be installed in an environment in which it
    124 could not run properly. </li>
    125 </ul>
    126 
    127 <p>Here are excerpts from a sample manifest that supports GCM:</p>
    128 
    129 <pre class="prettyprint pretty-xml">
    130 &lt;manifest package="com.example.gcm" ...&gt;
    131 
    132     &lt;uses-sdk android:minSdkVersion="8" android:targetSdkVersion="17"/&gt;
    133     &lt;uses-permission android:name="android.permission.INTERNET" /&gt;
    134     &lt;uses-permission android:name="android.permission.GET_ACCOUNTS" /&gt;
    135     &lt;uses-permission android:name="android.permission.WAKE_LOCK" /&gt;
    136     &lt;uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" /&gt;
    137 
    138     &lt;permission android:name="com.example.gcm.permission.C2D_MESSAGE"
    139         android:protectionLevel="signature" /&gt;
    140     &lt;uses-permission android:name="com.example.gcm.permission.C2D_MESSAGE" /&gt;
    141 
    142     &lt;application ...&gt;
    143         &lt;receiver
    144             android:name=".GcmBroadcastReceiver"
    145             android:permission="com.google.android.c2dm.permission.SEND" &gt;
    146             &lt;intent-filter&gt;
    147                 &lt;action android:name="com.google.android.c2dm.intent.RECEIVE" /&gt;
    148                 &lt;category android:name="com.example.gcm" /&gt;
    149             &lt;/intent-filter&gt;
    150         &lt;/receiver&gt;
    151         &lt;service android:name=".GcmIntentService" /&gt;
    152     &lt;/application&gt;
    153 
    154 &lt;/manifest&gt;
    155 </pre>
    156 
    157 <h2 id="app"> Step 3: Write Your Application</h2>
    158 
    159 <p>Finally, write your application. This section features a sample client
    160 application that illustrates how to use the
    161 <a href="{@docRoot}reference/com/google/android/gms/gcm/GoogleCloudMessaging.html">
    162 {@code GoogleCloudMessaging}</a> APIs. The sample consists of a main activity
    163 ({@code DemoActivity}), a {@link android.support.v4.content.WakefulBroadcastReceiver}
    164 ({@code GcmBroadcastReceiver}), and an {@link android.app.IntentService}
    165 ({@code GcmIntentService}). You can find the complete source code for this sample at the
    166 <a href="http://code.google.com/p/gcm">open source site</a>.</p>
    167 
    168 <p>Note the following:</p>
    169 
    170 <ul>
    171   <li>Among other things, the sample illustrates registration and upstream
    172 (device-to-cloud) messaging. Upstream messaging only applies to apps that are running against a
    173 <a href="ccs.html">CCS</a> (XMPP) server; HTTP-based servers don't support upstream messaging.</li>
    174   <li>The <a href="{@docRoot}reference/com/google/android/gms/gcm/GoogleCloudMessaging.html">
    175   {@code GoogleCloudMessaging}</a>
    176 registration APIs replace the old registration process, which was based on the
    177 now-obsolete client helper library. While the old registration process still works,
    178 we encourage you to use the newer
    179 <a href="{@docRoot}reference/com/google/android/gms/gcm/GoogleCloudMessaging.html">
    180 {@code GoogleCloudMessaging}</a>
    181 registration APIs, regardless of your underlying server.</li>
    182 </ul>
    183 
    184 <h3 id="sample-play">Check for Google Play Services APK</h3>
    185 
    186 <p>As described in <a href="{@docRoot}google/play-services/setup.html">
    187 Setup Google Play Services SDK</a>, apps that rely on the Play Services SDK
    188 should always check the device for a compatible Google Play services APK before
    189 accessing Google Play services features. In the sample app this check is done in
    190 two places: in the main activity's {@code onCreate()} method, and in its
    191 {@code onResume()} method. The check in {@code onCreate()} ensures that the app
    192 can't be used without a successful check. The check in {@code onResume()} ensures
    193 that if the user returns to the running app through some other means, such as
    194 through the back button, the check is still performed. If the
    195 device doesn't have a compatible Google Play services APK, your app can call
    196 {@code GooglePlayServicesUtil.getErrorDialog()} to allow users to download the
    197 APK from the Google Play Store or enable it in the device's system settings.
    198 For example:</p>
    199 
    200 <pre>private final static int PLAY_SERVICES_RESOLUTION_REQUEST = 9000;
    201 ...
    202 &#64;Override
    203 public void onCreate(Bundle savedInstanceState) {
    204     super.onCreate(savedInstanceState);
    205 
    206     setContentView(R.layout.main);
    207     mDisplay = (TextView) findViewById(R.id.display);
    208 
    209     context = getApplicationContext();
    210 
    211     // Check device for Play Services APK.
    212     if (checkPlayServices()) {
    213         // If this check succeeds, proceed with normal processing.
    214         // Otherwise, prompt user to get valid Play Services APK.
    215         ...
    216     }
    217 }
    218 
    219 // You need to do the Play Services APK check here too.
    220 &#64;Override
    221 protected void onResume() {
    222     super.onResume();
    223     checkPlayServices();
    224 }
    225 
    226 /**
    227  * Check the device to make sure it has the Google Play Services APK. If
    228  * it doesn't, display a dialog that allows users to download the APK from
    229  * the Google Play Store or enable it in the device's system settings.
    230  */
    231 private boolean checkPlayServices() {
    232     int resultCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable(this);
    233     if (resultCode != ConnectionResult.SUCCESS) {
    234         if (GooglePlayServicesUtil.isUserRecoverableError(resultCode)) {
    235             GooglePlayServicesUtil.getErrorDialog(resultCode, this,
    236                     PLAY_SERVICES_RESOLUTION_REQUEST).show();
    237         } else {
    238             Log.i(TAG, "This device is not supported.");
    239             finish();
    240         }
    241         return false;
    242     }
    243     return true;
    244 }</pre>
    245 
    246 <h3 id="sample-register">Register for GCM</h3>
    247 <p>An Android application needs to register with GCM servers before it can receive
    248 messages. When an app registers, it receives a registration ID, which it can then
    249 store for future use (note that registration IDs must be kept secret). In the
    250 following snippet the {@code onCreate()} method in the sample app's
    251 main activity checks to see if the app is already registered with GCM and with
    252 the server:</p>
    253 
    254 <pre>/**
    255  * Main UI for the demo app.
    256  */
    257 public class DemoActivity extends Activity {
    258 
    259     public static final String EXTRA_MESSAGE = "message";
    260     public static final String PROPERTY_REG_ID = "registration_id";
    261     private static final String PROPERTY_APP_VERSION = "appVersion";
    262     private final static int PLAY_SERVICES_RESOLUTION_REQUEST = 9000;
    263 
    264     /**
    265      * Substitute you own sender ID here. This is the project number you got
    266      * from the API Console, as described in "Getting Started."
    267      */
    268     String SENDER_ID = "Your-Sender-ID";
    269 
    270     /**
    271      * Tag used on log messages.
    272      */
    273     static final String TAG = "GCMDemo";
    274 
    275     TextView mDisplay;
    276     GoogleCloudMessaging gcm;
    277     AtomicInteger msgId = new AtomicInteger();
    278     SharedPreferences prefs;
    279     Context context;
    280 
    281     String regid;
    282 
    283     &#64;Override
    284     public void onCreate(Bundle savedInstanceState) {
    285         super.onCreate(savedInstanceState);
    286 
    287         setContentView(R.layout.main);
    288         mDisplay = (TextView) findViewById(R.id.display);
    289 
    290         context = getApplicationContext();
    291 
    292         // Check device for Play Services APK. If check succeeds, proceed with
    293         //  GCM registration.
    294         if (checkPlayServices()) {
    295             gcm = GoogleCloudMessaging.getInstance(this);
    296             regid = getRegistrationId(context);
    297 
    298             if (regid.isEmpty()) {
    299                 registerInBackground();
    300             }
    301         } else {
    302             Log.i(TAG, "No valid Google Play Services APK found.");
    303         }
    304     }
    305 ...
    306 }</pre>
    307 
    308 <p>The app calls {@code getRegistrationId()} to see whether there is an existing
    309 registration ID stored in shared preferences:</p>
    310 
    311 <pre>/**
    312  * Gets the current registration ID for application on GCM service.
    313  * &lt;p&gt;
    314  * If result is empty, the app needs to register.
    315  *
    316  * &#64;return registration ID, or empty string if there is no existing
    317  *         registration ID.
    318  */
    319 private String getRegistrationId(Context context) {
    320     final SharedPreferences prefs = getGCMPreferences(context);
    321     String registrationId = prefs.getString(PROPERTY_REG_ID, "");
    322     if (registrationId.isEmpty()) {
    323         Log.i(TAG, "Registration not found.");
    324         return "";
    325     }
    326     // Check if app was updated; if so, it must clear the registration ID
    327     // since the existing regID is not guaranteed to work with the new
    328     // app version.
    329     int registeredVersion = prefs.getInt(PROPERTY_APP_VERSION, Integer.MIN_VALUE);
    330     int currentVersion = getAppVersion(context);
    331     if (registeredVersion != currentVersion) {
    332         Log.i(TAG, "App version changed.");
    333         return "";
    334     }
    335     return registrationId;
    336 }
    337 ...
    338 /**
    339  * &#64;return Application's {&#64;code SharedPreferences}.
    340  */
    341 private SharedPreferences getGCMPreferences(Context context) {
    342     // This sample app persists the registration ID in shared preferences, but
    343     // how you store the regID in your app is up to you.
    344     return getSharedPreferences(DemoActivity.class.getSimpleName(),
    345             Context.MODE_PRIVATE);
    346 }</pre>
    347 
    348 <p>If the registration ID doesn't exist or the app was updated,
    349 {@code getRegistrationId()} returns an empty string
    350 to indicate that the app needs to get a new regID. {@code getRegistrationId()} calls
    351 the following method to check the app version:</p>
    352 
    353 <pre>/**
    354  * &#64;return Application's version code from the {&#64;code PackageManager}.
    355  */
    356 private static int getAppVersion(Context context) {
    357     try {
    358         PackageInfo packageInfo = context.getPackageManager()
    359                 .getPackageInfo(context.getPackageName(), 0);
    360         return packageInfo.versionCode;
    361     } catch (NameNotFoundException e) {
    362         // should never happen
    363         throw new RuntimeException("Could not get package name: " + e);
    364     }
    365 }</pre>
    366 
    367 
    368 <p>If there isn't a valid existing registration ID, {@code DemoActivity} calls the
    369 following {@code registerInBackground()} method to register. Note that because the GCM
    370 methods {@code register()} and {@code unregister()} are blocking, this has to
    371 take place on a background thread. This sample uses {@link android.os.AsyncTask}
    372 to accomplish this:</p>
    373 
    374 <pre>
    375 /**
    376  * Registers the application with GCM servers asynchronously.
    377  * &lt;p&gt;
    378  * Stores the registration ID and app versionCode in the application's
    379  * shared preferences.
    380  */
    381 private void registerInBackground() {
    382     new AsyncTask<Void, Void, String>() {
    383         &#64;Override
    384         protected String doInBackground(Void... params) {
    385             String msg = "";
    386             try {
    387                 if (gcm == null) {
    388                     gcm = GoogleCloudMessaging.getInstance(context);
    389                 }
    390                 regid = gcm.register(SENDER_ID);
    391                 msg = "Device registered, registration ID=" + regid;
    392 
    393                 // You should send the registration ID to your server over HTTP,
    394                 // so it can use GCM/HTTP or CCS to send messages to your app.
    395                 // The request to your server should be authenticated if your app
    396                 // is using accounts.
    397                 sendRegistrationIdToBackend();
    398 
    399                 // For this demo: we don't need to send it because the device
    400                 // will send upstream messages to a server that echo back the
    401                 // message using the 'from' address in the message.
    402 
    403                 // Persist the regID - no need to register again.
    404                 storeRegistrationId(context, regid);
    405             } catch (IOException ex) {
    406                 msg = "Error :" + ex.getMessage();
    407                 // If there is an error, don't just keep trying to register.
    408                 // Require the user to click a button again, or perform
    409                 // exponential back-off.
    410             }
    411             return msg;
    412         }
    413 
    414         &#64;Override
    415         protected void onPostExecute(String msg) {
    416             mDisplay.append(msg + "\n");
    417         }
    418     }.execute(null, null, null);
    419     ...
    420 }</pre>
    421 
    422 <p>Once you've received your registration ID, send it to your server:</p>
    423 <pre>
    424 /**
    425  * Sends the registration ID to your server over HTTP, so it can use GCM/HTTP
    426  * or CCS to send messages to your app. Not needed for this demo since the
    427  * device sends upstream messages to a server that echoes back the message
    428  * using the 'from' address in the message.
    429  */
    430 private void sendRegistrationIdToBackend() {
    431     // Your implementation here.
    432 }</pre>
    433 
    434 <p>After registering, the app calls {@code storeRegistrationId()} to store the
    435 registration ID in shared preferences for future use. This is just one way of
    436 persisting a regID. You might choose to use a different approach in your app:</p>
    437 
    438 <pre>/**
    439  * Stores the registration ID and app versionCode in the application's
    440  * {&#64;code SharedPreferences}.
    441  *
    442  * &#64;param context application's context.
    443  * &#64;param regId registration ID
    444  */
    445 private void storeRegistrationId(Context context, String regId) {
    446     final SharedPreferences prefs = getGCMPreferences(context);
    447     int appVersion = getAppVersion(context);
    448     Log.i(TAG, "Saving regId on app version " + appVersion);
    449     SharedPreferences.Editor editor = prefs.edit();
    450     editor.putString(PROPERTY_REG_ID, regId);
    451     editor.putInt(PROPERTY_APP_VERSION, appVersion);
    452     editor.commit();
    453 }</pre>
    454 
    455 <h3 id="sample-send">Send a message</h3>
    456 <p>When the user clicks the app's <strong>Send</strong> button, the app sends an
    457 upstream message using the
    458 <a href="{@docRoot}reference/com/google/android/gms/gcm/GoogleCloudMessaging.html">
    459 {@code GoogleCloudMessaging}</a> APIs. In order to receive the upstream message,
    460 your server should be connected to CCS. You can use one of the demo servers in
    461 <a href="ccs.html#implement">Implementing an XMPP-based App Server</a> to run the sample and connect
    462 to CCS.</p>
    463 
    464 <pre>public void onClick(final View view) {
    465     if (view == findViewById(R.id.send)) {
    466         new AsyncTask<Void, Void, String>() {
    467             &#64;Override
    468             protected String doInBackground(Void... params) {
    469                 String msg = "";
    470                 try {
    471                     Bundle data = new Bundle();
    472                         data.putString("my_message", "Hello World");
    473                         data.putString("my_action",
    474                                 "com.google.android.gcm.demo.app.ECHO_NOW");
    475                         String id = Integer.toString(msgId.incrementAndGet());
    476                         gcm.send(SENDER_ID + "@gcm.googleapis.com", id, data);
    477                         msg = "Sent message";
    478                 } catch (IOException ex) {
    479                     msg = "Error :" + ex.getMessage();
    480                 }
    481                 return msg;
    482             }
    483 
    484             &#64;Override
    485             protected void onPostExecute(String msg) {
    486                 mDisplay.append(msg + "\n");
    487             }
    488         }.execute(null, null, null);
    489     } else if (view == findViewById(R.id.clear)) {
    490         mDisplay.setText("");
    491     }
    492 }</pre>
    493 
    494 <h3 id="sample-receive">Receive a message</h3>
    495 
    496 <p>As described above in <a href="#manifest">Step 2</a>, the app includes a
    497 {@link android.support.v4.content.WakefulBroadcastReceiver} for the <code>com.google.android.c2dm.intent.RECEIVE</code>
    498 intent. A broadcast receiver is the mechanism GCM uses to deliver messages. When {@code onClick()}
    499 calls {@code gcm.send()}, it triggers the broadcast receiver's {@code onReceive()}
    500 method, which has the responsibility of making sure that the GCM message gets handled.</p>
    501 <p>A {@link android.support.v4.content.WakefulBroadcastReceiver} is a special type of
    502 broadcast receiver that takes care of
    503 creating and managing a
    504 <a href="{@docRoot}reference/android/os/PowerManager.html#PARTIAL_WAKE_LOCK">
    505 partial wake lock</a> for your app.
    506 It passes off the work of processing the GCM message to a
    507 {@link android.app.Service} (typically an
    508 {@link android.app.IntentService}), while ensuring that the device does not
    509 go back to sleep in the transition. If you don't hold a wake lock while transitioning
    510 the work to a service, you are effectively allowing the device to go back to sleep before
    511 the work completes. The net result is that the app might not finish processing
    512 the GCM message until some arbitrary point in the future, which is not what you want.</p>
    513 
    514 <p class="note"><strong>Note:</strong> Using {@link android.support.v4.content.WakefulBroadcastReceiver}
    515 is not a requirement. If you have a relatively simple app that doesn't require
    516 a service, you can intercept the GCM message in a regular {@link android.content.BroadcastReceiver}
    517 and do your processing there. Once you get the intent that GCM passes into
    518 your broadcast receiver's {@code onReceive()} method, what you do with it
    519 is up to you.</p>
    520 
    521 <p>This snippet starts {@code GcmIntentService} with the method
    522 {@link android.support.v4.content.WakefulBroadcastReceiver#startWakefulService startWakefulService()}.
    523 This method is comparable to {@link android.content.Context#startService startService()}, except that
    524 the {@link android.support.v4.content.WakefulBroadcastReceiver} is holding a
    525 wake lock when the service starts. The intent that is passed with
    526 {@link android.support.v4.content.WakefulBroadcastReceiver#startWakefulService startWakefulService()}
    527 holds an extra identifying the wake lock:</p>
    528 
    529 
    530 <pre>public class GcmBroadcastReceiver extends WakefulBroadcastReceiver {
    531     &#64;Override
    532     public void onReceive(Context context, Intent intent) {
    533         // Explicitly specify that GcmIntentService will handle the intent.
    534         ComponentName comp = new ComponentName(context.getPackageName(),
    535                 GcmIntentService.class.getName());
    536         // Start the service, keeping the device awake while it is launching.
    537         startWakefulService(context, (intent.setComponent(comp)));
    538         setResultCode(Activity.RESULT_OK);
    539     }
    540 }</pre>
    541 
    542 <p>The intent service shown below does the actual work of handling the GCM
    543 message. When the service is finished, it calls
    544 {@link android.support.v4.content.WakefulBroadcastReceiver#completeWakefulIntent GcmBroadcastReceiver.completeWakefulIntent()}
    545 to release the wake lock. The
    546 {@link android.support.v4.content.WakefulBroadcastReceiver#completeWakefulIntent completeWakefulIntent()}
    547 method has as its parameter the same intent that was
    548 passed in from the {@link android.support.v4.content.WakefulBroadcastReceiver}.
    549 </p>
    550 
    551 <p>This snippet processes the GCM message based on message type, and posts the
    552 result in a notification. But what you do with GCM messages in your app is up to
    553 you&mdash;the possibilities are endless. For example, the message might be a ping,
    554 telling the app to sync to a server to retrieve new content, or it might be a
    555 chat message that you display in the UI.</p>
    556 
    557 <pre>
    558 public class GcmIntentService extends IntentService {
    559     public static final int NOTIFICATION_ID = 1;
    560     private NotificationManager mNotificationManager;
    561     NotificationCompat.Builder builder;
    562 
    563     public GcmIntentService() {
    564         super("GcmIntentService");
    565     }
    566 
    567     &#64;Override
    568     protected void onHandleIntent(Intent intent) {
    569         Bundle extras = intent.getExtras();
    570         GoogleCloudMessaging gcm = GoogleCloudMessaging.getInstance(this);
    571         // The getMessageType() intent parameter must be the intent you received
    572         // in your BroadcastReceiver.
    573         String messageType = gcm.getMessageType(intent);
    574 
    575         if (!extras.isEmpty()) {  // has effect of unparcelling Bundle
    576             /*
    577              * Filter messages based on message type. Since it is likely that GCM
    578              * will be extended in the future with new message types, just ignore
    579              * any message types you're not interested in, or that you don't
    580              * recognize.
    581              */
    582             if (GoogleCloudMessaging.
    583                     MESSAGE_TYPE_SEND_ERROR.equals(messageType)) {
    584                 sendNotification("Send error: " + extras.toString());
    585             } else if (GoogleCloudMessaging.
    586                     MESSAGE_TYPE_DELETED.equals(messageType)) {
    587                 sendNotification("Deleted messages on server: " +
    588                         extras.toString());
    589             // If it's a regular GCM message, do some work.
    590             } else if (GoogleCloudMessaging.
    591                     MESSAGE_TYPE_MESSAGE.equals(messageType)) {
    592                 // This loop represents the service doing some work.
    593                 for (int i=0; i<5; i++) {
    594                     Log.i(TAG, "Working... " + (i+1)
    595                             + "/5 @ " + SystemClock.elapsedRealtime());
    596                     try {
    597                         Thread.sleep(5000);
    598                     } catch (InterruptedException e) {
    599                     }
    600                 }
    601                 Log.i(TAG, "Completed work @ " + SystemClock.elapsedRealtime());
    602                 // Post notification of received message.
    603                 sendNotification("Received: " + extras.toString());
    604                 Log.i(TAG, "Received: " + extras.toString());
    605             }
    606         }
    607         // Release the wake lock provided by the WakefulBroadcastReceiver.
    608         GcmBroadcastReceiver.completeWakefulIntent(intent);
    609     }
    610 
    611     // Put the message into a notification and post it.
    612     // This is just one simple example of what you might choose to do with
    613     // a GCM message.
    614     private void sendNotification(String msg) {
    615         mNotificationManager = (NotificationManager)
    616                 this.getSystemService(Context.NOTIFICATION_SERVICE);
    617 
    618         PendingIntent contentIntent = PendingIntent.getActivity(this, 0,
    619                 new Intent(this, DemoActivity.class), 0);
    620 
    621         NotificationCompat.Builder mBuilder =
    622                 new NotificationCompat.Builder(this)
    623         .setSmallIcon(R.drawable.ic_stat_gcm)
    624         .setContentTitle("GCM Notification")
    625         .setStyle(new NotificationCompat.BigTextStyle()
    626         .bigText(msg))
    627         .setContentText(msg);
    628 
    629         mBuilder.setContentIntent(contentIntent);
    630         mNotificationManager.notify(NOTIFICATION_ID, mBuilder.build());
    631     }
    632 }</pre>
    633 
    634 <h2 id="run">Running the Sample</h2>
    635 
    636 <p>To run the sample:</p>
    637 
    638 <ol>
    639   <li>Follow the instructions in <a href="gs.html">Getting Started</a> to get your sender ID and
    640   API key.</li>
    641   <li>Implement your client app, as described in this document. You can find the complete source
    642   code for the client app at the <a href="http://code.google.com/p/gcm">open source site</a>.</li>
    643   <li>Run one of the demo servers (Java or Python) provided in
    644 <a href="ccs.html#implement">Implementing an XMPP-based App Server</a>. Whichever demo server you
    645  choose, don't forget to edit its code before running it to supply
    646 your sender ID and API key.
    647 </li>
    648 
    649 </ol>
    650 
    651 <h2 id="stats">Viewing Statistics</h2>
    652 
    653 <p>To view  statistics and any error messages for your GCM applications:</p>
    654 <ol>
    655   <li> Go to the <code><a href="http://play.google.com/apps/publish">Developer Console</a></code>.</li>
    656   <li>Login with your developer account.
    657   <p>You will see a page that has a list of all of your apps.</p></li>
    658   <li> Click on the &quot;statistics&quot; link next to the app for which you
    659 want to view GCM stats.
    660   <p>Now you are on the statistics page.</p> </li>
    661   <li>Go to the drop-down menu and select the GCM metric you want to view.
    662   </li>
    663 </ol>
    664 <p class="note"><strong>Note:</strong> Stats on the Google API Console are not
    665 enabled for GCM. You must use the <a href="http://play.google.com/apps/publish">Developer Console</a>.</p>
    666 
    667