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