1page.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 37are the Google-provided servers that take messages from the 3rd-party 38application 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 44parameters 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 63Authorization: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 73is 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. 77See 78<a href="server.html#params">Implementing GCM Server</a> for a list of all the 79parameters 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 84just one recipient) using JSON:</p> 85 <pre class="prettyprint pretty-json">{ "registration_ids": [ "42" ] }</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&time_to_live=108&delay_while_idle=1&data.score=4x8&data.time=15:16.2342&registration_id=42 110 </pre> 111 112<p class="note"><strong>Note:</strong> If your organization has a firewall 113that restricts the traffic to or 114from the Internet, you need to configure it to allow connectivity with GCM in order for 115your Android devices to receive messages. 116The ports to open are: 5228, 5229, and 5230. GCM typically only uses 5228, but 117it sometimes uses 5229 and 5230. GCM doesn't provide specific IPs, so you should allow 118your firewall to accept outgoing connections to all IP addresses 119contained 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 132and the body contains more information about the status of the message 133(including possible errors). When the request is rejected, 134the 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 137contain. Click the troubleshoot link for advice on how to deal with each type of 138error.</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 147details about the message status, but its format will depend whether the request 148was JSON or plain text. See <a href="#success">Interpreting a success response</a> 149for 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. 154Indicates that the request could not be parsed as JSON, or it contained invalid 155fields (for instance, passing a string where a number was expected). The exact 156failure reason is described in the response and the problem should be addressed 157before 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 167an internal error in the GCM server while trying to process the request, or that 168the server is temporarily unavailable (for example, because of timeouts). Sender 169must retry later, honoring any <code>Retry-After</code> header included in the 170response. 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 177contains 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 203objects are listed in the same order as the request (i.e., for each registration 204ID in the request, its result is listed in the same index in the response) and 205they can have these fields:<br> 206 <ul> 207 <li><code>message_id</code>: String representing the message when it was 208successfully processed.</li> 209 <li><code>registration_id</code>: If set, means that GCM processed the 210message but it has another canonical registration ID for that device, so sender 211should replace the IDs on future requests (otherwise they might be rejected). 212This 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 215processing the message for that recipient. The possible values are the same as 216documented in the above table, plus "Unavailable" (meaning GCM servers 217were busy and could not process the message for that particular recipient, so 218it 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 223not necessary to parse the remainder of the response. Otherwise, we recommend 224that you iterate through the results field and do the following for each object 225in 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 230the new value (canonical ID) in your server database. Note that the original ID 231is not part of the result, so you need to obtain it from the list of 232code>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 238request.</li> 239 <li>If it is <code>NotRegistered</code>, you should remove the registration 240ID from your server database because the application was uninstalled from the 241device 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 244the request; it is probably a non-recoverable error that will also require removing 245the registration from the server database. See <a href="#error_codes">Interpreting 246an 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 252body contains 1 or 2 lines in the form of key/value pairs. 253The first line is always available and its content is either <code>id=<em>ID of 254sent message</em></code> or <code>Error=<em>GCM error code</em></code>. The second 255line, if available, 256has the format of <code>registration_id=<em>canonical ID</em></code>. The second 257line is optional, and it can only be sent if the first line is not an error. We 258recommend handling the plain-text response in a similar way as handling the 259JSON 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 264and 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 270your 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 273error 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 280might 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 291sure it matches the registration ID the phone receives in the 292<code>com.google.android.c2dm.intent.REGISTRATION</code> intent and that you're 293not 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 298registers for GCM usage, it must specify which senders are allowed to send messages. 299Make sure you're using one of those when trying to send messages to the device. 300If you switch to a different sender, the existing registration IDs won't work. 301Happens 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 313IDs. </li> 314 <li>If the application is updated but the new version does not have a broadcast 315receiver configured to receive <code>com.google.android.c2dm.intent.RECEIVE</code> 316intents.</li> 317</ul> 318For all these cases, you should remove this registration ID from the 3rd-party 319server and stop using it to send 320messages. 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 325exceed 4096 bytes. Note that this includes both the size of the keys as well 326as 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 331prefixed 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. 333Note that some words (such as <code>collapse_key</code>) are also used by GCM 334but are allowed in the payload, in which case the payload value will be 335overridden by the GCM value. 336<br /> 337Happens 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 341a duration in seconds between 0 and 2,419,200 (4 weeks). Happens when error code 342is <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 347authenticated. 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> 354Check that the token you're sending inside the <code>Authorization</code> header 355is the correct API key associated with your project. You can check the validity 356of 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 364If you receive a 401 HTTP status code, your API key is not valid. Otherwise you 365should see something like this:<br/> 366 367<pre> 368{"multicast_id":6782339717028231855,"success":0,"failure":1,"canonical_ids":0,"results":[{"error":"InvalidRegistration"}]} 369</pre> 370If you want to confirm the validity of a registration ID, you can do so by 371replacing "ABC" with the registration ID. 372<br/> 373Happens 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 378same 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 383from the GCM server.</li> 384 385 386<li>Implement exponential back-off in your retry mechanism. This means an 387exponentially increasing delay after each failed retry (e.g. if you waited one 388second before the first retry, wait at least two second before the next one, 389then 4 seconds and so on). If you're sending multiple messages, delay each one 390independently by an additional random amount to avoid issuing a new request for 391all messages at the same time.</li> 392 393 394Senders that cause problems risk being blacklisted. 395<br /> 396Happens 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> 403The server encountered an error while trying to process the request. You 404could retry the same request (obeying the requirements listed in the <a href="#timeout">Timeout</a> 405section), 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 /> 408Happens when the HTTP status code is 500, or when the <code>error</code> field of a JSON 409object 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> 415A message was addressed to a registration ID whose package name did not match 416the 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 423processed successfully. See <a href="#request">Request Format</a> for 424the requests these responses are based on.</p> 425<p> Here is a simple case of a JSON message successfully sent to one recipient 426without 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) 441with 3 messages successfully processed, 1 canonical registration ID returned, 442and 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 462in 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 465server database (from 23 to 32).</li> 466 <li>Sixth message: registration ID (42) should be removed from the server database 467because 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 474registration_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 481GCM HTTP connection server. Note that a full GCM implementation requires a 482client-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> 494version 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 508a Google account with the Google API Console, enable Google Cloud Messaging in GCM, 509and obtain an API key from the <a href="https://code.google.com/apis/console"> 510Google 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>, 521download 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 531Buildfile:build.xml 532 533init: 534 [mkdir] Created dir: build/classes 535 [mkdir] Created dir: dist 536 537compile: 538 [javac] Compiling 6 source files to build/classes 539 540war: 541 [war] Building war: <strong>dist/gcm-demo.war</strong> 542 543BUILD SUCCESSFUL 544Total 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 561site</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> 565and 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 568be used just once to create a persistent entity on App Engine. If you deploy 569the application, you can use App Engine's <code>Datastore Viewer</code> to change 570it 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>, 575using the <code>-Dsdk.dir</code> to indicate the location of the App Engine SDK 576and <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 580Buildfile: gcm-demo-appengine/build.xml 581 582init: 583 [mkdir] Created dir: gcm-demo-appengine/dist 584 585copyjars: 586 587compile: 588 589datanucleusenhance: 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 594runserver: 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 610you'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> 612is 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> 615on Linux or MacOS, or <code>ipconfig</code> on Windows.</p> 616 617</ol> 618<p> You server is now ready.</p> 619