Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 57394e3d authored by kmccormick's avatar kmccormick Committed by Android Git Automerger
Browse files

am 2fbe1094: am 3ef445a8: am 68291f33: am db3158ea: Merge "Doc update:...

am 2fbe1094: am 3ef445a8: am 68291f33: am db3158ea: Merge "Doc update: Refactoring to client/server." into jb-mr1.1-docs

* commit '2fbe1094':
  Doc update: Refactoring to client/server.
parents 305cf97b 2fbe1094
Loading
Loading
Loading
Loading
+8 −62
Original line number Diff line number Diff line
@@ -23,7 +23,7 @@ page.title=GCM Cloud Connection Server
      <li><a href="#msg_examples">Message Examples</a></li>
    </ol>
  </li>
  <li><a href="#flow">Control Flow</a> </li>
  <li><a href="#flow">Flow Control</a> </li>
</ol>

<h2>See Also</h2>
@@ -48,6 +48,8 @@ page.title=GCM Cloud Connection Server

<p>The upstream messaging (device-to-cloud) feature of CCS is part of the Google Play services platform. Upstream messaging is available through the <a href="{@docRoot}reference/com/google/android/gms/gcm/GoogleCloudMessaging.html">{@code GoogleCloudMessaging}</a> APIs. To use upstream messaging and the new streamlined registration process, you must <a href="{@docRoot}google/play-services/setup.html">set up</a> the Google Play services SDK.</p>

<p class="note"><strong>Note:</strong> For an example of an XMPP server, see <a href="server.html#xmpp">GCM Server</a>.

<h2 id="gcm">CCS vs. GCM HTTP</h2>

<p>CCS messaging differs from GCM HTTP messaging in the following ways:</p>
@@ -229,69 +231,13 @@ gcm.send(GCM_SENDER_ID + "&#64;gcm.googleapis.com", id, ttl, data);
  &lt;/gcm&gt;
&lt;/message&gt;</pre>

<h4 id="python">Python Example</h4>
<p>This example illustrates how to connect,
send, and receive GCM messages using XMPP. It shouldn't be used as-is
on a production deployment.</p>

<pre>
import sys, json, xmpp
SERVER = ('gcm.googleapis.com', 5235)
#USERNAME = '&lt;your_numeric_project_id&gt;'
#PASSWORD = '&lt;your_gcm_api_key&gt;'

# Unique message id for downstream messages
sent_message_id = 0

def message_callback(session, message):
  global sent_message_id
  gcm = message.getTags('gcm')

  if gcm:
    gcm_json = gcm[0].getData()
    msg = json.loads(gcm_json)
    msg_id = msg['message_id']
    device_reg_id = msg['from']

    # Ignore non-standard messages (e.g. acks/nacks).
    if not msg.has_key('message_type'):
      # Acknowledge the incoming message.
      send({'to': device_reg_id,
            'message_type': 'ack',
            'message_id': msg_id})

      # Send a response back to the server.
      send({'to': device_reg_id,
            'message_id' : str(sent_message_id),
            'data': {'pong': 1}})
      sent_message_id = sent_message_id + 1
<h2 id="flow">Flow Control</h2>

def send(json_dict):
  template = (&quot;&lt;message from='{0}' to='gcm@google.com'&gt;&quot;
              &quot;&lt;gcm xmlns='google:mobile:data'&gt;{1}&lt;/gcm&gt;&lt;/message&gt;&quot;)
  client.send(xmpp.protocol.Message(
      node=template.format(client.Bind.bound[0],
                           json.dumps(json_dict))))
<p>Every message sent to CCS receives either an ACK or a NACK response. Messages that haven't received one of these responses are considered pending. If the pending message count reaches 1000, the 3rd-party server should stop sending new messages and wait for CCS to acknowledge some of the existing pending messages.</p>

client = xmpp.Client(SERVER[0], debug=['socket'])
client.connect(server=SERVER, secure=1, use_srv=False)
auth = client.auth(USERNAME, PASSWORD, 'test')
if not auth:
  print 'Authentication failed!'
  sys.exit(1)
<p>Conversely, to avoid overloading the 3rd-party server, CCS will stop sending if there are too many unacknowledged messages. Therefore, the 3rd-party server should "ACK" received messages as soon as possible to maintain a constant flow of incoming messages. The aforementioned pending message limit doesn't apply to these ACKs. Even if the pending message count reaches 1000, the 3rd-party server should continue sending ACKs to avoid blocking delivery of new messages.</p>

client.RegisterHandler('message', message_callback)

