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—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—use 96 only if the app wants to keep the device from sleeping.</li> 97 <li>An <code>applicationPackage + ".permission.C2D_MESSAGE"</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—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—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="8"</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 <manifest package="com.example.gcm" ...> 131 132 <uses-sdk android:minSdkVersion="8" android:targetSdkVersion="17"/> 133 <uses-permission android:name="android.permission.INTERNET" /> 134 <uses-permission android:name="android.permission.GET_ACCOUNTS" /> 135 <uses-permission android:name="android.permission.WAKE_LOCK" /> 136 <uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" /> 137 138 <permission android:name="com.example.gcm.permission.C2D_MESSAGE" 139 android:protectionLevel="signature" /> 140 <uses-permission android:name="com.example.gcm.permission.C2D_MESSAGE" /> 141 142 <application ...> 143 <receiver 144 android:name=".GcmBroadcastReceiver" 145 android:permission="com.google.android.c2dm.permission.SEND" > 146 <intent-filter> 147 <action android:name="com.google.android.c2dm.intent.RECEIVE" /> 148 <category android:name="com.example.gcm" /> 149 </intent-filter> 150 </receiver> 151 <service android:name=".GcmIntentService" /> 152 </application> 153 154 </manifest> 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 @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 @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 @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 * <p> 314 * If result is empty, the app needs to register. 315 * 316 * @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 * @return Application's {@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 * @return Application's version code from the {@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 * <p> 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 @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 @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 * {@code SharedPreferences}. 441 * 442 * @param context application's context. 443 * @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 @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 @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 @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—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 @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 "statistics" 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