Home | History | Annotate | Download | only in gcm
      1 page.title=GCM HTTP Connection Server
      2 @jd:body
      3 
      4 <div id="qv-wrapper">
      5 <div id="qv">
      6 
      7 
      8 <h2>In this document</h2>
      9 
     10 <ol class="toc">
     11   <li><a href="#auth">Authentication</a> </li>
     12   <li><a href="#request">Request Format</a> </li>
     13   <li><a href="#response">Response Format</a>
     14   <ol class="toc">
     15     <li><a href="#success">Interpreting a success response</a>
     16     <li><a href="#error_codes">Interpreting an error response</a>
     17     <li><a href="#example-responses">Example responses</a>
     18   </ol>
     19   </li>
     20   <li><a href="#app-server">Implementing an HTTP-Based App Server</a>
     21 </ol>
     22 
     23 <h2>See Also</h2>
     24 
     25 <ol class="toc">
     26 <li><a href="gs.html">Getting Started</a></li>
     27 <li><a href="client.html">Implementing GCM Client</a></li>
     28 <li><a href="ccs.html">Cloud Connection Server</a></li>
     29 
     30 
     31 </ol>
     32 
     33 </div>
     34 </div>
     35 
     36 <p>This document describes the GCM HTTP connection server. Connection servers
     37 are the Google-provided servers that take messages from the 3rd-party
     38 application server and sending them to the device.</p>
     39 
     40 
     41 
     42 <p class="note"><strong>Note:</strong> See
     43 <a href="server.html#params">Implementing GCM Server</a> for a list of all the message
     44 parameters and which connection server(s) supports them.</p>
     45 
     46 
     47 <h2 id="auth">Authentication</h2>
     48 
     49 <p>To send a  message, the application server issues a POST request to
     50 <code>https://android.googleapis.com/gcm/send</code>.</p>
     51 <p>A  message request is made of 2 parts: HTTP header and HTTP body.</p>
     52 
     53 <p>The HTTP header must contain the following headers:</p>
     54 <ul>
     55   <li><code>Authorization</code>: key=YOUR_API_KEY</li>
     56   <li><code>Content-Type</code>: <code>application/json</code> for JSON; <code>application/x-www-form-urlencoded;charset=UTF-8</code> for plain text.
     57   </li>
     58 </ul>
     59 
     60 <p>For example:
     61 </p>
     62 <pre>Content-Type:application/json
     63 Authorization:key=AIzaSyB-1uEai2WiUapxCs2Q0GZYzPu7Udno5aA
     64 
     65 {
     66   "registration_ids" : ["APA91bHun4MxP5egoKMwt2KZFBaFUH-1RYqx..."],
     67   "data" : {
     68     ...
     69   },
     70 }</pre>
     71 <p class="note">
     72   <p><strong>Note:</strong> If <code>Content-Type</code> is omitted, the format
     73 is assumed to be plain text.</p>
     74 </p>
     75 
     76 <p>The HTTP body content depends on whether you're using JSON or plain text.
     77 See
     78 <a href="server.html#params">Implementing GCM Server</a> for a list of all the
     79 parameters your JSON or plain text message can contain.</p>
     80 
     81 
     82   <h2 id="request">Request Format</h2>
     83   <p>Here is the smallest possible request (a message without any parameters and
     84 just one recipient) using JSON:</p>
     85   <pre class="prettyprint pretty-json">{ &quot;registration_ids&quot;: [ &quot;42&quot; ] }</pre>
     86 
     87   <p>And here the same example using plain text:</p>
     88   <pre class="prettyprint">registration_id=42</pre>
     89 
     90   <p> Here is a message with a payload and 6 recipients:</p>
     91   <pre class="prettyprint pretty-HTML">{ "data": {
     92     "score": "5x1",
     93     "time": "15:10"
     94   },
     95   "registration_ids": ["4", "8", "15", "16", "23", "42"]
     96 }</pre>
     97   <p>Here is a message with all optional fields set and 6 recipients:</p>
     98   <pre class="prettyprint pretty-json">{ "collapse_key": "score_update",
     99   "time_to_live": 108,
    100   "delay_while_idle": true,
    101   "data": {
    102     "score": "4x8",
    103     "time": "15:16.2342"
    104   },
    105   "registration_ids":["4", "8", "15", "16", "23", "42"]
    106 }</pre>
    107   <p>And here is the same message using plain-text format (but just 1 recipient):  </p>
    108 
    109   <pre class="prettyprint">collapse_key=score_update&amp;time_to_live=108&amp;delay_while_idle=1&amp;data.score=4x8&amp;data.time=15:16.2342&amp;registration_id=42
    110   </pre>
    111 
    112 <p class="note"><strong>Note:</strong> If your organization has a firewall
    113 that restricts the traffic to or
    114 from the Internet, you need to configure it to allow connectivity with GCM in order for
    115 your Android devices to receive messages.
    116 The ports to open are: 5228, 5229, and 5230. GCM typically only uses 5228, but
    117 it sometimes uses 5229 and 5230. GCM doesn't provide specific IPs, so you should allow
    118 your firewall to accept outgoing connections to all IP addresses
    119 contained in the IP blocks listed in Google's ASN of 15169.</p>
    120 
    121 
    122 
    123 <h2 id="response">Response format</h2>
    124 
    125 <p>There are two possible outcomes when trying to send a message:</p>
    126 <ul>
    127   <li>The message is processed successfully.</li>
    128   <li>The GCM server rejects the request.</li>
    129 </ul>
    130 
    131 <p>When the message is processed successfully, the HTTP response has a 200 status
    132 and the body contains more information about the status of the message
    133 (including possible errors). When the request is rejected,
    134 the HTTP response contains a non-200 status code (such as 400, 401, or 503).</p>
    135 
    136 <p>The following table summarizes the statuses that the HTTP response header might
    137 contain. Click the troubleshoot link for advice on how to deal with each type of
    138 error.</p>
    139 <table border=1>
    140   <tr>
    141     <th>Response</th>
    142     <th>Description</th>
    143   </tr>
    144   <tr>
    145     <td>200</td>
    146     <td>Message was processed successfully. The response body will contain more
    147 details about the message status, but its format will depend whether the request
    148 was JSON or plain text. See <a href="#success">Interpreting a success response</a>
    149 for more details.</td>
    150   </tr>
    151   <tr>
    152     <td>400</td>
    153     <td><span id="internal-source-marker_0.2">Only applies for JSON requests.
    154 Indicates that the request could not be parsed as JSON, or it contained invalid
    155 fields (for instance, passing a string where a number was expected). The exact
    156 failure reason is described in the response and the problem should be addressed
    157 before the request can be retried.</td>
    158   </tr>
    159   <tr>
    160     <td>401</td>
    161     <td>There was an error authenticating the sender account.
    162 <a href="#auth_error">Troubleshoot</a></td>
    163   </tr>
    164   <tr>
    165     <td>5xx</td>
    166     <td>Errors in the 500-599 range (such as 500 or 503) indicate that there wa
    167 an internal error in the GCM server while trying to process the request, or that
    168 the server is temporarily unavailable (for example, because of timeouts). Sender
    169 must retry later, honoring any <code>Retry-After</code> header included in the
    170 response. Application servers must implement exponential back-off.
    171 <a href="#internal_error">Troubleshoot</a></td>
    172   </tr>
    173 </table>
    174 
    175 <h3 id="success">Interpreting a success response</h3>
    176 <p>When a JSON request is successful (HTTP status code 200), the response body
    177 contains a JSON object with the following fields:</p>
    178 <table>
    179   <tr>
    180     <th>Field</th>
    181     <th>Description</th>
    182   </tr>
    183   <tr>
    184     <td><code>multicast_id</code></td>
    185     <td>Unique ID (number) identifying the multicast message.</td>
    186   </tr>
    187   <tr>
    188     <td><code>success</code></td>
    189     <td>Number of messages that were processed without an error.</td>
    190   </tr>
    191   <tr>
    192     <td><code>failure</code></td>
    193     <td>Number of messages that could not be processed.</td>
    194   </tr>
    195   <tr>
    196     <td><code>canonical_ids</code></td>
    197     <td>Number of results that contain a canonical registration ID. See
    198 <a href="adv.html#canonical">Advanced Topics</a> for more discussion of this topic.</td>
    199   </tr>
    200   <tr>
    201     <td><code>results</code></td>
    202     <td>Array of objects representing the status of the messages processed. The
    203 objects are listed in the same order as the request (i.e., for each registration
    204 ID in the request, its result is listed in the same index in the response) and
    205 they can have these fields:<br>
    206       <ul>
    207         <li><code>message_id</code>: String representing the message when it was
    208 successfully processed.</li>
    209         <li><code>registration_id</code>: If set,  means that GCM processed the
    210 message but it has another canonical registration ID for that device, so sender
    211 should replace the IDs on future requests (otherwise they might be rejected).
    212 This field is never set if there is an error in the request.
    213         </li>
    214         <li><code>error</code>: String describing an error that occurred while
    215 processing the message for that recipient. The possible values are the same as
    216 documented in the above table, plus &quot;Unavailable&quot;  (meaning GCM servers
    217 were busy and could not process the message for that  particular recipient, so
    218 it could be retried).</li>
    219     </ul></td>
    220   </tr>
    221 </table>
    222 <p>If the value of <code>failure</code> and <code>canonical_ids</code> is 0, it's
    223 not necessary to parse the remainder of the response. Otherwise, we recommend
    224 that you iterate through the results field and do the following for each object
    225 in that list:</p>
    226 <ul>
    227   <li>If <code>message_id</code> is set, check for <code>registration_id</code>:
    228     <ul>
    229       <li>If <code>registration_id</code> is set, replace the original ID with
    230 the new value (canonical ID) in your server database. Note that the original ID
    231 is not part of the result, so you need to obtain it from the list of
    232 code>registration_ids</code> passed in the request (using the same index).</li>
    233     </ul>
    234   </li>
    235   <li>Otherwise, get the value of <code>error</code>:
    236     <ul>
    237       <li>If it is <code>Unavailable</code>, you could retry to send it in another
    238 request.</li>
    239       <li>If it is <code>NotRegistered</code>, you should remove the registration
    240 ID from your server database because the application was uninstalled from the
    241 device or it does not have a broadcast receiver configured to receive
    242 <code>com.google.android.c2dm.intent.RECEIVE</code> intents.</li>
    243       <li>Otherwise, there is something wrong in the registration ID passed in
    244 the request; it is probably a non-recoverable error that will also require removing
    245 the registration from the server database. See <a href="#error_codes">Interpreting
    246 an error response</a> for all possible error values.</li>
    247     </ul>
    248   </li>
    249 </ul>
    250 
    251 <p>When a plain-text request is successful (HTTP status code 200), the response
    252 body contains 1 or 2 lines in the form of key/value pairs.
    253 The first line is always available and its content is either <code>id=<em>ID of
    254 sent message</em></code> or <code>Error=<em>GCM error code</em></code>. The second
    255 line, if available,
    256 has the format of <code>registration_id=<em>canonical ID</em></code>. The second
    257 line is optional, and it can only be sent if the first line is not an error. We
    258 recommend handling the plain-text response in a similar way as handling the
    259 JSON response:</p>
    260 <ul>
    261   <li>If first line starts with <code>id</code>, check second line:
    262     <ul>
    263       <li>If second line starts with <code>registration_id</code>, gets its value
    264 and replace the registration IDs in your server database.</li>
    265     </ul>
    266   </li>
    267   <li>Otherwise, get the value of <code>Error</code>:
    268     <ul>
    269       <li>If it is <code>NotRegistered</code>, remove the registration ID from
    270 your server database.</li>
    271       <li>Otherwise, there is probably a non-recoverable error (<strong>Note:
    272 </strong>Plain-text requests will never return <code>Unavailable</code> as the
    273 error code, they would have returned a 500 HTTP status instead).</li>
    274     </ul>
    275   </li>
    276 </ul>
    277 
    278 <h3 id="error_codes">Interpreting an error response</h3>
    279 <p>Here are the recommendations for handling the different types of error that
    280 might occur when trying to send a message to a device:</p>
    281 
    282 <dl>
    283 <dt id="missing_reg"><strong>Missing Registration ID</strong></dt>
    284 <dd>Check that the request contains a registration ID (either in the
    285 <code>registration_id</code> parameter in a plain text message, or in the
    286 <code>registration_ids</code> field in JSON).
    287 <br/>Happens when error code is <code>MissingRegistration</code>.</dd>
    288 
    289 <dt id="invalid_reg"><strong>Invalid Registration ID</strong></dt>
    290 <dd>Check the formatting of the registration ID that you pass to the server. Make
    291 sure it matches the registration ID the phone receives in the
    292 <code>com.google.android.c2dm.intent.REGISTRATION</code> intent and that you're
    293 not truncating it or adding additional characters.
    294 <br/>Happens when error code is <code>InvalidRegistration</code>.</dd>
    295 
    296 <dt id="mismatched_sender"><strong>Mismatched Sender</strong></dt>
    297 <dd>A registration ID is tied to a certain group of senders. When an application
    298 registers for GCM usage, it must specify which senders are allowed to send messages.
    299 Make sure you're using one of those when trying to send messages to the device.
    300 If you switch to a different sender, the existing registration IDs won't work.
    301 Happens when error code is <code>MismatchSenderId</code>.</dd>
    302 
    303 <dt id="unreg_device"><strong>Unregistered Device</strong></dt>
    304 <dd>An existing registration ID may cease to be valid in a number of scenarios, including:
    305 <ul>
    306   <li>If the application manually unregisters by issuing a
    307 <span class="prettyprint pretty-java">
    308 <code>com.google.android.c2dm.intent.UNREGISTER</code></span><code>
    309 </code>intent.</li>
    310   <li>If the application is automatically unregistered, which can happen
    311 (but is not guaranteed) if the user uninstalls the application.</li>
    312   <li>If the registration ID expires. Google might decide to refresh registration
    313 IDs. </li>
    314   <li>If the application is updated but the new version does not have a broadcast
    315 receiver configured to receive <code>com.google.android.c2dm.intent.RECEIVE</code>
    316 intents.</li>
    317 </ul>
    318 For all these cases, you should remove this registration ID from the 3rd-party
    319 server and stop using it to send
    320 messages.
    321 <br/>Happens when error code is <code>NotRegistered</code>.</dd>
    322 
    323 <dt id="big_msg"><strong>Message Too Big</strong></dt>
    324   <dd>The total size of the payload data that is included in a message can't
    325 exceed 4096 bytes. Note that this includes both the size of the keys as well
    326 as the values.
    327 <br/>Happens when error code is <code>MessageTooBig</code>.</dd>
    328 
    329 <dt id="invalid_datakey"><strong>Invalid Data Key</strong></dt>
    330 <dd>The payload data contains a key (such as <code>from</code> or any value
    331 prefixed by <code>google.</code>) that is used internally by GCM in the
    332 <code>com.google.android.c2dm.intent.RECEIVE</code> Intent and cannot be used.
    333 Note that some words (such as <code>collapse_key</code>) are also used by GCM
    334 but are allowed in the payload, in which case the payload value will be
    335 overridden by the GCM value.
    336 <br />
    337 Happens when the error code is <code>InvalidDataKey</code>.</dd>
    338 
    339 <dt id="ttl_error"><strong>Invalid Time To Live</strong></dt>
    340   <dd>The value for the Time to Live field must be an integer representing
    341 a duration in seconds between 0 and 2,419,200 (4 weeks). Happens when error code
    342 is <code>InvalidTtl</code>.
    343 </dd>
    344 
    345   <dt id="auth_error"><strong>Authentication Error</strong></dt>
    346   <dd>The sender account that you're trying to use to send a message couldn't be
    347 authenticated. Possible causes are: <ul>
    348 <li>Authorization header missing or with invalid syntax.</li>
    349 <li>Invalid project number sent as key.</li>
    350 <li>Key valid but with GCM service disabled.</li>
    351 <li>Request originated from a server not whitelisted in the Server Key IPs.</li>
    352 
    353 </ul>
    354 Check that the token you're sending inside the <code>Authorization</code> header
    355 is the correct API key associated with your project. You can check the validity
    356 of your API key by running the following command:<br/>
    357 
    358 <pre># api_key=YOUR_API_KEY
    359 
    360 # curl --header "Authorization: key=$api_key" --header Content-Type:"application/json" https://android.googleapis.com/gcm/send  -d "{\"registration_ids\":[\"ABC\"]}"</pre>
    361 
    362 
    363 
    364 If you receive a 401 HTTP status code, your API key is not valid. Otherwise you
    365 should see something like this:<br/>
    366 
    367 <pre>
    368 {"multicast_id":6782339717028231855,"success":0,"failure":1,"canonical_ids":0,"results":[{"error":"InvalidRegistration"}]}
    369 </pre>
    370 If you want to confirm the validity of a registration ID, you can do so by
    371 replacing "ABC" with the registration ID.
    372 <br/>
    373 Happens when the HTTP status code is 401.
    374 
    375   <dt id="timeout"><strong>Timeout</strong></dt>
    376 
    377 <dd>The server couldn't process the request in time. You should retry the
    378 same request, but you MUST obey the following requirements:
    379 
    380 <ul>
    381 
    382 <li>Honor the <code>Retry-After</code> header if it's included in the response
    383 from the GCM server.</li>
    384 
    385 
    386 <li>Implement exponential back-off in your retry mechanism. This means an
    387 exponentially increasing delay after each failed retry (e.g. if you waited one
    388 second before the first retry, wait at least two second before the next one,
    389 then 4 seconds and so on). If you're sending multiple messages, delay each one
    390 independently by an additional random amount to avoid issuing a new request for
    391 all messages at the same time.</li>
    392 
    393 
    394 Senders that cause problems risk being blacklisted.
    395 <br />
    396 Happens when the HTTP status code is between 501 and 599, or when the
    397 <code>error</code> field of a JSON object in the results array is <code>Unavailable</code>.
    398 </dd>
    399 
    400 <dt id="internal_error"><strong>Internal Server Error</strong></dt>
    401 
    402 <dd>
    403 The server encountered an error while trying to process the request. You
    404 could retry the same request (obeying the requirements listed in the <a href="#timeout">Timeout</a>
    405 section), but if the error persists, please report the problem in the
    406 <a href="https://groups.google.com/forum/?fromgroups#!forum/android-gcm">android-gcm group</a>.
    407 <br />
    408 Happens when the HTTP status code is 500, or when the <code>error</code> field of a JSON
    409 object in the results array is <code>InternalServerError</code>.
    410 </dd>
    411 
    412 <dt id="restricted_package_name"><strong>Invalid Package Name</strong></dt>
    413 
    414 <dd>
    415 A message was addressed to a registration ID whose package name did not match
    416 the value passed in the request. Happens when error code is
    417 <code>InvalidPackageName</code>.
    418 </dd>
    419 </dl>
    420 
    421 <h3 id="example-responses">Example responses</h3>
    422 <p>This section shows a few examples of responses indicating messages that were
    423 processed successfully. See <a href="#request">Request Format</a> for
    424 the requests these responses are based on.</p>
    425 <p> Here is a simple case of a JSON message successfully sent to one recipient
    426 without canonical IDs in the response:</p>
    427 <pre class="prettyprint pretty-json">{ "multicast_id": 108,
    428   "success": 1,
    429   "failure": 0,
    430   "canonical_ids": 0,
    431   "results": [
    432     { "message_id": "1:08" }
    433   ]
    434 }</pre>
    435 
    436 <p>Or if the request was in plain-text format:</p>
    437 <pre class="prettyprint">id=1:08
    438 </pre>
    439 
    440 <p>Here are JSON results for 6 recipients (IDs 4, 8, 15, 16, 23, and 42 respectively)
    441 with 3 messages successfully processed, 1 canonical registration ID returned,
    442 and 3 errors:</p>
    443 <pre class="prettyprint pretty-json">{ "multicast_id": 216,
    444   "success": 3,
    445   "failure": 3,
    446   "canonical_ids": 1,
    447   "results": [
    448     { "message_id": "1:0408" },
    449     { "error": "Unavailable" },
    450     { "error": "InvalidRegistration" },
    451     { "message_id": "1:1516" },
    452     { "message_id": "1:2342", "registration_id": "32" },
    453     { "error": "NotRegistered"}
    454   ]
    455 }
    456 </pre>
    457 <p> In this example:</p>
    458 <ul>
    459   <li>First message: success, not required.</li>
    460   <li>Second message: should be resent (to registration ID 8).</li>
    461   <li>Third message: had an unrecoverable error (maybe the value got corrupted
    462 in the database).</li>
    463   <li>Fourth message: success, nothing required.</li>
    464   <li>Fifth message: success, but the registration ID should be updated in the
    465 server database (from 23 to 32).</li>
    466   <li>Sixth message: registration ID (42) should be removed from the server database
    467 because the application was uninstalled from the device.</li>
    468 </ul>
    469 <p>Or if just the 4th message above was sent using plain-text format:</p>
    470 <pre class="prettyprint">Error=InvalidRegistration
    471 </pre>
    472 <p>If the 5th message above was also sent using plain-text format:</p>
    473 <pre class="prettyprint">id=1:2342
    474 registration_id=32
    475 </pre>
    476 
    477 
    478 <h2 id="app-server">Implementing an HTTP-Based App Server</h2>
    479 
    480 <p>This section gives examples of implementing an app server that works with the
    481 GCM HTTP connection server. Note that a full GCM implementation requires a
    482 client-side implementation, in addition to the server.</a>
    483 
    484 
    485 <p>Requirements</p>
    486 <p>For the web server:</p>
    487 <ul>
    488   <li> <a href="http://ant.apache.org/">Ant 1.8</a> (it might work with earlier versions, but it's not guaranteed).</li>
    489   <li>One of the following:
    490     <ul>
    491       <li>A running web server compatible with Servlets API version 2.5, such as
    492 <a href="http://tomcat.apache.org/">Tomcat 6</a> or <a href="http://jetty.codehaus.org/">Jetty</a>, or</li>
    493       <li><a href="http://code.google.com/appengine/">Java App Engine SDK</a>
    494 version 1.6 or later.</li>
    495     </ul>
    496   </li>
    497   <li>A Google account registered to use GCM.</li>
    498   <li>The API  key for that account.</li>
    499 </ul>
    500 <p>For the Android application:</p>
    501 <ul>
    502   <li>Emulator (or device) running Android 2.2 with Google APIs.</li>
    503   <li>The Google API project number of the account registered to use GCM.</li>
    504 </ul>
    505 
    506 <h3 id="gcm-setup">Setting Up GCM</h3>
    507 <p>Before proceeding with the server and client setup, it's necessary to register
    508 a Google account with the Google API Console, enable Google Cloud Messaging in GCM,
    509 and obtain an API key from the <a href="https://code.google.com/apis/console">
    510 Google API Console</a>.</p>
    511 <p>For instructions on how to set up GCM, see <a href="gs.html">Getting Started</a>.</p>
    512 
    513 
    514 <h3 id="server-setup">Setting Up an HTTP Server</h3>
    515 <p>This section describes the different options for setting up an HTTP server.</p>
    516 
    517 <h4 id="webserver-setup">Using a standard web server</h4>
    518 <p>To set up the server using a standard, servlet-compliant web server:</p>
    519 <ol>
    520   <li>From the <a href="http://code.google.com/p/gcm">open source site</a>,
    521 download the following directories: <code>gcm-server</code>,
    522 <code>samples/gcm-demo-server</code>, and <code>samples/gcm-demo-appengine</code>.</p>
    523 
    524 
    525   <li>In a text editor, edit the <code>samples/gcm-demo-server/WebContent/WEB-INF/classes/api.key</code> and replace the existing text with the API key obtained above.</li>
    526   <li>In a shell window, go to the <code>samples/gcm-demo-server</code> directory.</li>
    527   <li>Generate the server's WAR file by running <code>ant war</code>:</li>
    528 
    529   <pre class="prettyprint">$ ant war
    530 
    531 Buildfile:build.xml
    532 
    533 init:
    534    [mkdir] Created dir: build/classes
    535    [mkdir] Created dir: dist
    536 
    537 compile:
    538    [javac] Compiling 6 source files to build/classes
    539 
    540 war:
    541      [war] Building war: <strong>dist/gcm-demo.war</strong>
    542 
    543 BUILD SUCCESSFUL
    544 Total time: 0 seconds
    545 </pre>
    546 
    547   <li>Deploy the <code>dist/gcm-demo.war</code> to your running server. For instance, if you're using Jetty, copy <code>gcm-demo.war</code> to the <code>webapps</code> directory of the Jetty installation.</li>
    548   <li>Open the server's main page in a browser. The URL depends on the server you're using and your machine's IP address, but it will be something like <code>http://192.168.1.10:8080/gcm-demo/home</code>, where <code>gcm-demo</code> is the application context and <code>/home</code> is the path of the main servlet.
    549 
    550   </li>
    551 </ol>
    552 <p class="note"><strong>Note:</strong> You can get the IP by running<code>ifconfig</code>on Linux or MacOS, or<code>ipconfig</code>on Windows. </p>
    553 
    554 <p> You server is now ready.</p>
    555 
    556 <h4 id="appengine-setup">Using App Engine for Java</h4>
    557 
    558 <p>To set up the server using a standard App Engine for Java:</p>
    559 <ol>
    560   <li>Get the files from the <a href="http://code.google.com/p/gcm">open source
    561 site</a>, as described above.</p>
    562   </li>
    563   <li>In a text editor, edit
    564 <code>samples/gcm-demo-appengine/src/com/google/android/gcm/demo/server/ApiKeyInitializer.java</code>
    565 and replace the existing text with the API key obtained above.
    566 
    567   <p class="note"><strong>Note:</strong> The API key value set in that class will
    568 be used just once to create a persistent entity on App Engine. If you deploy
    569 the application, you can use App Engine's <code>Datastore Viewer</code> to change
    570 it later.</p>
    571 
    572   </li>
    573   <li>In a shell window, go to the <code>samples/gcm-demo-appengine</code> directory.</li>
    574   <li>Start the development App Engine server by <code>ant runserver</code>,
    575 using the <code>-Dsdk.dir</code> to indicate the location of the App Engine SDK
    576 and <code>-Dserver.host</code> to set your server's hostname or IP address:</li>
    577 
    578 <pre class="prettyprint">
    579 $ ant -Dsdk.dir=/opt/google/appengine-java-sdk runserver -Dserver.host=192.168.1.10
    580 Buildfile: gcm-demo-appengine/build.xml
    581 
    582 init:
    583     [mkdir] Created dir: gcm-demo-appengine/dist
    584 
    585 copyjars:
    586 
    587 compile:
    588 
    589 datanucleusenhance:
    590   [enhance] DataNucleus Enhancer (version 1.1.4) : Enhancement of classes
    591   [enhance] DataNucleus Enhancer completed with success for 0 classes. Timings : input=28 ms, enhance=0 ms, total=28 ms. Consult the log for full details
    592   [enhance] DataNucleus Enhancer completed and no classes were enhanced. Consult the log for full details
    593 
    594 runserver:
    595      [java] Jun 15, 2012 8:46:06 PM com.google.apphosting.utils.jetty.JettyLogger info
    596      [java] INFO: Logging to JettyLogger(null) via com.google.apphosting.utils.jetty.JettyLogger
    597      [java] Jun 15, 2012 8:46:06 PM com.google.apphosting.utils.config.AppEngineWebXmlReader readAppEngineWebXml
    598      [java] INFO: Successfully processed gcm-demo-appengine/WebContent/WEB-INF/appengine-web.xml
    599      [java] Jun 15, 2012 8:46:06 PM com.google.apphosting.utils.config.AbstractConfigXmlReader readConfigXml
    600      [java] INFO: Successfully processed gcm-demo-appengine/WebContent/WEB-INF/web.xml
    601      [java] Jun 15, 2012 8:46:09 PM com.google.android.gcm.demo.server.ApiKeyInitializer contextInitialized
    602      [java] SEVERE: Created fake key. Please go to App Engine admin console, change its value to your API Key (the entity type is 'Settings' and its field to be changed is 'ApiKey'), then restart the server!
    603      [java] Jun 15, 2012 8:46:09 PM com.google.appengine.tools.development.DevAppServerImpl start
    604      [java] INFO: The server is running at http://192.168.1.10:8080/
    605      [java] Jun 15, 2012 8:46:09 PM com.google.appengine.tools.development.DevAppServerImpl start
    606      [java] INFO: The admin console is running at http://192.168.1.10:8080/_ah/admin
    607 </pre>
    608 
    609   <li>Open the server's main page in a browser. The URL depends on the server
    610 you're using and your machine's IP address, but it will be something like
    611 <code>http://192.168.1.10:8080/home</code>, where <code>/home</code>
    612 is the path of the main servlet.</li>
    613 
    614   <p class="note"><strong>Note:</strong> You can get the IP by running <code>ifconfig</code>
    615 on Linux or MacOS, or <code>ipconfig</code> on Windows.</p>
    616 
    617 </ol>
    618 <p> You server is now ready.</p>
    619