HTML 5 是一项让人振奋的技术,这有着充分的理由。这将会是一次技术突破,因为它可以将桌面应用程序功能带入浏览器中。除了传统浏览器外,对于移动浏览器,其潜力甚至更大。不仅如此,最流行的移动浏览器甚至已经采用并实现了 HTML 5 规范中很多重要部分。在这个由五个部分组成的系列里,您将仔细了解 HTML 5 中的一些新技术,它们对移动 Web 应用程序开发具有重大影响。在本系列的每一部分中,您将动手开发一个展示 HTML 5 新特性的移动 Web 应用程序,这些特性可用于最新的移动 Web 浏览器上,如那些基于 iPhone 和 Android 的设备。

常用缩略语

  • API: 应用程序编程接口
  • CSS: 层叠样式表
  • GPS: 全球定位系统
  • HTML: 超文本标记语言
  • JSONP: 带填充的 JSON
  • SDK: 软件开发工具包
  • UI: 用户界面
  • W3C: 万维网联盟

先决条件

本文中,您将使用最新的 Web 技术开发 Web 应用程序。这里大多数代码是 HTML、JavaScript 和 CSS — 所有 Web 开发的核心技术。您最需要的东西是用来测试的浏览器。对于本文,强烈建议您使用 Mozilla Firefox 3.5+,因为它是支持地理定位的桌面浏览器。当然,您还需要在移动浏览器上测试,还需要最新的 iPhone 和 Android SDK。在本文中使用的是 iPhone SDK 3.1.3 和 Android SDK 2.1。

基础知识:了解一下

地理定位本身就是一项新技术。它能让您知道用户在哪。但是仅仅知道这点并报告给用户并不是十分有用。难道所有人都关心自己所在的确切经纬度?这时可以结合其他数据和服务,让这个位置信息变得有用,可以产生一些有趣的结果。这些服务都需要用户的经度和纬度作为输入。这就是所需要的,让我们看看是如何获得的。清单 1 显示的是这方面的标准 JavaScript API。

清单 1. 找到用户: getCurrentPosition

JavaScript Code复制内容到剪贴板
  1. navigator.geolocation.getCurrentPosition(successCallback,errorCallback, options);

这是地理定位中重要的 API。对于一大类应用程序,只需用到这个 API。地理定位对象是标准导航器对象的一部分,它有几个方法,最常用的是 getCurrentPosition。访问用户位置是耗时的操作(就像在太空中找个卫星一样!),它还要取得用户的同意。因此这是一个异步操作。它的参数是回调函数:一个用于成功,一个用于失败。

成功函数将通过一个单独的 Position 类型的参数传递。这个对象有两个属性:一个时间戳的属性和称为坐标的 Coordinates 类型的属性。一个 Coordinates 对象有几个属性:

JavaScript Code复制内容到剪贴板
  1. latitude
  2. longitude
  3. altitude
  4. accuracy
  5. altitudeAccuracy
  6. heading
  7. speed

这些参数不是在所有设备上都可用,除了 latitude、longitude 和 accuracy。如果支持地理定位 API,并且设备可以解析位置,就可以获取 latitude、longitude 和 accuracy。

失败 callback 函数将传递一个 PositionError 类型参数。PositionError 实例有两个参数:code 和 message。message 是设备特定的,可用于调试。code 有以下三个取值:

JavaScript Code复制内容到剪贴板
  1. PERMISSION_DENIED (1)
  2. POSITION_UNAVAILABLE (2)
  3. TIMEOUT (3)

应用程序将根据 code 向用户友好显示失败消息。

请注意,W3C 规范还允许选择第三个参数。这包含花费多长时间取得用户位置的超时时间。尽管如此,像 iPhone 这样的设备目前还不支持,因此不建议使用。既然已经详细看过 API,看看实际如何使用的例子吧。

与 Twitter 集成

现在 hello world 混搭程序可通过某种方式使用 Twitter。在第一个例子中,将使用 Twitter 的搜索 API。它支持根据位置范围搜索微博。清单 2 显示的是本地 Twitter 搜索。

清单 2. 本地 Twitter 搜索

