summaryrefslogtreecommitdiffstats
path: root/docs/html/google/gcm/client.jd
blob: d44ee3c6717c3dd0f78ec9829f8caf2112f8b1a7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
page.title=Implementing GCM Client
page.tags=cloud,push,messaging
@jd:body

<div id="qv-wrapper">
<div id="qv">


<h2>In this document</h2>

<ol class="toc">
<li><a href="#play-services">Set Up Google Play Services</a></li>
<li><a href="#manifest">Edit Your Application's Manifest</a></li>
<li><a href="#app">Write Your Application</a>
  <ol class="toc">
    <li><a href="#sample-play">Check for Google Play Services APK</a></li>
    <li><a href="#sample-register">Register for GCM</a></li>
    <li><a href="#sample-send">Send a message</a></li>
    <li><a href="#sample-receive">Receive a message</a></li>
  </ol>
  <li><a href="#run">Running the Sample</a></li>
  <li><a href="#stats">Viewing Statistics</a></li>
</li>

</ol>

<h2>See Also</h2>

<ol class="toc">
<li><a href="gs.html">Getting Started</a></li>
<li><a href="server.html">Implementing GCM Server</a></li>
</ol>

</div>
</div>

<p>A Google Cloud Messaging (GCM) client is a GCM-enabled app that runs on an
Android device. To write your client code, we recommend that you use the
<a href="{@docRoot}reference/com/google/android/gms/gcm/package-summary.html">
GCM APIs</a>.
The client helper library that was offered in previous versions of GCM still works,
but it has been superseded by the more efficient
<a href="{@docRoot}reference/com/google/android/gms/gcm/package-summary.html">
GCM APIs</a>.</p>

<p>A full GCM implementation requires both a client implementation and a server
implementation. For more
information about implementing the server side, see <a href="server.html">
Implementing GCM Server</a>.</p>

<p>The following sections walk you through the steps involved in writing a GCM
client-side application. Your client app can be arbitrarily complex, but at bare
minimum, a GCM client app must include code to register (and thereby get a
registration ID), and a broadcast receiver to receive messages sent by GCM.
</p>

<h2 id="play-services">Step 1: Set Up Google Play Services</h2>

<p>To write your client application, use the
<a href="{@docRoot}reference/com/google/android/gms/gcm/package-summary.html">
GCM APIs</a>.
To use this API, you must set up your project to use the Google Play services SDK,
as described in <a href="/google/play-services/setup.html">Setup Google Play
Services SDK</a>.</p>

<p class="note"><strong>Caution:</strong> When you add the Play Services library to
your project, be sure to add it <em>with resources</em>, as described in
<a href="{@docRoot}google/play-services/setup.html#Setup">
Setup Google Play Services SDK</a>. The key point is that you must
<em>reference</em> the library&mdash;simply adding a {@code .jar} file to
your Eclipse project will not work. You must follow the directions
for referencing a library, or your app won't be able to access
the library's resources, and it won't run properly.
If you're using Android Studio, this is the string to add to the
{@code dependency} section of your application's {@code build.gradle} file:</p>

<pre>dependencies {
  compile "com.google.android.gms:play-services:3.1.+"
}
</pre>


<h2 id="manifest">Step 2: Edit Your Application's Manifest</h2>

<p>Add the following to your application's manifest:</p>
<ul>
  <li>The <code>com.google.android.c2dm.permission.RECEIVE</code> permission so
the Android application can register and receive messages.</li>
  <li>The <code>android.permission.INTERNET</code> permission so the Android
application can send the registration ID to the 3rd party server.</li>
  <li>The <code>android.permission.GET_ACCOUNTS</code> permission as GCM requires
a Google account (necessary only if if the device is running a version lower than
Android 4.0.4)</li>
  <li>The <code>android.permission.WAKE_LOCK</code> permission so the application
can keep the processor from sleeping when a message is received. Optional&mdash;use
only if the app wants to keep the device from sleeping.</li>
  <li>An <code>applicationPackage + &quot;.permission.C2D_MESSAGE&quot;</code>
permission to prevent other Android applications from registering and receiving
the Android application's messages. The permission name must exactly match this
pattern&mdash;otherwise the Android application will not receive the messages.</li>
   <li>A receiver for <code>com.google.android.c2dm.intent.RECEIVE</code>, with
