2013-07-23 18:12:38 -07:00
|
|
|
page.title=Implementing GCM Client
|
2013-05-30 19:06:41 -07:00
|
|
|
page.tags="cloud","push","messaging"
|
|
|
|
@jd:body
|
|
|
|
|
|
|
|
<div id="qv-wrapper">
|
|
|
|
<div id="qv">
|
|
|
|
|
2013-07-23 18:12:38 -07:00
|
|
|
|
|
|
|
<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>
|
|
|
|
|
2013-05-30 19:06:41 -07:00
|
|
|
<h2>See Also</h2>
|
|
|
|
|
|
|
|
<ol class="toc">
|
|
|
|
<li><a href="gs.html">Getting Started</a></li>
|
2013-07-23 18:12:38 -07:00
|
|
|
<li><a href="server.html">Implementing GCM Server</a></li>
|
2013-05-30 19:06:41 -07:00
|
|
|
</ol>
|
|
|
|
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
|
2013-07-23 18:12:38 -07:00
|
|
|
<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);
|
2013-05-30 19:06:41 -07:00
|
|
|
|
2013-07-23 18:12:38 -07:00
|
|
|
setContentView(R.layout.main);
|
|
|
|
mDisplay = (TextView) findViewById(R.id.display);
|
2013-05-30 19:06:41 -07:00
|
|
|
|
2013-07-23 18:12:38 -07:00
|
|
|
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>
|
2013-05-30 19:06:41 -07:00
|
|
|
|
|
|
|
|