while True:
  client.Process(1)</pre>

<h2 id="flow">Control Flow</h2>

<p>Every message sent by a 3rd-party server to CCS receives either an ACK or a NACK response. A single connection can have at most 1000 messages that were sent without having yet received a response.</p>

<p>To enforce this policy, the app can maintain a counter of sent messages that increments on each send and decrements on each ACK or NACK. If the counter exceeds 1000, the app should stop sending messages until an ACK or NACK is received.</p>

<p>Conversely, when CCS sends messages to a 3rd-party server, it expects ACKs for each message it sends, and it will not send more than 1000 unacknowledged messages.</p>

<p>The ACKs and messages must match on each connection. You can only send an ACK for a message on the connection on which it was received.</p>
<p>ACKs are only valid within the context of one connection. If the connection is closed before a message can be ACKed, the 3rd-party server should wait for CCS to resend the message before ACKing it again.
</p>
+24 −0
Original line number Diff line number Diff line
page.title=GCM Client
page.tags="cloud","push","messaging"
@jd:body

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

<h2>See Also</h2>

<ol class="toc">
<li><a href="gs.html">Getting Started</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 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>

<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>

<p>

+16 −0
Original line number Diff line number Diff line
page.title=GCM Demo Application
@jd:body

<div id="deprecatedSticker">
  <a href="#" 
     onclick="$('#naMessage').show();$('#deprecatedSticker').hide();return false">
    <strong>This doc is deprecated</strong></a>
</div>


<div id="naMessage" style="display:block">
<div><p><strong>The information in this document has been superseded by <a href="server.html">GCM Server</a> and <a href="client.html">GCM Client</a></strong>. Please use the <a href="{@docRoot}reference/com/google/android/gms/gcm/GoogleCloudMessaging.html">{@code GoogleCloudMessaging}</a> API instead of the GCM client helper library. The GCM server helper library is still valid.</p>

 <input style="margin-top:1em;padding:5px" type="button"
        value="That's nice, but I still want to read this document"
onclick="$('#naMessage').hide();$('#deprecatedSticker').show()" />
</div>
</div>

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

+0 −347
Original line number Diff line number Diff line
@@ -28,20 +28,6 @@ page.title=GCM Architectural Overview
      <li><a href="#user">What Does the User See?</a></li>
    </ol>
  </li>
  <li><a href="#writing_apps">Writing Android Applications that use GCM</a>
    <ol>
    <li><a href="#manifest">Creating the Manifest</a></li>
    <li><a href="#registering">Registering for GCM</a></li>

    <li><a href="#handling_intents">Handling Intents Sent by GCM</a>
      <ol>
        <li><a href="#handling_reg">Handling Registration Results</a></li>
        <li><a href="#received_data">Handling Received Data</a></li>
      </ol>
    </li>
    <li><a href="#testing">Developing and Testing Your Android Applications</a></li>
    </ol>
  </li>
  <li><a href="#server">Role of  the 3rd-party Application Server</a>
    <ol class="toc">
      <li><a href="#send-msg">Sending Messages</a>
@@ -53,7 +39,6 @@ page.title=GCM Architectural Overview
    </ol>
    <li><a href="#stats">Viewing Statistics</a>
  </li>
  <li><a href="#example">Examples</a></li>
</ol>


@@ -306,336 +291,6 @@ from the <code>com.google.android.c2dm.intent.RECEIVE</code><code> </code>Intent
includes GCM. They must approve the use of this feature to install the
Android application. </p>

<h2 id="writing_apps">Writing Android Applications that Use GCM</h2>

<p>To write Android applications that use GCM, you must have an application
server that can perform the tasks described in <a href="#server">Role of the
3rd-party Application Server</a>. This section describes the steps you take to
create a client application that uses GCM.</p>

<p>Remember that there is no user interface associated with  GCM.
However you choose to process messages in your Android application is up to you.</p>

<p>There are two primary steps involved in writing a client Android application:</p>

<ul>
  <li>Creating a manifest that contains the permissions the Android application needs to
use GCM.</li>
  <li>Implementing your  code. To use GCM, this implementation must
include:
    <ul>
      <li>Code to start and stop the registration service.</li>
      <li>Receivers for the <code>com.google.android.c2dm.intent.RECEIVE</code> and <code>com.google.android.c2dm.intent.REGISTRATION</code> intents.</li>
    </ul>
  </li>
</ul>

