Fixes for: b/11713745 b/11712882 b/10669388 b/10641901 Change-Id: I071eba31d51f0e29b9be4a7f7ede0f01c7a52838
410 lines
20 KiB
Plaintext
410 lines
20 KiB
Plaintext
page.title=GCM Advanced Topics
|
|
@jd:body
|
|
|
|
<div id="qv-wrapper">
|
|
<div id="qv">
|
|
|
|
<h2>Quickview</h2>
|
|
|
|
<ul>
|
|
<li>Learn more about GCM advanced features.</li>
|
|
</ul>
|
|
|
|
|
|
<h2>In this document</h2>
|
|
|
|
<ol>
|
|
<li><a href="#lifetime">Lifetime of a Message</a></li>
|
|
<li><a href="#throttling">Throttling</a></li>
|
|
<li><a href="#reg-state">Keeping the Registration State in Sync</a>
|
|
<ol>
|
|
<li><a href="#canonical">Canonical IDs</a></li>
|
|
</ol>
|
|
</li>
|
|
<li><a href="#retry">Automatic Retry Using Exponential Back-Off</a></li>
|
|
<li><a href="#unreg">Unregistration</a>
|
|
<ol>
|
|
<li><a href="#unreg-why">Why you should rarely unregister</a></li>
|
|
<li><a href="#unreg-how">How unregistration works</a></li>
|
|
</ol>
|
|
</li>
|
|
<li><a href="#collapsible">Send-to-Sync vs. Messages with Payload</a>
|
|
<ol>
|
|
<li><a href="#s2s">Send-to-sync messages</a></li>
|
|
<li><a href="#payload">Messages with payload</a></li>
|
|
<li><a href="#which">Which should I use?</a></li>
|
|
</ol>
|
|
</li>
|
|
<li><a href="#ttl">Setting an Expiration Date for a Message</a> </li>
|
|
<li><a href="#throttling"></a><a href="#multi-senders">Receiving Messages from
|
|
Multiple Senders</a></li>
|
|
</ol>
|
|
|
|
</div>
|
|
</div>
|
|
<p>This document covers advanced topics for GCM.</p>
|
|
|
|
|
|
|
|
|
|
<h2 id="msg-lifetime">Lifetime of a Message</h2>
|
|
<p>When a 3rd-party server posts a message to GCM and receives a message ID back,
|
|
it does not mean that the message was already delivered to the device. Rather, it
|
|
means that it was accepted for delivery. What happens to the message after it is
|
|
accepted depends on many factors.</p>
|
|
|
|
<p>In the best-case scenario, if the device is connected to GCM, the screen is on,
|
|
and there are no throttling restrictions (see <a href="#throttling">Throttling</a>),
|
|
the message will be delivered right away.</p>
|
|
|
|
<p>If the device is connected but idle, the message will still be
|
|
delivered right away unless the <code>delay_while_idle</code> flag is set to true.
|
|
Otherwise, it will be stored in the GCM servers until the device is awake. And
|
|
that's where the <code>collapse_key</code> flag plays a role: if there is already
|
|
a message with the same collapse key (and registration ID) stored and waiting for
|
|
delivery, the old message will be discarded and the new message will take its place
|
|
(that is, the old message will be collapsed by the new one). However, if the collapse
|
|
key is not set, both the new and old messages are stored for future delivery.
|
|
Collapsible messages are also called <a href="#s2s">send-to-sync messages</a>.</p>
|
|
|
|
<p class="note"><strong>Note:</strong> There is a limit on how many messages can
|
|
be stored without collapsing. That limit is currently 100. If the limit is reached,
|
|
all stored messages are discarded. Then when the device is back online, it receives
|
|
a special message indicating that the limit was reached. The application can then
|
|
handle the situation properly, typically by requesting a full sync.
|
|
<br><br>
|
|
Likewise, there is a limit on how many <code>collapse_key</code>s you can have for
|
|
a particular device. GCM allows a maximum of 4 different collapse keys to be used
|
|
by the GCM server per device
|
|
any given time. In other words, the GCM server can simultaneously store 4 different
|
|
send-to-sync messages, each with a different collapse key. If you exceed this number
|
|
GCM will only keep 4 collapse keys, with no guarantees about which ones they will be.
|
|
See <a href="#s2s">Send-to-sync messages</a> for more information.
|
|
</p>
|
|
|
|
<p>If the device is not connected to GCM, the message will be stored until a
|
|
connection is established (again respecting the collapse key rules). When a connection
|
|
is established, GCM will deliver all pending messages to the device, regardless of
|
|
the <code>delay_while_idle</code> flag. If the device never gets connected again
|
|
(for instance, if it was factory reset), the message will eventually time out and
|
|
be discarded from GCM storage. The default timeout is 4 weeks, unless the
|
|
<code>time_to_live</code> flag is set.</p>
|
|
|
|
<p>Finally, when GCM attempts to deliver a message to the device and the
|
|
application was uninstalled, GCM will discard that message right away and
|
|
invalidate the registration ID. Future attempts to send a message to that device
|
|
will get a <code>NotRegistered</code> error. See <a href="#unreg">
|
|
How Unregistration Works</a> for more information.</p>
|
|
<p>Although is not possible to track the status of each individual message, the
|
|
Google Cloud Console stats are broken down by messages sent to device, messages
|
|
collapsed, and messages waiting for delivery.</p>
|
|
|
|
<h2 id="throttling">Throttling</h2>
|
|
<p>To prevent abuse (such as sending a flood of messages to a device) and
|
|
to optimize for the overall network efficiency and battery life of
|
|
devices, GCM implements throttling of messages using a token bucket
|
|
scheme. Messages are throttled on a per application and per <a href="#collapsible">collapse
|
|
key</a> basis (including non-collapsible messages). Each application
|
|
collapse key is granted some initial tokens, and new tokens are granted
|
|
periodically therefter. Each token is valid for a single message sent to
|
|
the device. If an application collapse key exhausts its supply of
|
|
available tokens, new messages are buffered in a pending queue until
|
|
new tokens become available at the time of the periodic grant. Thus
|
|
throttling in between periodic grant intervals may add to the latency
|
|
of message delivery for an application collapse key that sends a large
|
|
number of messages within a short period of time. Messages in the pending
|
|
queue of an application collapse key may be delivered before the time
|
|
of the next periodic grant, if they are piggybacked with messages
|
|
belonging to a non-throttled category by GCM for network and battery
|
|
efficiency reasons.</p>
|
|
|
|
<h2 id="reg-state">Keeping the Registration State in Sync</h2>
|
|
<p>Whenever the application registers as described in
|
|
<a href="{@docRoot}google/gcm/client.html">Implementing GCM Client</a>,
|
|
it should save the registration ID for future use, pass it to the
|
|
3rd-party server to complete the registration, and keep track of
|
|
whether the server completed the registration. If the server fails
|
|
to complete the registration, it should try again or unregister from GCM.</p>
|
|
|
|
<p>There are also two other scenarios that require special care:</p>
|
|
<ul>
|
|
<li>Application update</li>
|
|
<li>Backup and restore
|
|
</li>
|
|
</ul>
|
|
<p>When an application is updated, it should invalidate its existing registration
|
|
ID, as it is not guaranteed to work with the new version. Because there is no
|
|
lifecycle method called when the application is updated, the best way to achieve
|
|
this validation is by storing the current application version when a registration
|
|
ID is stored. Then when the application is started, compare the stored value with
|
|
the current application version. If they do not match, invalidate the stored data
|
|
and start the registration process again.</p>
|
|
|
|
<p>Similarly, you should not save the registration ID when an application is
|
|
backed up. This is because the registration ID could become invalid by the time
|
|
the application is restored, which would put the application in an invalid state
|
|
(that is, the application thinks it is registered, but the server and GCM do not
|
|
store that registration ID anymore—thus the application will not get more
|
|
messages).</p>
|
|
<h3 id="canonical">Canonical IDs</h3>
|
|
<p>On the server side, as long as the application is behaving well, everything
|
|
should work normally. However, if a bug in the application triggers multiple
|
|
registrations for the same device, it can be hard to reconcile state and you might
|
|
end up with duplicate messages.</p>
|
|
<p>GCM provides a facility called "canonical registration IDs" to easily
|
|
recover from these situations. A canonical registration ID is defined to be the ID
|
|
of the last registration requested by your application. This is the ID that the
|
|
server should use when sending messages to the device.</p>
|
|
<p>If later on you try to send a message using a different registration ID, GCM
|
|
will process the request as usual, but it will include the canonical registration
|
|
ID in the <code>registration_id</code> field of the response. Make sure to replace
|
|
the registration ID stored in your server with this canonical ID, as eventually
|
|
the ID you're using will stop working.</p>
|
|
|
|
<h2 id="retry">Automatic Retry Using Exponential Back-Off</h2>
|
|
|
|
<p>When registration or unregistration fails, the app should retry the failed operation.</p>
|
|
<p>In the simplest case, if your application attempts to register and GCM is not a
|
|
fundamental part of the application, the application could simply ignore the error
|
|
and try to register again the next time it starts. Otherwise, it should retry the
|
|
previous operation using exponential back-off. In exponential back-off, each time
|
|
there is a failure, it should wait twice the previous amount of time before trying
|
|
again. If the register (or unregister) operation was synchronous, it could be retried
|
|
in a simple loop. However, since it is asynchronous, the best approach is to schedule
|
|
a {@link android.app.PendingIntent} to retry the operation.
|
|
|
|
<h2 id="unreg">Unregistration</h2>
|
|
|
|
<p>This section explains when you should unregister in GCM and what happens
|
|
when you do.</p>
|
|
|
|
<h3 id="unreg-why">Why you should rarely unregister</h3>
|
|
|
|
<p>A registration ID (regID) represents a particular Android application running
|
|
on a particular device. You should only need to unregister in rare cases, such as
|
|
if you want an app to stop receiving messages, or if you suspect that the regID has
|
|
been compromised. In general, though, once an app has a regID, you shouldn't need
|
|
to change it.</p>
|
|
|
|
<p>In particular, you should never unregister your app as a mechanism for
|
|
logout or for switching between users, for the following reasons:</p>
|
|
|
|
<ul>
|
|
<li>A regID maps an app to a device. It isn't associated with a particular
|
|
logged in user. If you unregister and then re-register, GCM may return the same
|
|
ID or a different ID—there's no guarantee either way.</li>
|
|
|
|
<li>Unregistration may take up to 5 minutes to propagate.</li>
|
|
<li>After unregistration, re-registration may again take up to 5 minutes to
|
|
propagate. During this time messages may be rejected due to the state of being
|
|
unregistered, and after all this, messages may still go to the wrong user.</li>
|
|
</ul>
|
|
|
|
|
|
<p>The solution is to manage your own mapping between users, the regID, and
|
|
individual messages:</p>
|
|
|
|
<ul>
|
|
<li>Your app server should maintain a mapping between the current user
|
|
and the regID. This should include information about which user is supposed to
|
|
receive a particular message.</li>
|
|
<li>The app running on the device should check to ensure that messages it
|
|
receives match the logged in user.</li>
|
|
</ul>
|
|
|
|
|
|
<h3 id="unreg-how">How unregistration works</h3>
|
|
|
|
<p>An application can be automatically unregistered after it is uninstalled from
|
|
the device. However, this process does not happens right away, as Android does not
|
|
provide an uninstall callback. What happens in this scenario is as follows:</p>
|
|
<ol>
|
|
<li>The end user uninstalls the application.</li>
|
|
<li>The 3rd-party server sends a message to GCM server.</li>
|
|
<li>The GCM server sends the message to the device.</li>
|
|
<li>The GCM client receives the message and queries Package Manager about
|
|
whether there are broadcast receivers configured to receive it, which returns
|
|
<code>false</code>.
|
|
</li>
|
|
<li>The GCM client informs the GCM server that the application was uninstalled.</li>
|
|
<li>The GCM server marks the registration ID for deletion.</li>
|
|
<li>The 3rd-party server sends a message to GCM.</li>
|
|
<li>The GCM returns a <code>NotRegistered</code> error message to the 3rd-party server.</li>
|
|
<li>The 3rd-party deletes the registration ID.
|
|
</li>
|
|
</ol>
|
|
|
|
<p class ="note"><strong>Note:</strong> The GCM client is the Google Cloud
|
|
Messaging framework present on the device.</p>
|
|
|
|
<p>Note that it might take a while for the registration ID be completely removed
|
|
from GCM. Thus it is possible that messages sent during step 7 above gets a valid
|
|
message ID as response, even though the message will not be delivered to the device.
|
|
Eventually, the registration ID will be removed and the server will get a
|
|
<code>NotRegistered</code> error, without any further action being required from
|
|
the 3rd-party server (this scenario happens frequently while an application is
|
|
being developed and tested).</p>
|
|
|
|
<h2 id="collapsible">Send-to-Sync vs. Messages with Payload</h2>
|
|
|
|
<p>Every message sent in GCM has the following characteristics:</p>
|
|
<ul>
|
|
<li>It has a payload limit of 4096 bytes.</li>
|
|
<li>By default, it is stored by GCM for 4 weeks.</li>
|
|
</ul>
|
|
|
|
<p>But despite these similarities, messages can behave very differently depending
|
|
on their particular settings. One major distinction between messages is whether
|
|
they are collapsed (where each new message replaces the preceding message) or not
|
|
collapsed (where each individual message is delivered). Every message sent in GCM
|
|
is either a "send-to-sync" (collapsible) message or a "message with
|
|
payload" (non-collapsible message). These concepts are described in more
|
|
detail in the following sections.</p>
|
|
|
|
<h3 id="s2s"><strong>Send-to-sync messages</strong></h3>
|
|
|
|
<p>A send-to-sync (collapsible) message is often a "tickle" that tells
|
|
a mobile application to sync data from the server. For example, suppose you have
|
|
an email application. When a user receives new email on the server, the server
|
|
pings the mobile application with a "New mail" message. This tells the
|
|
application to sync to the server to pick up the new email. The server might send
|
|
this message multiple times as new mail continues to accumulate, before the application
|
|
has had a chance to sync. But if the user has received 25 new emails, there's no
|
|
need to preserve every "New mail" message. One is sufficient. Another
|
|
example would be a sports application that updates users with the latest score.
|
|
Only the most recent message is relevant, so it makes sense to have each new
|
|
message replace the preceding message. </p>
|
|
|
|
<p>The email and sports applications are cases where you would probably use the
|
|
GCM <code>collapse_key</code> parameter. A <em>collapse key</em> is an arbitrary
|
|
string that is used to collapse a group of like messages when the device is offline,
|
|
so that only the most recent message gets sent to the client. For example,
|
|
"New mail," "Updates available," and so on</p>
|
|
<p>GCM allows a maximum of 4 different collapse keys to be used by the GCM server
|
|
at any given time. In other words, the GCM server can simultaneously store 4
|
|
different send-to-sync messages per device, each with a different collapse key.
|
|
For example, Device A can have A1, A2, A3, and A4. Device B can have B1, B2, B3,
|
|
and B4, and so on. If you exceed this number GCM will only keep 4 collapse keys, with no
|
|
guarantees about which ones they will be.</p>
|
|
|
|
<h3 id="payload">Messages with payload</h3>
|
|
<p>Unlike a send-to-sync message, every "message with payload"
|
|
(non-collapsible message) is delivered. The payload the message contains can be
|
|
up to 4kb. For example, here is a JSON-formatted message in an IM application in
|
|
which spectators are discussing a sporting event:</p>
|
|
|
|
<pre class="prettyprint pretty-json">{
|
|
"registration_id" : "APA91bHun4MxP5egoKMwt2KZFBaFUH-1RYqx...",
|
|
"data" : {
|
|
"Nick" : "Mario",
|
|
"Text" : "great match!",
|
|
"Room" : "PortugalVSDenmark",
|
|
},
|
|
}</pre>
|
|
|
|
<p>A "message with payload" is not simply a "ping" to the
|
|
mobile application to contact the server to fetch data. In the aforementioned IM
|
|
application, for example, you would want to deliver every message, because every
|
|
message has different content. To specify a non-collapsible message, you simply
|
|
omit the <code>collapse_key</code> parameter. Thus GCM will send each message
|
|
individually. Note that the order of delivery is not guaranteed.</p>
|
|
|
|
<p>GCM will store up to 100 non-collapsible messages. After that, all messages
|
|
are discarded from GCM, and a new message is created that tells the client how
|
|
far behind it is. The message is delivered through a regular
|
|
<code>com.google.android.c2dm.intent.RECEIVE</code> intent with the
|
|
extra <code>message_type</code>, for which the value is always the string
|
|
"deleted_messages".</p>
|
|
|
|
<p>The application should respond by syncing with the server to recover the
|
|
discarded messages. </p>
|
|
|
|
<h3 id="which">Which should I use?</h3>
|
|
<p>If your application does not need to use non-collapsible messages, collapsible
|
|
messages are a better choice from a performance standpoint, because they put less
|
|
of a burden on the device battery. However, if you use collapsible messages, remember that
|
|
<strong>GCM only allows a maximum of 4 different collapse keys to be used by the GCM server
|
|
per device at any given time</strong>. You must not exceed this number, or it could cause
|
|
unpredictable consequences.</p>
|
|
|
|
<h2 dir="ltr" id="ttl">Setting an Expiration Date for a Message</h2>
|
|
<p>The Time to Live (TTL) feature lets the sender specify the maximum lifespan
|
|
of a message using the <code>time_to_live</code> parameter in the send request.
|
|
The value of this parameter must be a duration from 0 to 2,419,200 seconds, and
|
|
it corresponds to the maximum period of time for which GCM will store and try to
|
|
deliver the message. Requests that don't contain this field default to the maximum
|
|
period of 4 weeks.</p>
|
|
<p>Here are some possible uses for this feature:</p>
|
|
<ul>
|
|
<li>Video chat incoming calls</li>
|
|
<li>Expiring invitation events</li>
|
|
<li>Calendar events</li>
|
|
</ul>
|
|
<h3 id="bg">Background </h3>
|
|
<p>GCM will usually deliver messages immediately after they are sent. However,
|
|
this might not always be possible. For example, the device could be turned off,
|
|
offline, or otherwise unavailable. In other cases, the sender itself might request
|
|
that messages not be delivered until the device becomes active by using the
|
|
<code>delay_while_idle</code> flag. Finally, GCM might intentionally delay messages
|
|
to prevent an application from consuming excessive resources and negatively
|
|
impacting battery life.</p>
|
|
|
|
<p>When this happens, GCM will store the message and deliver it as soon as it's
|
|
feasible. While this is fine in most cases, there are some applications for which
|
|
a late message might as well never be delivered. For example, if the message is
|
|
an incoming call or video chat notification, it will only be meaningful for a
|
|
small period of time before the call is terminated. Or if the message is an
|
|
invitation to an event, it will be useless if received after the event has ended.</p>
|
|
|
|
<p>Another advantage of specifying the expiration date for a message is that GCM
|
|
will never throttle messages with a <code>time_to_live</code> value of 0 seconds.
|
|
In other words, GCM will guarantee best effort for messages that must be delivered
|
|
"now or never." Keep in mind that a <code>time_to_live</code> value of
|
|
0 means messages that can't be delivered immediately will be discarded. However,
|
|
because such messages are never stored, this provides the best latency for
|
|
sending notifications.</p>
|
|
|
|
<p>Here is an example of a JSON-formatted request that includes TTL:</p>
|
|
<pre class="prettyprint pretty-json">
|
|
{
|
|
"collapse_key" : "demo",
|
|
"delay_while_idle" : true,
|
|
"registration_ids" : ["xyz"],
|
|
"data" : {
|
|
"key1" : "value1",
|
|
"key2" : "value2",
|
|
},
|
|
"time_to_live" : 3
|
|
},
|
|
</pre>
|
|
|
|
|
|
<h2 id="multi-senders">Receiving Messages from Multiple Senders</h2>
|
|
|
|
<p>GCM allows multiple parties to send messages to the same application. For
|
|
example, suppose your application is an articles aggregator with multiple
|
|
contributors, and you want each of them to be able to send a message when they
|
|
publish a new article. This message might contain a URL so that the application
|
|
can download the article. Instead of having to centralize all sending activity in
|
|
one location, GCM gives you the ability to let each of these contributors send
|
|
its own messages.</p>
|
|
|
|
<p>To make this possible, all you need to do is have each sender generate its own
|
|
project number. Then include those IDs in the sender field, separated by commas,
|
|
when requesting a registration. Finally, share the registration ID with your
|
|
partners, and they'll be able to send messages to your application using their
|
|
own authentication keys.</p>
|
|
<p>This code snippet illustrates this feature. Senders are passed as an intent
|
|
extra in a comma-separated list:</p>
|
|
|
|
<pre class="prettyprint pretty-java">Intent intent = new Intent(GCMConstants.INTENT_TO_GCM_REGISTRATION);
|
|
intent.setPackage(GSF_PACKAGE);
|
|
intent.putExtra(GCMConstants.EXTRA_APPLICATION_PENDING_INTENT,
|
|
PendingIntent.getBroadcast(context, 0, new Intent(), 0));
|
|
String senderIds = "968350041068,652183961211";
|
|
intent.putExtra(GCMConstants.EXTRA_SENDER, senderIds);
|
|
ontext.startService(intent);
|
|
</pre>
|
|
|
|
<p>Note that there is limit of 100 multiple senders.</p>
|