XML/HTML Code复制内容到剪贴板
  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <meta name = "viewport" content = "width = device-width"/>
  5. <title>Local Twitter Search</title>
  6. <script type="text/javascript">
  7. function startSearch(){
  8. var gps = navigator.geolocation;
  9. if (gps){
  10. gps.getCurrentPosition(searchTwitter,
  11. function(error){
  12. alert("Got an error, code: " + error.code + " message: "
  13. + error.message);
  14. });
  15. } else {
  16. searchTwitter();
  17. }
  18. }
  19. function searchTwitter(position){
  20. var query = "http://search.twitter.com/search.json?callback=showResults&q=";
  21. query += $("kwBox").value;
  22. if (position){
  23. var lat = position.coords.latitude;
  24. var long = position.coords.longitude;
  25. query += "&geocode=" + escape(lat + "," + long + ",50mi");
  26. }
  27. var script = document.createElement("script");
  28. script.src = query;
  29. document.getElementsByTagName("head")[0].appendChild(script);
  30. }
  31. </script>
  32. </head>
  33. <body>
  34. <div id="main">
  35. <label for="kwBox">Search Twitter:</label>
  36. <input type="text" id="kwBox"/>
  37. <input type="button" value="Go!" onclick="startSearch()"/>
  38. </div>
  39. <div id="results">
  40. </div>
  41. </body>
  42. </html>

用户可以在文本框输入搜索条目。单击按钮调用 startSearch 函数。此处就使用地理定位 API。首先检查其是否可用。如果可用,就调用 getCurrentPosition API。如回调成功,就使用 searchTwitter 函数。如果 callback 函数失败,就传递一个显示失败信息的终止参数。

如果浏览器成功找到位置,就调用 searchTwitter 函数。这里使用传递给函数的位置来向 Twitter 搜索查询添加 geocode 参数。清单 2搜索指定位置 50 英里内的帖子。为了调用 Twitter,要使用动态脚本标签,这是一项常称为 JSONP 的技术。Twitter 搜索 API 对此提供支持,它允许直接从浏览器调用 Twitter 搜索,不需要服务器。这由查询中的 callback 参数指出。请注意它设置成 showResults。这是所要调用的函数名称。在 清单 2 中未显示,因为这只是用来创建 UI,但在本文的源代码中已有包含(查看 下载)。 图 1 显示的是 清单 2 中代码的屏幕截图,这是在 iPhone 上运行的。

图 1. 从 iPhone 上搜索 Twitter

本应用程序和其他位置感知应用程序一样,只要一次获得位置。尽管如此,其他应用程序在用户移动时要保持追踪。这些应用程序需要使用其他更高级的地理定位 API。

更高级的内容:追踪

有时候应用程序不只需要知道用户的当前位置,还需要在用户每次改变位置时及时更新。有个用于此目的的 API,是watchPosition。它与 getCurrentPosition 很相似,接收同样的参数。最大的不同是它返回 ID。这个 ID 可与最后的地理定位 APIclearWatch 联合使用。该函数会用到从 watchPosition 获得的 ID。当您调用 watchPosition,浏览器将会一直向您传入的成功回调函数发送更新,直到调用 clearWatch。持续不断获取用户位置信息将会耗尽设备资源,所以请谨慎使用这些 API。现在看看例子。

与 Google 地图集成

本例中,您将使用 Google 地图 API。这些 API 已对使用移动设备进行了优化,尤其是对 iPhone 和 Android 平台。这使得它们对移动 Web 开发人员很有吸引力,尤其是位置感知应用程序。以下的应用程序示例将会在地图上显示用户位置,并且在每次用户改变位置时更新。清单 3 是映射代码。

清单 3. 使用 Geolocation 映射应用程序

