HTML 5 是一項(xiàng)讓人振奮的技術(shù),這有著充分的理由。這將會(huì)是一次技術(shù)突破,因?yàn)樗梢詫⒆烂鎽?yīng)用程序功能帶入瀏覽器中。除了傳統(tǒng)瀏覽器外,對(duì)于移動(dòng)瀏覽器,其潛力甚至更大。不僅如此,最流行的移動(dòng)瀏覽器甚至已經(jīng)采用并實(shí)現(xiàn)了 HTML 5 規(guī)范中很多重要部分。在這個(gè)由五個(gè)部分組成的系列里,您將仔細(xì)了解 HTML 5 中的一些新技術(shù),它們對(duì)移動(dòng) Web 應(yīng)用程序開發(fā)具有重大影響。在本系列的每一部分中,您將動(dòng)手開發(fā)一個(gè)展示 HTML 5 新特性的移動(dòng) Web 應(yīng)用程序,這些特性可用于最新的移動(dòng) Web 瀏覽器上,如那些基于 iPhone 和 Android 的設(shè)備。
常用縮略語
- API: 應(yīng)用程序編程接口
- CSS: 層疊樣式表
- GPS: 全球定位系統(tǒng)
- HTML: 超文本標(biāo)記語言
- JSONP: 帶填充的 JSON
- SDK: 軟件開發(fā)工具包
- UI: 用戶界面
- W3C: 萬維網(wǎng)聯(lián)盟
本文中,您將使用最新的 Web 技術(shù)開發(fā) Web 應(yīng)用程序。這里大多數(shù)代碼是 HTML、JavaScript 和 CSS — 所有 Web 開發(fā)的核心技術(shù)。您最需要的東西是用來測試的瀏覽器。對(duì)于本文,強(qiáng)烈建議您使用 Mozilla Firefox 3.5+,因?yàn)樗侵С值乩矶ㄎ坏淖烂鏋g覽器。當(dāng)然,您還需要在移動(dòng)瀏覽器上測試,還需要最新的 iPhone 和 Android SDK。在本文中使用的是 iPhone SDK 3.1.3 和 Android SDK 2.1。
基礎(chǔ)知識(shí):了解一下
地理定位本身就是一項(xiàng)新技術(shù)。它能讓您知道用戶在哪。但是僅僅知道這點(diǎn)并報(bào)告給用戶并不是十分有用。難道所有人都關(guān)心自己所在的確切經(jīng)緯度?這時(shí)可以結(jié)合其他數(shù)據(jù)和服務(wù),讓這個(gè)位置信息變得有用,可以產(chǎn)生一些有趣的結(jié)果。這些服務(wù)都需要用戶的經(jīng)度和緯度作為輸入。這就是所需要的,讓我們看看是如何獲得的。清單 1 顯示的是這方面的標(biāo)準(zhǔn) JavaScript API。
清單 1. 找到用戶: getCurrentPosition
- navigator.geolocation.getCurrentPosition(successCallback,errorCallback, options);
這是地理定位中重要的 API。對(duì)于一大類應(yīng)用程序,只需用到這個(gè) API。地理定位對(duì)象是標(biāo)準(zhǔn)導(dǎo)航器對(duì)象的一部分,它有幾個(gè)方法,最常用的是 getCurrentPosition。訪問用戶位置是耗時(shí)的操作(就像在太空中找個(gè)衛(wèi)星一樣!),它還要取得用戶的同意。因此這是一個(gè)異步操作。它的參數(shù)是回調(diào)函數(shù):一個(gè)用于成功,一個(gè)用于失敗。
成功函數(shù)將通過一個(gè)單獨(dú)的 Position 類型的參數(shù)傳遞。這個(gè)對(duì)象有兩個(gè)屬性:一個(gè)時(shí)間戳的屬性和稱為坐標(biāo)的 Coordinates 類型的屬性。一個(gè) Coordinates 對(duì)象有幾個(gè)屬性:
JavaScript Code復(fù)制內(nèi)容到剪貼板- latitude
- longitude
- altitude
- accuracy
- altitudeAccuracy
- heading
- speed
這些參數(shù)不是在所有設(shè)備上都可用,除了 latitude、longitude 和 accuracy。如果支持地理定位 API,并且設(shè)備可以解析位置,就可以獲取 latitude、longitude 和 accuracy。
失敗 callback 函數(shù)將傳遞一個(gè) PositionError 類型參數(shù)。PositionError 實(shí)例有兩個(gè)參數(shù):code 和 message。message 是設(shè)備特定的,可用于調(diào)試。code 有以下三個(gè)取值:
JavaScript Code復(fù)制內(nèi)容到剪貼板- PERMISSION_DENIED (1)
- POSITION_UNAVAILABLE (2)
- TIMEOUT (3)
應(yīng)用程序?qū)⒏鶕?jù) code 向用戶友好顯示失敗消息。
請(qǐng)注意,W3C 規(guī)范還允許選擇第三個(gè)參數(shù)。這包含花費(fèi)多長時(shí)間取得用戶位置的超時(shí)時(shí)間。盡管如此,像 iPhone 這樣的設(shè)備目前還不支持,因此不建議使用。既然已經(jīng)詳細(xì)看過 API,看看實(shí)際如何使用的例子吧。
與 Twitter 集成
現(xiàn)在 hello world 混搭程序可通過某種方式使用 Twitter。在第一個(gè)例子中,將使用 Twitter 的搜索 API。它支持根據(jù)位置范圍搜索微博。清單 2 顯示的是本地 Twitter 搜索。
清單 2. 本地 Twitter 搜索
- <!DOCTYPE html>
- <html>
- <head>
- <meta name = "viewport" content = "width = device-width"/>
- <title>Local Twitter Search</title>
- <script type="text/javascript">
- function startSearch(){
- var gps = navigator.geolocation;
- if (gps){
- gps.getCurrentPosition(searchTwitter,
- function(error){
- alert("Got an error, code: " + error.code + " message: "
- + error.message);
- });
- } else {
- searchTwitter();
- }
- }
- function searchTwitter(position){
- var query = "http://search.twitter.com/search.json?callback=showResults&q=";
- query += $("kwBox").value;
- if (position){
- var lat = position.coords.latitude;
- var long = position.coords.longitude;
- query += "&geocode=" + escape(lat + "," + long + ",50mi");
- }
- var script = document.createElement("script");
- script.src = query;
- document.getElementsByTagName("head")[0].appendChild(script);
- }
- </script>
- </head>
- <body>
- <div id="main">
- <label for="kwBox">Search Twitter:</label>
- <input type="text" id="kwBox"/>
- <input type="button" value="Go!" onclick="startSearch()"/>
- </div>
- <div id="results">
- </div>
- </body>
- </html>
用戶可以在文本框輸入搜索條目。單擊按鈕調(diào)用 startSearch 函數(shù)。此處就使用地理定位 API。首先檢查其是否可用。如果可用,就調(diào)用 getCurrentPosition API。如回調(diào)成功,就使用 searchTwitter 函數(shù)。如果 callback 函數(shù)失敗,就傳遞一個(gè)顯示失敗信息的終止參數(shù)。
如果瀏覽器成功找到位置,就調(diào)用 searchTwitter 函數(shù)。這里使用傳遞給函數(shù)的位置來向 Twitter 搜索查詢添加 geocode 參數(shù)。清單 2搜索指定位置 50 英里內(nèi)的帖子。為了調(diào)用 Twitter,要使用動(dòng)態(tài)腳本標(biāo)簽,這是一項(xiàng)常稱為 JSONP 的技術(shù)。Twitter 搜索 API 對(duì)此提供支持,它允許直接從瀏覽器調(diào)用 Twitter 搜索,不需要服務(wù)器。這由查詢中的 callback 參數(shù)指出。請(qǐng)注意它設(shè)置成 showResults。這是所要調(diào)用的函數(shù)名稱。在 清單 2 中未顯示,因?yàn)檫@只是用來創(chuàng)建 UI,但在本文的源代碼中已有包含(查看 下載)。 圖 1 顯示的是 清單 2 中代碼的屏幕截圖,這是在 iPhone 上運(yùn)行的。
圖 1. 從 iPhone 上搜索 Twitter
本應(yīng)用程序和其他位置感知應(yīng)用程序一樣,只要一次獲得位置。盡管如此,其他應(yīng)用程序在用戶移動(dòng)時(shí)要保持追蹤。這些應(yīng)用程序需要使用其他更高級(jí)的地理定位 API。
更高級(jí)的內(nèi)容:追蹤
有時(shí)候應(yīng)用程序不只需要知道用戶的當(dāng)前位置,還需要在用戶每次改變位置時(shí)及時(shí)更新。有個(gè)用于此目的的 API,是watchPosition。它與 getCurrentPosition 很相似,接收同樣的參數(shù)。最大的不同是它返回 ID。這個(gè) ID 可與最后的地理定位 APIclearWatch 聯(lián)合使用。該函數(shù)會(huì)用到從 watchPosition 獲得的 ID。當(dāng)您調(diào)用 watchPosition,瀏覽器將會(huì)一直向您傳入的成功回調(diào)函數(shù)發(fā)送更新,直到調(diào)用 clearWatch。持續(xù)不斷獲取用戶位置信息將會(huì)耗盡設(shè)備資源,所以請(qǐng)謹(jǐn)慎使用這些 API。現(xiàn)在看看例子。
與 Google 地圖集成
本例中,您將使用 Google 地圖 API。這些 API 已對(duì)使用移動(dòng)設(shè)備進(jìn)行了優(yōu)化,尤其是對(duì) iPhone 和 Android 平臺(tái)。這使得它們對(duì)移動(dòng) Web 開發(fā)人員很有吸引力,尤其是位置感知應(yīng)用程序。以下的應(yīng)用程序示例將會(huì)在地圖上顯示用戶位置,并且在每次用戶改變位置時(shí)更新。清單 3 是映射代碼。
清單 3. 使用 Geolocation 映射應(yīng)用程序
- <html>
- <head>
- <meta name="viewport" content="initial-scale=1.0, user-scalable=no" />
- <meta http-equiv="content-type" content="text/html; charset=UTF-8"/>
- <title>I'm tracking you!</title>
- <script type="text/javascript" src="http://maps.google.com/maps/api/js?
- sensor=true"></script>
- <script type="text/javascript">
- var trackerId = 0;
- var geocoder;
- var theUser = {};
- var map = {};
- function initialize() {
- geocoder = new google.maps.Geocoder();
- if (navigator.geolocation){
- var gps = navigator.geolocation;
- gps.getCurrentPosition(function(pos){
- var latLng = new google.maps.LatLng(pos.coords.
- latitude,pos.coords.longitude);
- var opts = {zoom:12, center:latLng, mapTypeId:
- google.maps.MapTypeId.ROADMAP};
- map = new google.maps.Map($("map_canvas"), opts);
- theUser = new google.maps.Marker({
- position: latLng,
- map: map,
- title: "You!"
- });
- showLocation(pos);
- });
- trackerId = gps.watchPosition(function(pos){
- var latLng = new google.maps.LatLng(pos.coords.latitude,pos.
- coords.longitude);
- map.setCenter(latLng);
- theUser.setPosition(latLng);
- showLocation(pos);
- });
- }
- }
- </script>
- </head>
- <body style="margin:0px; padding:0px;" onload="initialize()">
- <div id="superbar">
- <span class="msg">Current location:
- <span id="location"></span>
- </span>
- <input type="button" value="Stop tracking me!"
- onclick="stopTracking()"/>
- </div>
- <div id="map_canvas" style="width:100%; height:90%; float:left;
- border: 1px solid black;">
- </div>
- </body>
- </html>
一旦文檔主體加載,就調(diào)用 initialize 函數(shù)。該函數(shù)檢查瀏覽器是否支持地理定位。如果支持,就調(diào)用 getCurrentPosition,與 清單 2 中的前個(gè)例子一樣。當(dāng)它獲取位置,就使用 Google 地圖 API 創(chuàng)建地圖。請(qǐng)注意如何使用緯度和經(jīng)度來創(chuàng)建 google.maps.LatLng實(shí)例。該對(duì)象用于使地圖居中。下一步,創(chuàng)建地圖上的標(biāo)記來表示用戶當(dāng)前位置。該標(biāo)記再次用到從地理定位 API 接收到的緯度和經(jīng)度。
創(chuàng)建地圖并放置標(biāo)記后,開始追蹤用戶。捕獲從 watchPosition 中返回的 ID。無論何時(shí)接收到新的位置,都將地圖在新位置重新居中,并將標(biāo)記移到新位置。清單 4 顯示了需要了解的另兩個(gè)函數(shù)。
清單 4. 地理編碼和取消追蹤函數(shù)
- function showLocation(pos){
- var latLng = new google.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;
- }
- }
- });
- }
- }
- function stopTracking(){
- if (trackerId){
- navigator.geolocation.clearWatch(trackerId);
- }
- }
在 清單 3 中,當(dāng)?shù)貓D初始繪制及接收到用戶位置更新時(shí),調(diào)用 showLocation 函數(shù)。該函數(shù)如 清單 4 所示。它使用的是google.maps.Geocoder 實(shí)例(在 清單 3 的 initialize 函數(shù)開始處創(chuàng)建)。這個(gè) API 可執(zhí)行地理編碼或者接收地址將其轉(zhuǎn)換為映射坐標(biāo)(緯度和經(jīng)度)。它還執(zhí)行逆向地理編碼 — 將映射坐標(biāo)轉(zhuǎn)換成實(shí)際位置。本例中,使用了地理定位 API 生成的坐標(biāo),并使用 Google 地圖 API 對(duì)其逆向編碼。結(jié)果顯示在屏幕上。
清單 4 中最后一個(gè)函數(shù)是 stopTracking 函數(shù),當(dāng)用戶單擊 清單 3 的 HTML 生成的按鈕時(shí)調(diào)用。此處當(dāng)首次調(diào)用 watchPosition 函數(shù)時(shí)得到 trackerId。只要簡單地將其傳遞給 clearWatch 函數(shù),瀏覽器/設(shè)備就會(huì)停止獲取用戶位置并停止調(diào)用 JavaScript。圖 2 顯示的是正在使用的追蹤應(yīng)用程序的屏幕截圖。
圖 2. 追蹤應(yīng)用程序
當(dāng)然,要實(shí)際測試追蹤,需要改變位置。可以使用 Google App Engine,因?yàn)樗軐⒛?Web 應(yīng)用程序上傳到公共可達(dá)位置。然后可以直接在連接良好的移動(dòng)設(shè)備中測試。一旦完成,您可以乘坐公共交通工具,或者是讓別人開車帶您四處走走,看看您的 Web 應(yīng)用程序?qū)Σ粩喔淖兊奈恢米龀龅捻憫?yīng)。
結(jié)束語
本文演示了如何在移動(dòng) Web 應(yīng)用程序中使用地理定位 API。GPS 聽上去很吸引人,但相當(dāng)復(fù)雜。盡管如此,如您所見,地理定位的 W3C 標(biāo)準(zhǔn)提供了很簡單的 API。它直接獲取用戶位置并隨時(shí)間變化追蹤位置。并由此將坐標(biāo)傳遞給很多支持位置的 Web 服務(wù),或者是您自己正在開發(fā)的位置感知服務(wù)。在本系列關(guān)于 HTML 5 和移動(dòng) Web 應(yīng)用程序的第 2 部分中,您將看到如何利用本地存儲(chǔ)提升移動(dòng) Web 應(yīng)用程序性能。