the category set
as <code>applicationPackage</code>. The receiver should require the
<code>com.google.android.c2dm.SEND</code> permission, so that only the GCM
Framework can send a message to it. If your app uses an {@link android.app.IntentService}
(not required, but a common pattern), this receiver should be an instance of
{@link android.support.v4.content.WakefulBroadcastReceiver}.
A {@link android.support.v4.content.WakefulBroadcastReceiver} takes care of
creating and managing a
<a href="{@docRoot}reference/android/os/PowerManager.html#PARTIAL_WAKE_LOCK">
partial wake lock</a> for your app.</li>

<li>A {@link android.app.Service} (typically an {@link android.app.IntentService})
to which the {@link android.support.v4.content.WakefulBroadcastReceiver} passes off
the work of handling the GCM message, while ensuring that the device does not
go back to sleep in the process. Including an {@link android.app.IntentService} is
optional&mdash;you could choose to process your messages in a regular
{@link android.content.BroadcastReceiver} instead, but realistically, most apps will
use a {@link android.app.IntentService}.
</li>
  <li>If the GCM feature is critical to the Android application's function, be sure to
set <code>android:minSdkVersion=&quot;8&quot;</code> or higher in the manifest. This
ensures that the Android application cannot be installed in an environment in which it
could not run properly. </li>
</ul>

<p>Here are excerpts from a sample manifest that supports GCM:</p>

<pre class="prettyprint pretty-xml">
&lt;manifest package="com.example.gcm" ...&gt;

    &lt;uses-sdk android:minSdkVersion="8" android:targetSdkVersion="17"/&gt;
    &lt;uses-permission android:name="android.permission.INTERNET" /&gt;
    &lt;uses-permission android:name="android.permission.GET_ACCOUNTS" /&gt;
    &lt;uses-permission android:name="android.permission.WAKE_LOCK" /&gt;
    &lt;uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" /&gt;

    &lt;permission android:name="com.example.gcm.permission.C2D_MESSAGE"
        android:protectionLevel="signature" /&gt;
    &lt;uses-permission android:name="com.example.gcm.permission.C2D_MESSAGE" /&gt;

    &lt;application ...&gt;
        &lt;receiver
            android:name=".GcmBroadcastReceiver"
            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;category android:name="com.example.gcm" /&gt;
            &lt;/intent-filter&gt;
        &lt;/receiver&gt;
        &lt;service android:name=".GcmIntentService" /&gt;
    &lt;/application&gt;

&lt;/manifest&gt;
</pre>

<h2 id="app"> Step 3: Write Your Application</h2>

<p>Finally, write your application. This section features a sample client
application that illustrates how to use the
<a href="{@docRoot}reference/com/google/android/gms/gcm/GoogleCloudMessaging.html">
{@code GoogleCloudMessaging}</a> API. The sample consists of a main activity
({@code DemoActivity}), a {@link android.support.v4.content.WakefulBroadcastReceiver}
({@code GcmBroadcastReceiver}), and an {@link android.app.IntentService}
({@code GcmIntentService}). You can find the complete source code for this sample at the
<a href="http://code.google.com/p/gcm">open source site</a>.</p>

<p>Note the following:</p>

<ul>
  <li>Among other things, the sample illustrates registration and upstream
(device-to-cloud) messaging. Upstream messaging only applies to apps that are running against a
<a href="ccs.html">CCS</a> (XMPP) server; HTTP-based servers don't support upstream messaging.</li>
  <li>The <a href="{@docRoot}reference/com/google/android/gms/gcm/GoogleCloudMessaging.html">
  {@code GoogleCloudMessaging}</a>
registration APIs replace the old registration process, which was based on the
now-obsolete client helper library. While the old registration process still works,
we encourage you to use the newer
<a href="{@docRoot}reference/com/google/android/gms/gcm/GoogleCloudMessaging.html">
{@code GoogleCloudMessaging}</a>
registration APIs, regardless of your underlying server.</li>
</ul>

<h3 id="sample-play">Check for Google Play Services APK</h3>

<p>As described in <a href="{@docRoot}google/play-services/setup.html">
Setup Google Play Services SDK</a>, apps that rely on the Play Services SDK
should always check the device for a compatible Google Play services APK before
accessing Google Play services features. In the sample app this check is done in
two places: in the main activity's {@code onCreate()} method, and in its
{@code onResume()} method. The check in {@code onCreate()} ensures that the app
can't be used without a successful check. The check in {@code onResume()} ensures
that if the user returns to the running app through some other means, such as
through the back button, the check is still performed. If the
device doesn't have a compatible Google Play services APK, your app can call
{@code GooglePlayServicesUtil.getErrorDialog()} to allow users to download the
APK from the Google Play Store or enable it in the device's system settings.
For example:</p>