XML/HTML Code复制内容到剪贴板
  1. <html>
  2. <head>
  3. <meta name="viewport" content="initial-scale=1.0, user-scalable=no" />
  4. <meta http-equiv="content-type" content="text/html; charset=UTF-8"/>
  5. <title>I'm tracking you!</title>
  6. <script type="text/javascript" src="http://maps.google.com/maps/api/js?
  7. sensor=true"></script>
  8. <script type="text/javascript">
  9. var trackerId = 0;
  10. var geocoder;
  11. var theUser = {};
  12. var map = {};
  13. function initialize() {
  14. geocoder = new google.maps.Geocoder();
  15. if (navigator.geolocation){
  16. var gps = navigator.geolocation;
  17. gps.getCurrentPosition(function(pos){
  18. var latLng = new google.maps.LatLng(pos.coords.
  19. latitude,pos.coords.longitude);
  20. var opts = {zoom:12, center:latLng, mapTypeId:
  21. google.maps.MapTypeId.ROADMAP};
  22. map = new google.maps.Map($("map_canvas"), opts);
  23. theUser = new google.maps.Marker({
  24. position: latLng,
  25. map: map,
  26. title: "You!"
  27. });
  28. showLocation(pos);
  29. });
  30. trackerId = gps.watchPosition(function(pos){
  31. var latLng = new google.maps.LatLng(pos.coords.latitude,pos.
  32. coords.longitude);
  33. map.setCenter(latLng);
  34. theUser.setPosition(latLng);
  35. showLocation(pos);
  36. });
  37. }
  38. }
  39. </script>
  40. </head>
  41. <body style="margin:0px; padding:0px;" onload="initialize()">
  42. <div id="superbar">
  43. <span class="msg">Current location:
  44. <span id="location"></span>
  45. </span>
  46. <input type="button" value="Stop tracking me!"
  47. onclick="stopTracking()"/>
  48. </div>
  49. <div id="map_canvas" style="width:100%; height:90%; float:left;
  50. border: 1px solid black;">
  51. </div>
  52. </body>
  53. </html>

一旦文档主体加载,就调用 initialize 函数。该函数检查浏览器是否支持地理定位。如果支持,就调用 getCurrentPosition,与 清单 2 中的前个例子一样。当它获取位置,就使用 Google 地图 API 创建地图。请注意如何使用纬度和经度来创建 google.maps.LatLng实例。该对象用于使地图居中。下一步,创建地图上的标记来表示用户当前位置。该标记再次用到从地理定位 API 接收到的纬度和经度。

创建地图并放置标记后,开始追踪用户。捕获从 watchPosition 中返回的 ID。无论何时接收到新的位置,都将地图在新位置重新居中,并将标记移到新位置。清单 4 显示了需要了解的另两个函数。

清单 4. 地理编码和取消追踪函数

JavaScript Code复制内容到剪贴板
  1. function showLocation(pos){
  2. var latLng = new google.maps.LatLng(pos.coords.latitude,pos.coords.longitude);
  3. if (geocoder) {
  4. geocoder.geocode({'latLng': latLng}, function(results, status) {
  5. if (status == google.maps.GeocoderStatus.OK) {
  6. if (results[1]) {
  7. $("location").innerHTML = results[1].formatted_address;
  8. }
  9. }
  10. });
  11. }
  12. }
  13. function stopTracking(){
  14. if (trackerId){
  15. navigator.geolocation.clearWatch(trackerId);
  16. }
  17. }

在 清单 3 中,当地图初始绘制及接收到用户位置更新时,调用 showLocation 函数。该函数如 清单 4 所示。它使用的是google.maps.Geocoder 实例(在 清单 3 的 initialize 函数开始处创建)。这个 API 可执行地理编码或者接收地址将其转换为映射坐标(纬度和经度)。它还执行逆向地理编码 — 将映射坐标转换成实际位置。本例中,使用了地理定位 API 生成的坐标,并使用 Google 地图 API 对其逆向编码。结果显示在屏幕上。

清单 4 中最后一个函数是 stopTracking 函数,当用户单击 清单 3 的 HTML 生成的按钮时调用。此处当首次调用 watchPosition 函数时得到 trackerId。只要简单地将其传递给 clearWatch 函数,浏览器/设备就会停止获取用户位置并停止调用 JavaScript。图 2 显示的是正在使用的追踪应用程序的屏幕截图。

图 2. 追踪应用程序

当然,要实际测试追踪,需要改变位置。可以使用 Google App Engine,因为它能将您的 Web 应用程序上传到公共可达位置。然后可以直接在连接良好的移动设备中测试。一旦完成,您可以乘坐公共交通工具,或者是让别人开车带您四处走走,看看您的 Web 应用程序对不断改变的位置做出的响应。

结束语

本文演示了如何在移动 Web 应用程序中使用地理定位 API。GPS 听上去很吸引人,但相当复杂。尽管如此,如您所见,地理定位的 W3C 标准提供了很简单的 API。它直接获取用户位置并随时间变化追踪位置。并由此将坐标传递给很多支持位置的 Web 服务,或者是您自己正在开发的位置感知服务。在本系列关于 HTML 5 和移动 Web 应用程序的第 2 部分中,您将看到如何利用本地存储提升移动 Web 应用程序性能。