<p class="note"><strong>Note:</strong> This section describes how to
write an app without using the 
<a href="{@docRoot}reference/com/google/android/gcm/package-summary.html">helper libraries</a>. 
For details on writing
an app that uses the helper libraries (which is the recommended and
simpler approach), see <a href="gs.html">GCM: Getting Started</a>.

<h3 id="manifest">Creating the Manifest</h3>

<p>To use the GCM feature, the
<code>AndroidManifest.xml</code> file must include the following:</p>

<ul>
  <li>The <code>com.google.android.c2dm.permission.RECEIVE</code> permission so the Android application can register and receive messages.</li>
  <li>The <code>android.permission.INTERNET</code> permission so the Android application can send the registration ID to the 3rd-party server.</li>
  <li>The <code>android.permission.GET_ACCOUNTS</code> permission as GCM requires a Google account (necessary only if if the device is running a version lower than Android 4.0.4)</li>
  <li>The <code>android.permission.WAKE_LOCK</code> permission so the application can keep the processor from sleeping when a message is received. Optional&mdash;use only if the app wants to keep the device from sleeping.</li>
  <li>An <code>applicationPackage + &quot;.permission.C2D_MESSAGE</code> permission to prevent other Android applications from registering and receiving the Android application's
messages. The permission name must exactly match this pattern&mdash;otherwise the Android application will not receive the messages.</li>
   <li>A receiver for <code>com.google.android.c2dm.intent.RECEIVE</code> and <code>com.google.android.c2dm.intent.REGISTRATION</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. Note that both registration and the receiving
of messages are implemented as <a href="{@docRoot}guide/components/intents-filters.html">Intents</a>.</li>
  <li>An intent service to handle the intents received by the broadcast receiver. Optional.</li>
  <li>If the GCM feature is critical to the Android application's function, be sure to
set <code>android:minSdkVersion=&quot;8&quot;</code> 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 manifest that supports GCM:</p>

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

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

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

    &lt;application ...&gt;
        &lt;receiver
            android:name=".MyBroadcastReceiver"
            android:permission="com.google.android.c2dm.permission.SEND" &gt;
            &lt;intent-filter&gt;
                &lt;action android:name="com.google.android.c2dm.intent.RECEIVE" /&gt;
                &lt;action android:name="com.google.android.c2dm.intent.REGISTRATION" /&gt;
                &lt;category android:name="com.example.gcm" /&gt;
            &lt;/intent-filter&gt;
        &lt;/receiver&gt;
        &lt;service android:name=".MyIntentService" /&gt;
    &lt;/application&gt;

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

<h3 id="registering">Registering for GCM</h3>

<div class="sidebox-wrapper">
<div class="sidebox">
  <h2>Streamlined Registration</h2>
  <p>There is now a simpler alternative to registering and unregistering. Simply call the <a href="{@docRoot}reference/com/google/android/gms/gcm/GoogleCloudMessaging.html">{@code GoogleCloudMessaging}</a> method
<a href="{@docRoot}reference/com/google/android/gms/gcm/GoogleCloudMessaging.html#register">{@code register(senderID...)}</a>.
This method registers the application for GCM and returns the registration ID. To unregister, call the
<a href="{@docRoot}reference/com/google/android/gms/gcm/GoogleCloudMessaging.html#unregister">{@code unregister()}</a> method (though you should rarely if ever need to unregister).</p>
</div>
</div>

<p>An Android application needs to register with GCM servers before it can receive messages. To register, the application sends an Intent
(<code>com.google.android.c2dm.intent.REGISTER</code>), with 2 extra parameters:
</p>

<ul>
  <li><code>sender</code> is the project number of the account authorized to send messages
to the Android application. </li>
  <li><code>app</code> is the Android application's ID, set with a <code>PendingIntent</code> to
allow the registration service to extract Android application information. </li>
</ul>

<p>For example:</p>

<pre style="clear:right">Intent registrationIntent = new Intent(&quot;com.google.android.c2dm.intent.REGISTER&quot;);
// sets the app name in the intent
registrationIntent.putExtra(&quot;app&quot;, PendingIntent.getBroadcast(this, 0, new Intent(), 0));
registrationIntent.putExtra(&quot;sender&quot;, senderID);
startService(registrationIntent);</pre>

<p>This intent will be asynchronously sent to the GCM server, and the response will be delivered to
the application as a <code>com.google.android.c2dm.intent.REGISTRATION</code> intent containing
the registration ID assigned to the Android application running on that particular device.</p>

<p>Registration is not complete until the Android application sends the registration ID
to the 3rd-party application server, which in turn will use the registration ID to send
messages to the application.</p>

