diff options
Diffstat (limited to 'docs/html/google/gcm/client.jd')
-rw-r--r-- | docs/html/google/gcm/client.jd | 649 |
1 files changed, 5 insertions, 644 deletions
diff --git a/docs/html/google/gcm/client.jd b/docs/html/google/gcm/client.jd index df357a2..7604932 100644 --- a/docs/html/google/gcm/client.jd +++ b/docs/html/google/gcm/client.jd @@ -1,663 +1,24 @@ -page.title=Implementing GCM Client +page.title=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> +<li><a href="server.html">GCM Server</a></li> </ol> </div> </div> -<p>A 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/GoogleCloudMessaging.html"> -{@code GoogleCloudMessaging}</a> APIs. -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/GoogleCloudMessaging.html"> -{@code GoogleCloudMessaging}</a> APIs.</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/GoogleCloudMessaging.html"> -{@code GoogleCloudMessaging}</a> API. -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—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—use -only if the app wants to keep the device from sleeping.</li> - <li>An <code>applicationPackage + ".permission.C2D_MESSAGE"</code> -permission to prevent other Android applications from registering and receiving -the Android application's messages. The permission name must exactly match this -pattern—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—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="8"</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"> -<manifest package="com.example.gcm" ...> - - <uses-sdk android:minSdkVersion="8" android:targetSdkVersion="17"/> - <uses-permission android:name="android.permission.INTERNET" /> - <uses-permission android:name="android.permission.GET_ACCOUNTS" /> - <uses-permission android:name="android.permission.WAKE_LOCK" /> - <uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" /> - - <permission android:name="com.example.gcm.permission.C2D_MESSAGE" - android:protectionLevel="signature" /> - <uses-permission android:name="com.example.gcm.permission.C2D_MESSAGE" /> - - <application ...> - <receiver - android:name=".GcmBroadcastReceiver" - android:permission="com.google.android.c2dm.permission.SEND" > - <intent-filter> - <action android:name="com.google.android.c2dm.intent.RECEIVE" /> - <category android:name="com.example.gcm" /> - </intent-filter> - </receiver> - <service android:name=".GcmIntentService" /> - </application> - -</manifest> -</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> APIs. 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; -... -@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. -@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. 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; - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); +<p>A GCM client is a GCM-enabled app that runs on an Android device. To write your client code, we recommend that you use the new <a href="{@docRoot}reference/com/google/android/gms/gcm/GoogleCloudMessaging.html">{@code GoogleCloudMessaging}</a> APIs. 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/GoogleCloudMessaging.html">{@code GoogleCloudMessaging}</a> APIs.</p> - setContentView(R.layout.main); - mDisplay = (TextView) findViewById(R.id.display); +<p>A full GCM implementation requires both a client implementation and a server-side implementation. For a step-by-step guide to creating a complete sample implementation that includes both client and server, see <a href="gs.html">Getting Started</a>. </p> - 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. - * <p> - * If result is empty, the app needs to register. - * - * @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; -} -... -/** - * @return Application's {@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>/** - * @return Application's version code from the {@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. - * <p> - * Stores the registration ID and app versionCode in the application's - * shared preferences. - */ -private void registerInBackground() { - new AsyncTask<Void, Void, String>() { - @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; - } - - @Override - protected void onPostExecute(String msg) { - mDisplay.append(msg + "\n"); - } - }.execute(null, null, null); - ... - /** - * 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 - * {@code SharedPreferences}. - * - * @param context application's context. - * @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> - -<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> APIs. 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>() { - @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; - } - - @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 { - @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—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"); - } - - @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 <code><a href="http://play.google.com/apps/publish">Developer Console</a></code>.</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 "statistics" 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> +<p> |