| 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">Send-to-sync messages</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> |