Home | History | Annotate | Download | only in gcm
      1 page.title=Getting Started with GCM
      2 page.tags="cloud","push","messaging"
      3 @jd:body
      4 
      5 <div id="qv-wrapper">
      6 <div id="qv">
      7 
      8 
      9 <h2>In this document</h2>
     10 
     11 <ol class="toc">
     12 <li><a href="#create-proj">Creating a Google API Project</a></li>
     13 <li><a href="#gcm-service">Enabling the GCM Service</a></li>
     14 <li><a href="#access-key">Obtaining an API Key</a></li>
     15 <li><a href="#client">Writing a Client App</a></li>
     16 <li><a href="#server">Writing the Server Code</a></li>
     17 </ol>
     18 
     19 <h2>See Also</h2>
     20 
     21 <ol class="toc">
     22 <li><a href="https://code.google.com/apis/console">Google APIs Console page</a></li>
     23 <li><a href="https://services.google.com/fb/forms/gcm/" class="external-link" target="_android">CCS and User Notifications Signup Form</a></li>
     24 </ol>
     25 
     26 </div>
     27 </div>
     28 
     29 <p>The sections below guide you through the process of setting up a GCM
     30 implementation.
     31 Before you start, make sure to <a href="/google/play-services/setup.html">set up
     32 the Google Play Services SDK</a>. You need this SDK to use the <a href="{@docRoot}reference/com/google/android/gms/gcm/GoogleCloudMessaging.html">{@code GoogleCloudMessaging}</a> methods.</p>
     33 
     34 <p>Note that a full GCM implementation requires a server-side implementation, in addition to the client implementation in your app. This document offers a complete example that includes both the client and server.</p>
     35 
     36 
     37 <h2 id="create-proj">Creating a Google API project</h2>
     38 <p>To create a Google API project:</p>
     39 <ol>
     40   <li>Open the <a href="https://code.google.com/apis/console">Google APIs Console page</a>.
     41   </li>
     42   <li>If you haven't created an API project yet, this page will prompt you to do so:
     43   <p><img src="{@docRoot}images/gcm/gcm-create-api-proj.png" class="screenshot" /></p>
     44 <p class="note"><strong>Note:</strong> If you already have existing projects, the first page you see will be the <strong>Dashboard</strong> page. From there you can create a new project by opening the project drop-down menu (upper left corner) and choosing <strong>Other projects > Create</strong>.</p></li>
     45   <li> Click <strong>Create project</strong>.
     46     Your browser URL will change to something like:</li>
     47 
     48 <pre> https://code.google.com/apis/console/#project:<strong>4815162342</strong></pre>
     49 
     50   <li> Take note of the value after <code>#project:</code> (4815162342 in this example). This is your project number, and it will be used later on as the GCM sender ID.</li>
     51   
     52 </ol>
     53 <h2 id="gcm-service">Enabling the GCM Service</h2>
     54 <p>To enable the GCM service:</p>
     55 <ol>
     56   <li> In the main Google APIs Console page, select <strong>Services</strong>.</li>
     57   <li>Turn the <strong>Google Cloud Messaging</strong> toggle to ON.</li>
     58   <li>In the Terms of Service page, accept the terms.
     59   </li>
     60 </ol>
     61 <h2 id="access-key">Obtaining an API Key</h2>
     62 <p>To obtain an API  key:</p>
     63 <ol>
     64   <li> In the main Google APIs Console page, select <strong>API Access</strong>. You will see a screen that resembles the following:</li><br />
     65 
     66 
     67 <img src="{@docRoot}images/gcm/gcm-api-access.png" style="width:400px;padding:4px;margin-bottom:0em;">
     68 
     69 
     70   <li>Click  <strong>Create new Server key</strong>. Either a server key or a browser key should work. The advantage to using a server key is that it allows you to whitelist IP addresses. The following screen appears:</li><br />
     71 
     72 
     73 <img src="{@docRoot}images/gcm/gcm-config-server-key.png" style="width:400px;padding:4px;margin-bottom:0em;">
     74 
     75   
     76   <li>Click <strong>Create</strong>:</li><br />
     77   
     78 
     79 <img src="{@docRoot}images/gcm/gcm-api-key.png" style="width:400px;padding:4px;margin-bottom:0em;">
     80 
     81 
     82 
     83 </ol>
     84 <p> Take note of the <strong>API key</strong> value (<code>YourKeyWillBeShownHere</code>) in this example, as it will be used later on.</p>
     85 <p class="note"><strong>Note:</strong> If you need to rotate the key, click  <strong>Generate new key</strong>. A new key  will be created while the old one will still be active for up to 24 hours. If you want to get rid of the old key immediately (for example, if you feel it was compromised), click <strong>Delete key</strong>.</p>
     86 
     87 <p>The following sections walk you through the steps of creating client and server-side code.</p>
     88 
     89 <h2 id="client">Writing a Client App</h2>
     90 
     91 <p>This section walks you through the steps involved in writing a client-side application&mdash;that is, the GCM-enabled application that runs on an Android device. This client sample is designed to work in conjunction with the server code shown in <a href="#server">Writing the Server Code</a>, below.</p>
     92 
     93 
     94 
     95 <h3 id="manifest">Step 1: Edit Your App's Manifest</h3>
     96 <ul>
     97   <li>The <code>com.google.android.c2dm.permission.RECEIVE</code> permission so the Android application can register and receive messages.</li>
     98   <li>The <code>android.permission.INTERNET</code> permission so the Android application can send the registration ID to the 3rd party server.</li>
     99   <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>
    100   <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>
    101   <li>An <code>applicationPackage + &quot;.permission.C2D_MESSAGE&quot;</code> permission to prevent other Android applications from registering and receiving the Android application's
    102 messages. The permission name must exactly match this pattern&mdash;otherwise the Android application will not receive the messages.</li>
    103    <li>A receiver for <code>com.google.android.c2dm.intent.RECEIVE</code>, with the category set
    104 as <code>applicationPackage</code>. The receiver should require the <code>com.google.android.c2dm.SEND</code> permission, so that only the GCM
    105 Framework can send a message to it. Note that the receiving
    106 of messages is implemented as an <a href="{@docRoot}guide/components/intents-filters.html">intent</a>.</li>
    107   <li>An intent service to handle the intents received by the broadcast receiver. Optional.</li>
    108   <li>If the GCM feature is critical to the Android application's function, be sure to
    109 set <code>android:minSdkVersion=&quot;8&quot;</code> in the manifest. This
    110 ensures that the Android application cannot be installed in an environment in which it
    111 could not run properly. </li>
    112 </ul>
    113 
    114 <p>Here are excerpts from a manifest that supports GCM:</p>
    115 
    116 <pre class="prettyprint pretty-xml">
    117 &lt;manifest package="com.example.gcm" ...&gt;
    118 
    119     &lt;uses-sdk android:minSdkVersion="8" android:targetSdkVersion="17"/&gt;
    120     &lt;uses-permission android:name="android.permission.INTERNET" /&gt;
    121     &lt;uses-permission android:name="android.permission.GET_ACCOUNTS" /&gt;
    122     &lt;uses-permission android:name="android.permission.WAKE_LOCK" /&gt;
    123     &lt;uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" /&gt;
    124 
    125     &lt;permission android:name="com.example.gcm.permission.C2D_MESSAGE" 
    126         android:protectionLevel="signature" /&gt;
    127     &lt;uses-permission android:name="com.example.gcm.permission.C2D_MESSAGE" /&gt;
    128 
    129     &lt;application ...&gt;
    130         &lt;receiver
    131             android:name=".MyBroadcastReceiver"
    132             android:permission="com.google.android.c2dm.permission.SEND" &gt;
    133             &lt;intent-filter&gt;
    134                 &lt;action android:name="com.google.android.c2dm.intent.RECEIVE" /&gt;
    135                 &lt;category android:name="com.example.gcm" /&gt;
    136             &lt;/intent-filter&gt;
    137         &lt;/receiver&gt;
    138         &lt;service android:name=".MyIntentService" /&gt;
    139     &lt;/application&gt;
    140 
    141 &lt;/manifest&gt;
    142 </pre>
    143 
    144 
    145 <h3 id="register">Step 2: Register for GCM</h3>
    146 
    147 <p>An Android application running on a mobile device registers to receive messages by calling 
    148 the <a href="{@docRoot}reference/com/google/android/gms/gcm/GoogleCloudMessaging.html">{@code GoogleCloudMessaging}</a> method 
    149 <a href="{@docRoot}reference/com/google/android/gms/gcm/GoogleCloudMessaging.html#register">{@code register(senderID...)}</a>.
    150 This method registers the application for GCM and returns the registration ID. This streamlined approach replaces the previous
    151 GCM registration process. See the example below for details.</p>
    152 
    153 <h3 id="app"> Step 3: Write Your Application</h3>
    154 
    155 <p>Finally, write your application. GCM offers a variety of ways to get the job done:</p>
    156 
    157 <ul>
    158   <li>For your messaging server, you can either use the new <a href="ccs.html">GCM Cloud Connection Server</a> (CCS), the older <a href="gcm.html">GCM HTTP server</a>, or both in tandem. For more discussion, see see <a href="server.html">GCM Server</a>.</li>
    159   <li>To write your client application (that is, the GCM-enabled app that runs on an Android device), use the <a href="{@docRoot}reference/com/google/android/gms/gcm/GoogleCloudMessaging.html">{@code GoogleCloudMessaging}</a> APIs as shown below. Don't forget to 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>.</li>
    160 </ul>
    161 </li>
    162   
    163 </ul>
    164 
    165 <h4 id="example">Example</h4>
    166 
    167 <p>Here is 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}) and a broadcast receiver ({@code GcmBroadcastReceiver}). You can use this client sample code in conjunction with the server code shown in <a href="#server">Writing the Server Code</a>.</p>
    168 
    169 <p>Note the following:</p>
    170 
    171 <ul>
    172   <li>The sample primarily illustrates two things: registration, and upstream messaging. Upstream messaging only applies to apps that are running against a <a href="ccs.html">CCS</a> server; HTTP-based servers don't support upstream messaging.</li>
    173   <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>
    174 </ul>
    175 
    176 <h5>Registering</h5>
    177 <p>An Android application needs to register with GCM servers before it can receive messages. So in its {@code onCreate()} method, {@code DemoActivity} checks to see whether the app is registered with GCM and with the server:</p>
    178 
    179 <pre>/**
    180  * Main UI for the demo app.
    181  */
    182 public class DemoActivity extends Activity {
    183 
    184     public static final String EXTRA_MESSAGE = "message";
    185     public static final String PROPERTY_REG_ID = "registration_id";
    186     private static final String PROPERTY_APP_VERSION = "appVersion";
    187     private static final String PROPERTY_ON_SERVER_EXPIRATION_TIME =
    188             "onServerExpirationTimeMs";
    189     /**
    190      * Default lifespan (7 days) of a reservation until it is considered expired.
    191      */
    192     public static final long REGISTRATION_EXPIRY_TIME_MS = 1000 * 3600 * 24 * 7;
    193 
    194     /**
    195      * Substitute you own sender ID here.
    196      */
    197     String SENDER_ID = "Your-Sender-ID";
    198 
    199     /**
    200      * Tag used on log messages.
    201      */
    202     static final String TAG = "GCMDemo";
    203 
    204     TextView mDisplay;
    205     GoogleCloudMessaging gcm;
    206     AtomicInteger msgId = new AtomicInteger();
    207     SharedPreferences prefs;
    208     Context context;
    209 
    210     String regid;
    211 
    212     &#64;Override
    213     public void onCreate(Bundle savedInstanceState) {
    214         super.onCreate(savedInstanceState);
    215 
    216         setContentView(R.layout.main);
    217         mDisplay = (TextView) findViewById(R.id.display);
    218 
    219         context = getApplicationContext();
    220         regid = getRegistrationId(context);
    221 
    222         if (regid.length() == 0) {
    223             registerBackground();
    224         }
    225         gcm = GoogleCloudMessaging.getInstance(this);
    226     }
    227 ...
    228 }</pre>
    229 
    230 <p>The app calls {@code getRegistrationId()} to see whether there is an existing registration ID stored in shared preferences:</p>
    231 
    232 <pre>/**
    233  * Gets the current registration id for application on GCM service.
    234  * &lt;p&gt;
    235  * If result is empty, the registration has failed.
    236  *
    237  * &#64;return registration id, or empty string if the registration is not
    238  *         complete.
    239  */
    240 private String getRegistrationId(Context context) {
    241     final SharedPreferences prefs = getGCMPreferences(context);
    242     String registrationId = prefs.getString(PROPERTY_REG_ID, "");
    243     if (registrationId.length() == 0) {
    244         Log.v(TAG, "Registration not found.");
    245         return "";
    246     }
    247     // check if app was updated; if so, it must clear registration id to
    248     // avoid a race condition if GCM sends a message
    249     int registeredVersion = prefs.getInt(PROPERTY_APP_VERSION, Integer.MIN_VALUE);
    250     int currentVersion = getAppVersion(context);
    251     if (registeredVersion != currentVersion || isRegistrationExpired()) {
    252         Log.v(TAG, "App version changed or registration expired.");
    253         return "";
    254     }
    255     return registrationId;
    256 }
    257 
    258 ...
    259 
    260 /**
    261  * &#64;return Application's {&#64;code SharedPreferences}.
    262  */
    263 private SharedPreferences getGCMPreferences(Context context) {
    264     return getSharedPreferences(DemoActivity.class.getSimpleName(), 
    265             Context.MODE_PRIVATE);
    266 }</pre>
    267 
    268 <p>If the registration ID doesn't exist, or the app was updated, or the registration ID has expired, {@code getRegistrationId()} returns an empty string to indicate that the app needs to get a new regID. {@code getRegistrationId()} calls the following methods to check the app version and whether the regID has expired:</p>
    269 
    270 <pre>/**
    271  * &#64;return Application's version code from the {&#64;code PackageManager}.
    272  */
    273 private static int getAppVersion(Context context) {
    274     try {
    275         PackageInfo packageInfo = context.getPackageManager()
    276                 .getPackageInfo(context.getPackageName(), 0);
    277         return packageInfo.versionCode;
    278     } catch (NameNotFoundException e) {
    279         // should never happen
    280         throw new RuntimeException("Could not get package name: " + e);
    281     }
    282 }
    283 
    284 /**
    285  * Checks if the registration has expired.
    286  *
    287  * &lt;p&gt;To avoid the scenario where the device sends the registration to the
    288  * server but the server loses it, the app developer may choose to re-register
    289  * after REGISTRATION_EXPIRY_TIME_MS.
    290  *
    291  * &#64;return true if the registration has expired.
    292  */
    293 private boolean isRegistrationExpired() {
    294     final SharedPreferences prefs = getGCMPreferences(context);
    295     // checks if the information is not stale
    296     long expirationTime =
    297             prefs.getLong(PROPERTY_ON_SERVER_EXPIRATION_TIME, -1);
    298     return System.currentTimeMillis() > expirationTime;
    299 }</pre>
    300 
    301 
    302 <p>If there isn't a valid existing registration ID, {@code DemoActivity} calls the following {@code registerBackground()} method to register. Note that because GCM methods are blocking, this has to take place on a background thread. This sample uses {@link android.os.AsyncTask} to accomplish this:</p>
    303 
    304 <pre>
    305 /**
    306  * Registers the application with GCM servers asynchronously.
    307  * &lt;p&gt;
    308  * Stores the registration id, app versionCode, and expiration time in the 
    309  * application's shared preferences.
    310  */
    311 private void registerBackground() {
    312     new AsyncTask<Void, Void, String>() {
    313         &#64;Override
    314         protected String doInBackground(Void... params) {
    315             String msg = "";
    316             try {
    317                 if (gcm == null) {
    318                     gcm = GoogleCloudMessaging.getInstance(context);
    319                 }
    320                 regid = gcm.register(SENDER_ID);
    321                 msg = "Device registered, registration id=" + regid;
    322 
    323                 // You should send the registration ID to your server over HTTP,
    324                 // so it can use GCM/HTTP or CCS to send messages to your app.
    325 
    326                 // For this demo: we don't need to send it because the device
    327                 // will send upstream messages to a server that echo back the message
    328                 // using the 'from' address in the message.
    329 
    330                 // Save the regid - no need to register again.
    331                 setRegistrationId(context, regid);
    332             } catch (IOException ex) {
    333                 msg = "Error :" + ex.getMessage();
    334             }
    335             return msg;
    336         }
    337 
    338         &#64;Override
    339         protected void onPostExecute(String msg) {
    340             mDisplay.append(msg + "\n");
    341         }
    342     }.execute(null, null, null);
    343 }</pre>
    344 
    345 <p>After registering, the app calls {@code setRegistrationId()} to store the registration ID in shared preferences for future use:</p>
    346 
    347 <pre>/**
    348  * Stores the registration id, app versionCode, and expiration time in the
    349  * application's {&#64;code SharedPreferences}.
    350  *
    351  * &#64;param context application's context.
    352  * &#64;param regId registration id
    353  */
    354 private void setRegistrationId(Context context, String regId) {
    355     final SharedPreferences prefs = getGCMPreferences(context);
    356     int appVersion = getAppVersion(context);
    357     Log.v(TAG, "Saving regId on app version " + appVersion);
    358     SharedPreferences.Editor editor = prefs.edit();
    359     editor.putString(PROPERTY_REG_ID, regId);
    360     editor.putInt(PROPERTY_APP_VERSION, appVersion);
    361     long expirationTime = System.currentTimeMillis() + REGISTRATION_EXPIRY_TIME_MS;
    362 
    363     Log.v(TAG, "Setting registration expiry time to " +
    364             new Timestamp(expirationTime));
    365     editor.putLong(PROPERTY_ON_SERVER_EXPIRATION_TIME, expirationTime);
    366     editor.commit();
    367 }</pre>
    368 
    369 <h5>Sending a message</h5>
    370 <p>When the user clicks the app's <strong>Send</strong> button, the app sends an upstream message using the new <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 the code shown in <a href="#server">Writing the Server Code</a> as a sample XMPP client to connect to CCS.</p>
    371 
    372 <pre>public void onClick(final View view) {
    373     if (view == findViewById(R.id.send)) {
    374         new AsyncTask<Void, Void, String>() {
    375             &#64;Override
    376             protected String doInBackground(Void... params) {
    377                 String msg = "";
    378                 try {
    379                     Bundle data = new Bundle();
    380                     data.putString("hello", "World");
    381                     String id = Integer.toString(msgId.incrementAndGet());
    382                     gcm.send(SENDER_ID + "&#64;gcm.googleapis.com", id, data);
    383                     msg = "Sent message";
    384                 } catch (IOException ex) {
    385                     msg = "Error :" + ex.getMessage();
    386                 }
    387                 return msg;
    388             }
    389 
    390             &#64;Override
    391             protected void onPostExecute(String msg) {
    392                 mDisplay.append(msg + "\n");
    393             }
    394         }.execute(null, null, null);
    395     } else if (view == findViewById(R.id.clear)) {
    396         mDisplay.setText("");
    397     } 
    398 }</pre>
    399 
    400 <p>As described above in <a href="#manifest">Step 1</a>, the app includes a broadcast receiver for the <code>com.google.android.c2dm.intent.RECEIVE</code> intent. This 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 handling the GCM message. In this sample the receiver's {@code onReceive()} method calls {@code sendNotification()} to put the message into a notification:</p>
    401 
    402 <pre>/**
    403  * Handling of GCM messages.
    404  */
    405 public class GcmBroadcastReceiver extends BroadcastReceiver {
    406     static final String TAG = "GCMDemo";
    407     public static final int NOTIFICATION_ID = 1;
    408     private NotificationManager mNotificationManager;
    409     NotificationCompat.Builder builder;
    410     Context ctx;
    411     &#64;Override
    412     public void onReceive(Context context, Intent intent) {
    413         GoogleCloudMessaging gcm = GoogleCloudMessaging.getInstance(context);
    414         ctx = context;
    415         String messageType = gcm.getMessageType(intent);
    416         if (GoogleCloudMessaging.MESSAGE_TYPE_SEND_ERROR.equals(messageType)) {
    417             sendNotification("Send error: " + intent.getExtras().toString());
    418         } else if (GoogleCloudMessaging.MESSAGE_TYPE_DELETED.equals(messageType)) {
    419             sendNotification("Deleted messages on server: " +
    420                     intent.getExtras().toString());
    421         } else {
    422             sendNotification("Received: " + intent.getExtras().toString());
    423         }
    424         setResultCode(Activity.RESULT_OK);
    425     }
    426 
    427     // Put the GCM message into a notification and post it.
    428     private void sendNotification(String msg) {
    429         mNotificationManager = (NotificationManager)
    430                 ctx.getSystemService(Context.NOTIFICATION_SERVICE);
    431 
    432         PendingIntent contentIntent = PendingIntent.getActivity(ctx, 0,
    433                 new Intent(ctx, DemoActivity.class), 0);
    434 
    435         NotificationCompat.Builder mBuilder =
    436                 new NotificationCompat.Builder(ctx)
    437         .setSmallIcon(R.drawable.ic_stat_gcm)
    438         .setContentTitle("GCM Notification")
    439         .setStyle(new NotificationCompat.BigTextStyle()
    440         .bigText(msg))
    441         .setContentText(msg);
    442 
    443         mBuilder.setContentIntent(contentIntent);
    444         mNotificationManager.notify(NOTIFICATION_ID, mBuilder.build());
    445     }
    446 }</pre>
    447 
    448 <h2 id="server">Writing the Server Code</h2>
    449 
    450 <p>Here is an example of a CCS server written in Python. You can use this in conjunction with the sample client code shown above. This sample echo server sends an initial message, and for every upstream message received, it sends a dummy response back to the application that sent the upstream message. This example illustrates how to connect,
    451 send, and receive GCM messages using XMPP. It shouldn't be used as-is
    452 on a production deployment. For examples of HTTP-based servers, see <a href="server.html">GCM Server</a>.</p>
    453 
    454 <pre>
    455 #!/usr/bin/python
    456 import sys, json, xmpp, random, string
    457 
    458 SERVER = 'gcm.googleapis.com'
    459 PORT = 5235
    460 USERNAME = ''
    461 PASSWORD = ''
    462 REGISTRATION_ID = ''
    463 
    464 unacked_messages_quota = 1000
    465 send_queue = []
    466 
    467 # Return a random alphanumerical id
    468 def random_id():
    469   rid = ''
    470   for x in range(8): rid += random.choice(string.ascii_letters + string.digits)
    471   return rid
    472 
    473 def message_callback(session, message):
    474   global unacked_messages_quota
    475   gcm = message.getTags('gcm')
    476   if gcm:
    477     gcm_json = gcm[0].getData()
    478     msg = json.loads(gcm_json)
    479     if not msg.has_key('message_type'):
    480       # Acknowledge the incoming message immediately.
    481       send({'to': msg['from'],
    482             'message_type': 'ack',
    483             'message_id': msg['message_id']})
    484       # Queue a response back to the server.
    485       if msg.has_key('from'):
    486         # Send a dummy echo response back to the app that sent the upstream message.
    487         send_queue.append({'to': msg['from'],
    488                            'message_id': random_id(),
    489                            'data': {'pong': 1}})
    490     elif msg['message_type'] == 'ack' or msg['message_type'] == 'nack':
    491       unacked_messages_quota += 1
    492 
    493 def send(json_dict):
    494   template = (&quot;&lt;message&gt;&lt;gcm xmlns='google:mobile:data'&gt;{1}&lt;/gcm&gt;&lt;/message&gt;&quot;)
    495   client.send(xmpp.protocol.Message(
    496       node=template.format(client.Bind.bound[0], json.dumps(json_dict))))
    497 
    498 def flush_queued_messages():
    499   global unacked_messages_quota
    500   while len(send_queue) and unacked_messages_quota &gt; 0:
    501     send(send_queue.pop(0))
    502     unacked_messages_quota -= 1
    503 
    504 client = xmpp.Client('gcm.googleapis.com', debug=['socket'])
    505 client.connect(server=(SERVER,PORT), secure=1, use_srv=False)
    506 auth = client.auth(USERNAME, PASSWORD)
    507 if not auth:
    508   print 'Authentication failed!'
    509   sys.exit(1)
    510 
    511 client.RegisterHandler('message', message_callback)
    512 
    513 send_queue.append({'to': REGISTRATION_ID,
    514                    'message_id': 'reg_id',
    515                    'data': {'message_destination': 'RegId',
    516                             'message_id': random_id()}})
    517 
    518 while True:
    519   client.Process(1)
    520   flush_queued_messages()</pre>
    521 
    522 
    523 
    524