<h3 id="unregistering">Unregistering from GCM</h3>

<p>To unregister from GCM, do the following:</p>

<pre class="prettyprint pretty-java">Intent unregIntent = new Intent(&quot;com.google.android.c2dm.intent.UNREGISTER&quot;);
unregIntent.putExtra(&quot;app&quot;, PendingIntent.getBroadcast(this, 0, new Intent(), 0));
startService(unregIntent);
</pre>

<p>Similar to the registration request, this intent is sent asynchronously, and the response comes as a <code>com.google.android.c2dm.intent.REGISTRATION</code> intent.


<h3 id="handling_intents">Handling Intents sent by GCM</h3>

<p>As discussed in <a href="#manifest">Creating the Manifest</a>, the manifest
defines a broadcast receiver for the <code>com.google.android.c2dm.intent.REGISTRATION</code> and <code>com.google.android.c2dm.intent.RECEIVE</code> intents.
These <a href="{@docRoot}guide/components/intents-filters.html">intents</a> are sent by GCM to indicate that a device was registered (or unregistered), or to deliver messages, respectively.</p>

<p>Handling these intents might require I/O operations (such as network calls to the 3rd-party server), and
such operations should not be done in the receiver's <code>onReceive()</code> method.
You may be tempted to spawn a new thread directly, but there are no guarantees that the process will run long enough for the thread to finish the work.
Thus the recommended way to handle the intents is to delegate them to a service, such as an {@link android.app.IntentService}.
For example:</p>


<pre class="prettyprint pretty-java">
public class MyBroadcastReceiver extends BroadcastReceiver {

    &#64;Override
    public final void onReceive(Context context, Intent intent) {
        MyIntentService.runIntentInService(context, intent);
        setResult(Activity.RESULT_OK, null, null);
    }
}
</pre>

<p>Then in <code>MyIntentService</code>:</p>
<pre class="prettyprint pretty-java">
public class MyIntentService extends IntentService {

    private static PowerManager.WakeLock sWakeLock;
    private static final Object LOCK = MyIntentService.class;
    
    static void runIntentInService(Context context, Intent intent) {
        synchronized(LOCK) {
            if (sWakeLock == null) {
                PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
                sWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "my_wakelock");
            }
        }
        sWakeLock.acquire();
        intent.setClassName(context, MyIntentService.class.getName());
        context.startService(intent);
    }
    
    &#64;Override
    public final void onHandleIntent(Intent intent) {
        try {
            String action = intent.getAction();
            if (action.equals("com.google.android.c2dm.intent.REGISTRATION")) {
                handleRegistration(intent);
            } else if (action.equals("com.google.android.c2dm.intent.RECEIVE")) {
                handleMessage(intent);
            }
        } finally {
            synchronized(LOCK) {
                sWakeLock.release();
            }
        }
    }
}
</pre>

<p class="note"><strong>Note:</strong> your application must acquire a wake lock before starting the service&mdash;otherwise the device could be put to sleep before the service is started.</p>

<h4 id="handling_reg">Handling Registration Results</h4>

<p>When a <code>com.google.android.c2dm.intent.REGISTRATION</code> intent is received, it could potentially contain 3 extras: <code>registration_id</code>, <code>error</code>, and <code>unregistered</code>.

<p>When a registration succeeds, <code>registration_id</code> contains the registration ID and the other extras are not set.
The application must ensure that the 3rd-party server receives the registration ID. It may do so by saving the registration ID and sending it to the server.
If the network is down or there are errors, the application should retry sending the registration ID when the network is up again or the next time it starts.</p>

<p class="note"><strong>Note:</strong> Although the <code>com.google.android.c2dm.intent.REGISTRATION</code> intent is typically received after a request was made by the application, 
Google may periodically refresh the registration ID. So the application must be prepared to handle it at any time.</p>

<p>When an unregistration succeeds, only the <code>unregistered</code> extra is set, and similar to the registration workflow,
the application must contact the 3rd-party server to remove the registration ID (note that the registration ID is not available in the intent,
but the application should have saved the registration ID when it got it).<p>

<p>If the application request (be it register or unregister) fails, the <code>error</code> will be set with an error code, and the other extras will not be set.

Here are the possible error codes:</p>

<table>
  <tr>
    <th>Error Code</th>
    <th>Description</th>
  </tr>
  <tr>
    <td><code>SERVICE_NOT_AVAILABLE</code></td>
    <td>The device can't read the response, or there was a 500/503 from the