<pre>private final static int PLAY_SERVICES_RESOLUTION_REQUEST = 9000;
...
&#64;Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    setContentView(R.layout.main);
    mDisplay = (TextView) findViewById(R.id.display);

    context = getApplicationContext();

    // Check device for Play Services APK.
    if (checkPlayServices()) {
        // If this check succeeds, proceed with normal processing.
        // Otherwise, prompt user to get valid Play Services APK.
        ...
    }
}

// You need to do the Play Services APK check here too.
&#64;Override
protected void onResume() {
    super.onResume();
    checkPlayServices();
}

/**
 * Check the device to make sure it has the Google Play Services APK. If
 * it doesn't, display a dialog that allows users to download the APK from
 * the Google Play Store or enable it in the device's system settings.
 */
private boolean checkPlayServices() {
    int resultCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable(this);
    if (resultCode != ConnectionResult.SUCCESS) {
        if (GooglePlayServicesUtil.isUserRecoverableError(resultCode)) {
            GooglePlayServicesUtil.getErrorDialog(resultCode, this,
                    PLAY_SERVICES_RESOLUTION_REQUEST).show();
        } else {
            Log.i(TAG, "This device is not supported.");
            finish();
        }
        return false;
    }
    return true;
}</pre>

<h3 id="sample-register">Register for GCM</h3>
<p>An Android application needs to register with GCM servers before it can receive
messages. When an app registers, it receives a registration ID, which it can then
store for future use (note that registration IDs must be kept secret). In the
following snippet the {@code onCreate()} method in the sample app's
main activity checks to see if the app is already registered with GCM and with
the server:</p>

<pre>/**
 * Main UI for the demo app.
 */
public class DemoActivity extends Activity {

    public static final String EXTRA_MESSAGE = "message";
    public static final String PROPERTY_REG_ID = "registration_id";
    private static final String PROPERTY_APP_VERSION = "appVersion";
    private final static int PLAY_SERVICES_RESOLUTION_REQUEST = 9000;

    /**
     * Substitute you own sender ID here. This is the project number you got
     * from the API Console, as described in "Getting Started."
     */
    String SENDER_ID = "Your-Sender-ID";

    /**
     * Tag used on log messages.
     */
    static final String TAG = "GCMDemo";

    TextView mDisplay;
    GoogleCloudMessaging gcm;
    AtomicInteger msgId = new AtomicInteger();
    SharedPreferences prefs;
    Context context;

    String regid;

    &#64;Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.main);
        mDisplay = (TextView) findViewById(R.id.display);

        context = getApplicationContext();

        // Check device for Play Services APK. If check succeeds, proceed with
        //  GCM registration.
        if (checkPlayServices()) {
            gcm = GoogleCloudMessaging.getInstance(this);
            regid = getRegistrationId(context);

            if (regid.isEmpty()) {
                registerInBackground();
            }
        } else {
            Log.i(TAG, "No valid Google Play Services APK found.");
        }
    }
...
}</pre>

<p>The app calls {@code getRegistrationId()} to see whether there is an existing
registration ID stored in shared preferences:</p>

<pre>/**
 * Gets the current registration ID for application on GCM service.
 * &lt;p&gt;
 * If result is empty, the app needs to register.
 *
 * &#64;return registration ID, or empty string if there is no existing
 *         registration ID.
 */
private String getRegistrationId(Context context) {
    final SharedPreferences prefs = getGCMPreferences(context);
    String registrationId = prefs.getString(PROPERTY_REG_ID, "");
    if (registrationId.isEmpty()) {
        Log.i(TAG, "Registration not found.");
        return "";
    }
    // Check if app was updated; if so, it must clear the registration ID
    // since the existing regID is not guaranteed to work with the new
    // app version.
    int registeredVersion = prefs.getInt(PROPERTY_APP_VERSION, Integer.MIN_VALUE);
    int currentVersion = getAppVersion(context);
    if (registeredVersion != currentVersion) {
        Log.i(TAG, "App version changed.");
        return "";
    }
    return registrationId;
}
...
/**
 * &#64;return Application's {&#64;code SharedPreferences}.
 */
private SharedPreferences getGCMPreferences(Context context) {
    // This sample app persists the registration ID in shared preferences, but
    // how you store the regID in your app is up to you.
    return getSharedPreferences(DemoActivity.class.getSimpleName(),
            Context.MODE_PRIVATE);
}</pre>

