OSDN Git Service

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