server that can be retried later. The Android application should use exponential back-off and retry. See <a href="adv.html#retry">Advanced Topics</a> for more information. </td>
  </tr>
  <tr>
    <td><code>ACCOUNT_MISSING</code></td>
    <td>There is no Google account on the phone.  The Android application should ask the
user to open the account manager and add a Google account. Fix on the device
side.</td>
  </tr>
  <tr>
    <td><code>AUTHENTICATION_FAILED</code></td>
    <td>Bad Google Account password. The Android application should ask the user to enter his/her Google Account
password, and let the user retry manually later. Fix on the device side.</td>
  </tr>
  <tr>
    <td><code>INVALID_SENDER</code></td>
    <td>The sender account is not recognized. This must be fixed on the Android application side. The developer must fix the application to provide the right <code>sender</code> extra in the <code>com.google.android.c2dm.intent.REGISTER</code> intent.</td>
  </tr>
  <tr>
    <td><code>PHONE_REGISTRATION_ERROR</code></td>
    <td> Incorrect phone registration with Google. This
phone doesn't currently support GCM.</td>
  </tr>
  <tr>
    <td><code>INVALID_PARAMETERS</code></td>
    <td>The  request sent by the phone does not contain the expected parameters. This phone doesn't currently support GCM.</td>
  </tr>
</table>




<p>Here's an example on how to handle the registration in the <code>MyIntentService</code> example:</p>

<pre class="prettyprint pretty-java">
private void handleRegistration(Intent intent) {
    String registrationId = intent.getStringExtra("registration_id");
    String error = intent.getStringExtra("error");
    String unregistered = intent.getStringExtra("unregistered");
    // registration succeeded
    if (registrationId != null) {
        // store registration ID on shared preferences
        // notify 3rd-party server about the registered ID
    }
        
    // unregistration succeeded
    if (unregistered != null) {
        // get old registration ID from shared preferences
        // notify 3rd-party server about the unregistered ID
    } 
        
    // last operation (registration or unregistration) returned an error;
    if (error != null) {
        if ("SERVICE_NOT_AVAILABLE".equals(error)) {
           // optionally retry using exponential back-off
           // (see <a href="adv.html#retry">Advanced Topics</a>)
        } else {
            // Unrecoverable error, log it
            Log.i(TAG, "Received error: " + error);
        }
    }
}</pre>



<h4 id="received_data">Handling Received Data</h4>

<p>The <code>com.google.android.c2dm.intent.RECEIVE</code> intent is used by GCM to
deliver the messages sent by the 3rd-party server to the application running in the device.
If the server included key-pair values in the <code>data</code> parameter, they are available as
extras in this intent, with the keys being the extra names. GCM also includes an  extra called
<code>from</code> which contains the sender ID as an string, and another called <code>collapse_key</code> containing the collapse key (when in use).

<p>Here is an example, again using the <code>MyIntentReceiver</code> class:</p>

<pre class="prettyprint pretty-java">
private void handleMessage(Intent intent) {
    // server sent 2 key-value pairs, score and time
    String score = intent.getExtra("score");
    String time = intent.getExtra("time");
    // generates a system notification to display the score and time
}</pre>

<h3 id="testing">Developing and Testing Your Android Applications</h3>

<p>Here are some guidelines for developing and testing an Android application
that uses the GCM feature:</p>

<ul>
  <li>To develop and test your Android applications, you need to run and debug the
applications on an Android 2.2 system image that includes the necessary
underlying Google services. </li>
  <li>To develop and debug on an actual device, you need a device running an
Android 2.2 system image that includes the Google Play Store application. </li>
  <li>To develop and test on the Android Emulator, you need to download the
Android 2.2 version of the Google APIs Add-On into your SDK using the <em>Android
SDK and AVD Manager</em>. Specifically, you need to download the component named
&quot;Google APIs by Google Inc, Android API 8&quot;. Then, you need to set up
an AVD that uses that system image. </li>
  <li>If the GCM feature is critical to the Android application's function, be sure to
set <code>android:minSdkVersion=&quot;8&quot;</code> in the manifest. This
ensures that the Android application cannot be installed in an environment in which it
could not run properly. </li>
</ul>


<h2 id="server">Role of the 3rd-party Application Server</h2>

@@ -1104,6 +759,4 @@ registration_id=32
</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>

<h2 id="example">Examples</h2>
<p>See the <a href="demo.html">GCM Demo Application</a> document.</p>
+277 −87

File changed.

Preview size limit exceeded, changes collapsed.

Loading