<p>If the registration ID doesn't exist or the app was updated,
{@code getRegistrationId()} returns an empty string
to indicate that the app needs to get a new regID. {@code getRegistrationId()} calls
the following method to check the app version:</p>

<pre>/**
 * &#64;return Application's version code from the {&#64;code PackageManager}.
 */
private static int getAppVersion(Context context) {
    try {
        PackageInfo packageInfo = context.getPackageManager()
                .getPackageInfo(context.getPackageName(), 0);
        return packageInfo.versionCode;
    } catch (NameNotFoundException e) {
        // should never happen
        throw new RuntimeException("Could not get package name: " + e);
    }
}</pre>


<p>If there isn't a valid existing registration ID, {@code DemoActivity} calls the
following {@code registerInBackground()} method to register. Note that because the GCM
methods {@code register()} and {@code unregister()} are blocking, this has to
take place on a background thread. This sample uses {@link android.os.AsyncTask}
to accomplish this:</p>

<pre>
/**
 * Registers the application with GCM servers asynchronously.
 * &lt;p&gt;
 * Stores the registration ID and app versionCode in the application's
 * shared preferences.
 */
private void registerInBackground() {
    new AsyncTask<Void, Void, String>() {
        &#64;Override
        protected String doInBackground(Void... params) {
            String msg = "";
            try {
                if (gcm == null) {
                    gcm = GoogleCloudMessaging.getInstance(context);
                }
                regid = gcm.register(SENDER_ID);
                msg = "Device registered, registration ID=" + regid;

                // You should send the registration ID to your server over HTTP,
                // so it can use GCM/HTTP or CCS to send messages to your app.
                // The request to your server should be authenticated if your app
                // is using accounts.
                sendRegistrationIdToBackend();

                // For this demo: we don't need to send it because the device
                // will send upstream messages to a server that echo back the
                // message using the 'from' address in the message.

                // Persist the regID - no need to register again.
                storeRegistrationId(context, regid);
            } catch (IOException ex) {
                msg = "Error :" + ex.getMessage();
                // If there is an error, don't just keep trying to register.
                // Require the user to click a button again, or perform
                // exponential back-off.
            }
            return msg;
        }

        &#64;Override
        protected void onPostExecute(String msg) {
            mDisplay.append(msg + "\n");
        }
    }.execute(null, null, null);
    ...
}</pre>

<p>Once you've received your registration ID, send it to your server:</p>
<pre>
/**
 * Sends the registration ID to your server over HTTP, so it can use GCM/HTTP
 * or CCS to send messages to your app. Not needed for this demo since the
 * device sends upstream messages to a server that echoes back the message
 * using the 'from' address in the message.
 */
private void sendRegistrationIdToBackend() {
    // Your implementation here.
}</pre>

<p>After registering, the app calls {@code storeRegistrationId()} to store the
registration ID in shared preferences for future use. This is just one way of
persisting a regID. You might choose to use a different approach in your app:</p>

<pre>/**
 * Stores the registration ID and app versionCode in the application's
 * {&#64;code SharedPreferences}.
 *
 * &#64;param context application's context.
 * &#64;param regId registration ID
 */
private void storeRegistrationId(Context context, String regId) {
    final SharedPreferences prefs = getGCMPreferences(context);
    int appVersion = getAppVersion(context);
    Log.i(TAG, "Saving regId on app version " + appVersion);
    SharedPreferences.Editor editor = prefs.edit();
    editor.putString(PROPERTY_REG_ID, regId);
    editor.putInt(PROPERTY_APP_VERSION, appVersion);
    editor.commit();
}</pre>

<h4 id="reg-errors">Handle registration errors</h4>

<p>As stated above, an Android app must register with GCM servers and get a registration ID
(regID) before it can receive messages. A given regID is not guaranteed to last indefinitely,
so the first thing your app should always do is check to make sure it has a valid regID
(as shown in the code snippets above).</p>

<p>In addition to confirming that it has a valid regID, your app should be prepared to handle
the registration error {@code TOO_MANY_REGISTRATIONS}. This error indicates that the device
has too many apps registered with GCM. The error only occurs in cases where there are
extreme numbers of apps, so it should not affect the average user. The remedy is to prompt
the user to delete some of the other GCM-enabled apps from the device to make
room for the new one.</p>


