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。
Javascript Code复制内容到剪贴板
清单 1. 找到用户: getCurrentPosition- navigator.geolocation.getCurrentPosition(successCallback,errorCallback,options);
这是地理定位中重要的 API。对于一大类应用程序,只需用到这个 API。地理定位对象是标准导航器对象的一部分,它有几个方法,最常用的是getCurrentPosition。访问用户位置是耗时的操作(就像在太空中找个卫星一样!),它还要取得用户的同意。因此这是一个异步操作。它的参数是回调函数:一个用于成功,一个用于失败。
成功函数将通过一个单独的Position类型的参数传递。这个对象有两个属性:一个时间戳的属性和称为坐标的Coordinates类型的属性。一个Coordinates对象有几个属性:
Javascript Code复制内容到剪贴板- latitude
- longitude
- altitude
- accuracy
- altitudeAccuracy
- heading
- speed
这些参数不是在所有设备上都可用,除了 latitude、longitude 和 accuracy。如果支持地理定位 API,并且设备可以解析位置,就可以获取 latitude、longitude 和 accuracy。
失败callback函数将传递一个PositionError类型参数。PositionError实例有两个参数:code 和 message。message 是设备特定的,可用于调试。code 有以下三个取值:
Javascript Code复制内容到剪贴板- PERMISSION_DENIED(1)
- POSITION_UNAVAILABLE(2)
- TIMEOUT(3)
应用程序将根据 code 向用户友好显示失败消息。
请注意,W3C 规范还允许选择第三个参数。这包含花费多长时间取得用户位置的超时时间。尽管如此,像 iPhone 这样的设备目前还不支持,因此不建议使用。既然已经详细看过 API,看看实际如何使用的例子吧。
与 Twitter 集成
现在 hello world 混搭程序可通过某种方式使用 Twitter。在第一个例子中,将使用 Twitter 的搜索 API。它支持根据位置范围搜索微博。清单 2显示的是本地 Twitter 搜索。
XML/HTML Code复制内容到剪贴板
清单 2. 本地 Twitter 搜索- <!DOCTYPEhtml>
- <html>
- <head>
- <metaname="viewport"content="width=device-width"/>
- <title>LocalTwitterSearch</title>
- <scripttype="text/javascript">
- functionstartSearch(){
- vargps=navigator.geolocation;
- if(gps){
- gps.getCurrentPosition(searchTwitter,
- function(error){
- alert("Gotanerror,code:"+error.code+"message:"
- +error.message);
- });
- }else{
- searchTwitter();
- }
- }
- functionsearchTwitter(position){
- varquery="http://search.twitter.com/search.json?callback=showResults&q=";
- query+=$("kwBox").value;
- if(position){
- varlat=position.coords.latitude;
- varlong=position.coords.longitude;
- query+="&geocode="+escape(lat+","+long+",50mi");
- }
- varscript=document.createElement("script");
- script.src=query;
- document.getElementsByTagName("head")[0].appendChild(script);
- }
- </script>
- </head>
- <body>
- <divid="main">
- <labelfor="kwBox">SearchTwitter:</label>
- <inputtype="text"id="kwBox"/>
- <inputtype="button"value="Go!"onclick="startSearch()"/>
- </div>
- <divid="results">
- </div>
- </body>
- </html>
用户可以在文本框输入搜索条目。单击按钮调用startSearch函数。此处就使用地理定位 API。首先检查其是否可用。如果可用,就调用getCurrentPositionAPI。如回调成功,就使用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是映射代码。
XML/HTML Code复制内容到剪贴板
清单 3. 使用 Geolocation 映射应用程序- <html>
- <head>
- <metaname="viewport"content="initial-scale=1.0,user-scalable=no"/>
- <metahttp-equiv="content-type"content="text/html;charset=UTF-8"/>
- <title>I'mtrackingyou!</title>
- <scripttype="text/javascript"src="http://maps.google.com/maps/api/js?
- sensor=true"></script>
- <scripttype="text/javascript">
- vartrackerId=0;
- vargeocoder;
- vartheUser={};
- varmap={};
- functioninitialize(){
- geocoder=newgoogle.maps.Geocoder();
- if(navigator.geolocation){
- vargps=navigator.geolocation;
- gps.getCurrentPosition(function(pos){
- varlatLng=newgoogle.maps.LatLng(pos.coords.
- latitude,pos.coords.longitude);
- varopts={zoom:12,center:latLng,mapTypeId:
- google.maps.MapTypeId.ROADMAP};
- map=newgoogle.maps.Map($("map_canvas"),opts);
- theUser=newgoogle.maps.Marker({
- position:latLng,
- map:map,
- title:"You!"
- });
- showLocation(pos);
- });
- trackerId=gps.watchPosition(function(pos){
- varlatLng=newgoogle.maps.LatLng(pos.coords.latitude,pos.
- coords.longitude);
- map.setCenter(latLng);
- theUser.setPosition(latLng);
- showLocation(pos);
- });
- }
- }
- </script>
- </head>
- <bodystyle="margin:0px;padding:0px;"onload="initialize()">
- <divid="superbar">
- <spanclass="msg">Currentlocation:
- <spanid="location"></span>
- </span>
- <inputtype="button"value="Stoptrackingme!"
- onclick="stopTracking()"/>
- </div>
- <divid="map_canvas"style="width:100%;height:90%;float:left;
- border:1pxsolidblack;">
- </div>
- </body>
- </html>
一旦文档主体加载,就调用initialize函数。该函数检查浏览器是否支持地理定位。如果支持,就调用getCurrentPosition,与清单 2中的前个例子一样。当它获取位置,就使用 Google 地图 API 创建地图。请注意如何使用纬度和经度来创建google.maps.LatLng实例。该对象用于使地图居中。下一步,创建地图上的标记来表示用户当前位置。该标记再次用到从地理定位 API 接收到的纬度和经度。
创建地图并放置标记后,开始追踪用户。捕获从watchPosition中返回的 ID。无论何时接收到新的位置,都将地图在新位置重新居中,并将标记移到新位置。清单 4显示了需要了解的另两个函数。
Javascript Code复制内容到剪贴板
清单 4. 地理编码和取消追踪函数- functionshowLocation(pos){
- varlatLng=newgoogle.maps.LatLng(pos.coords.latitude,pos.coords.longitude);
- if(geocoder){
- geocoder.geocode({'latLng':latLng},function(results,status){
- if(status==google.maps.GeocoderStatus.OK){
- if(results[1]){
- $("location").innerHTML=results[1].formatted_address;
- }
- }
- });
- }
- }
- functionstopTracking(){
- if(trackerId){
- navigator.geolocation.clearWatch(trackerId);
- }
- }
在清单 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 应用程序性能。