<h3 id="sample-send">Send a message</h3>
<p>When the user clicks the app's <strong>Send</strong> button, the app sends an
upstream message using the
<a href="{@docRoot}reference/com/google/android/gms/gcm/GoogleCloudMessaging.html">
{@code GoogleCloudMessaging}</a> API. In order to receive the upstream message,
your server should be connected to CCS. You can use one of the demo servers in
<a href="ccs.html#implement">Implementing an XMPP-based App Server</a> to run the sample and connect
to CCS.</p>

<pre>public void onClick(final View view) {
    if (view == findViewById(R.id.send)) {
        new AsyncTask<Void, Void, String>() {
            &#64;Override
            protected String doInBackground(Void... params) {
                String msg = "";
                try {
                    Bundle data = new Bundle();
                        data.putString("my_message", "Hello World");
                        data.putString("my_action",
                                "com.google.android.gcm.demo.app.ECHO_NOW");
                        String id = Integer.toString(msgId.incrementAndGet());
                        gcm.send(SENDER_ID + "@gcm.googleapis.com", id, data);
                        msg = "Sent message";
                } catch (IOException ex) {
                    msg = "Error :" + ex.getMessage();
                }
                return msg;
            }

            &#64;Override
            protected void onPostExecute(String msg) {
                mDisplay.append(msg + "\n");
            }
        }.execute(null, null, null);
    } else if (view == findViewById(R.id.clear)) {
        mDisplay.setText("");
    }
}</pre>

<h3 id="sample-receive">Receive a message</h3>

<p>As described above in <a href="#manifest">Step 2</a>, the app includes a
{@link android.support.v4.content.WakefulBroadcastReceiver} for the <code>com.google.android.c2dm.intent.RECEIVE</code>
intent. A broadcast receiver is the mechanism GCM uses to deliver messages. When {@code onClick()}
calls {@code gcm.send()}, it triggers the broadcast receiver's {@code onReceive()}
method, which has the responsibility of making sure that the GCM message gets handled.</p>
<p>A {@link android.support.v4.content.WakefulBroadcastReceiver} is a special type of
broadcast receiver that takes care of
creating and managing a
<a href="{@docRoot}reference/android/os/PowerManager.html#PARTIAL_WAKE_LOCK">
partial wake lock</a> for your app.
It passes off the work of processing the GCM message to a
{@link android.app.Service} (typically an
{@link android.app.IntentService}), while ensuring that the device does not
go back to sleep in the transition. If you don't hold a wake lock while transitioning
the work to a service, you are effectively allowing the device to go back to sleep before
the work completes. The net result is that the app might not finish processing
the GCM message until some arbitrary point in the future, which is not what you want.</p>

<p class="note"><strong>Note:</strong> Using {@link android.support.v4.content.WakefulBroadcastReceiver}
is not a requirement. If you have a relatively simple app that doesn't require
a service, you can intercept the GCM message in a regular {@link android.content.BroadcastReceiver}
and do your processing there. Once you get the intent that GCM passes into
your broadcast receiver's {@code onReceive()} method, what you do with it
is up to you.</p>

<p>This snippet starts {@code GcmIntentService} with the method
{@link android.support.v4.content.WakefulBroadcastReceiver#startWakefulService startWakefulService()}.
This method is comparable to {@link android.content.Context#startService startService()}, except that
the {@link android.support.v4.content.WakefulBroadcastReceiver} is holding a
wake lock when the service starts. The intent that is passed with
{@link android.support.v4.content.WakefulBroadcastReceiver#startWakefulService startWakefulService()}
holds an extra identifying the wake lock:</p>


<pre>public class GcmBroadcastReceiver extends WakefulBroadcastReceiver {
    &#64;Override
    public void onReceive(Context context, Intent intent) {
        // Explicitly specify that GcmIntentService will handle the intent.
        ComponentName comp = new ComponentName(context.getPackageName(),
                GcmIntentService.class.getName());
        // Start the service, keeping the device awake while it is launching.
        startWakefulService(context, (intent.setComponent(comp)));
        setResultCode(Activity.RESULT_OK);
    }
}</pre>

<p>The intent service shown below does the actual work of handling the GCM
message. When the service is finished, it calls
{@link android.support.v4.content.WakefulBroadcastReceiver#completeWakefulIntent GcmBroadcastReceiver.completeWakefulIntent()}
to release the wake lock. The
{@link android.support.v4.content.WakefulBroadcastReceiver#completeWakefulIntent completeWakefulIntent()}
method has as its parameter the same intent that was
passed in from the {@link android.support.v4.content.WakefulBroadcastReceiver}.
</p>

<p>This snippet processes the GCM message based on message type, and posts the
result in a notification. But what you do with GCM messages in your app is up to
you&mdash;the possibilities are endless. For example, the message might be a ping,
telling the app to sync to a server to retrieve new content, or it might be a
chat message that you display in the UI.</p>

<pre>
public class GcmIntentService extends IntentService {
    public static final int NOTIFICATION_ID = 1;
    private NotificationManager mNotificationManager;
    NotificationCompat.Builder builder;

    public GcmIntentService() {
        super("GcmIntentService");
    }

    &#64;Override
    protected void onHandleIntent(Intent intent) {
        Bundle extras = intent.getExtras();
        GoogleCloudMessaging gcm = GoogleCloudMessaging.getInstance(this);
        // The getMessageType() intent parameter must be the intent you received
        // in your BroadcastReceiver.
        String messageType = gcm.getMessageType(intent);

        if (!extras.isEmpty()) {  // has effect of unparcelling Bundle
            /*
             * Filter messages based on message type. Since it is likely that GCM
             * will be extended in the future with new message types, just ignore
             * any message types you're not interested in, or that you don't
             * recognize.
             */
            if (GoogleCloudMessaging.
                    MESSAGE_TYPE_SEND_ERROR.equals(messageType)) {
                sendNotification("Send error: " + extras.toString());
            } else if (GoogleCloudMessaging.
                    MESSAGE_TYPE_DELETED.equals(messageType)) {
                sendNotification("Deleted messages on server: " +
                        extras.toString());
            // If it's a regular GCM message, do some work.
            } else if (GoogleCloudMessaging.
                    MESSAGE_TYPE_MESSAGE.equals(messageType)) {
                // This loop represents the service doing some work.
                for (int i=0; i<5; i++) {
                    Log.i(TAG, "Working... " + (i+1)
                            + "/5 @ " + SystemClock.elapsedRealtime());
                    try {
                        Thread.sleep(5000);
                    } catch (InterruptedException e) {
                    }
                }
                Log.i(TAG, "Completed work @ " + SystemClock.elapsedRealtime());
                // Post notification of received message.
                sendNotification("Received: " + extras.toString());
                Log.i(TAG, "Received: " + extras.toString());
            }
        }
        // Release the wake lock provided by the WakefulBroadcastReceiver.
        GcmBroadcastReceiver.completeWakefulIntent(intent);
    }

    // Put the message into a notification and post it.
    // This is just one simple example of what you might choose to do with
    // a GCM message.
    private void sendNotification(String msg) {
        mNotificationManager = (NotificationManager)
                this.getSystemService(Context.NOTIFICATION_SERVICE);

        PendingIntent contentIntent = PendingIntent.getActivity(this, 0,
                new Intent(this, DemoActivity.class), 0);

        NotificationCompat.Builder mBuilder =
                new NotificationCompat.Builder(this)
        .setSmallIcon(R.drawable.ic_stat_gcm)
        .setContentTitle("GCM Notification")
        .setStyle(new NotificationCompat.BigTextStyle()
        .bigText(msg))
        .setContentText(msg);

        mBuilder.setContentIntent(contentIntent);
        mNotificationManager.notify(NOTIFICATION_ID, mBuilder.build());
    }
}</pre>

<h2 id="run">Running the Sample</h2>

<p>To run the sample:</p>

<ol>
  <li>Follow the instructions in <a href="gs.html">Getting Started</a> to get your sender ID and
  API key.</li>
  <li>Implement your client app, as described in this document. You can find the complete source
  code for the client app at the <a href="http://code.google.com/p/gcm">open source site</a>.</li>
  <li>Run one of the demo servers (Java or Python) provided in
<a href="ccs.html#implement">Implementing an XMPP-based App Server</a>. Whichever demo server you
 choose, don't forget to edit its code before running it to supply
your sender ID and API key.
</li>

</ol>

<h2 id="stats">Viewing Statistics</h2>

<p>To view  statistics and any error messages for your GCM applications:</p>
<ol>
  <li> Go to the <a href="http://play.google.com/apps/publish">Developer Console</a>.</li>
  <li>Login with your developer account.
  <p>You will see a page that has a list of all of your apps.</p></li>
  <li> Click on the &quot;statistics&quot; link next to the app for which you
want to view GCM stats.
  <p>Now you are on the statistics page.</p> </li>
  <li>Go to the drop-down menu and select the GCM metric you want to view.
  </li>
</ol>
<p class="note"><strong>Note:</strong> Stats on the Google API Console are not
enabled for GCM. You must use the <a href="http://play.google.com/apps/publish">Developer Console</a>.</p>