第25章 移动定位
HTML5 Geolocation API是HTML5新增的地理位置应用程序接口,它提供了一个可以准确感知浏览器用户当前位置的方法。如果浏览器支持,且设备具有定位功能,就能够直接使用这组API来获取当前位置信息。该Geolocation API可以应用于移动设备中的地理定位。
Geolocation API允许用户在Web应用程序中共享位置信息,使其能够享受位置感知服务。本章将介绍HTML5 Geolocation位置信息的来源:纬度、经度和其他特性,以及获取这些数据的途径(GPS、Wi-Fi和蜂窝站点等)。然后,将讨论HTML5地理定位数据的隐私问题,以及浏览器如何使用这些数据。最后,将深入探讨HTML5 Geolocation API在实际中的应用。目前有两种类型的定位请求API:单次定位请求和重复性的位置更新请求。我们会分别介绍这两种请求的使用方式和适用场景,并演示如何使用它们构建实用的HTML5 Geolocation应用程序。
【学习重点】
▲ 了解移动定位技术
▲ 正确使用HTML5 Geolocation技术
▲ 应用HTML5 Geolocation技术解决实际问题
25.1 位置信息概述
HTML5 Geolocation API的使用方法相当简单。请求一个位置信息,如果用户同意,浏览器就会返回位置信息,该位置信息是通过支持HTML5地理定位功能的底层设备。例如,笔记本电脑或手机提供给浏览器的。位置信息由纬度、经度坐标和一些其他元数据组成。有了这些位置信息就可以构建引人注目的位置感知类应用程序。
25.1.1 为什么要学习Geolocation
让我们设想一个场景:有一个Web应用程序,它可以向用户提供附近不远处某商店运动鞋的打折优惠信息。使用HTML5 Geolocation API,可以请求用户共享他们的位置,如果他们同意,应用程序就可以向其提供相关信息,告诉用户去附近哪家商店可以挑选到打折的鞋子。
HTML5 Geolocation技术的另一个应用场景是构建计算行走(跑步)路程的应用程序。想象一下,在开始跑步时通过手机浏览器启动应用程序的记录功能。在用户移动过程中,应用程序会记录已跑过的距离,还可以把跑步过程对应的坐标显示在地图上,甚至可以显示出海拔信息。如果用户正在和其他选手一起参加跑步比赛,应用程序甚至可以显示其对手的位置。
再有一种HTMLS Geolocation应用场景是基于GPS导航的社交网络应用,可以用它看到好友们当前所处的位置,如知道了好友的方位,就可以挑选合适的咖啡馆。此外,还有很多特殊的应用。
25.1.2 位置信息表示方式
位置信息主要由一对纬度和经度坐标组成,例如:
Latitude: 39.17222, Longitude: -120.13778
在这里,纬度(距离赤道以北或以南的数值表示)是39.172 22,经度(距离英国格林威治以东或以西的数值表示)是120.137 78,经纬度坐标可以用以下两种方式表示:
☑ 十进制格式,如39.172 22。
☑ DMS角度格式,如39°20'。
HTML5 Geolocation API返回坐标的格式为十进制格式。
除了纬度和经度坐标,HTML5 Geolocation还提供位置坐标的准确度,并提供其他一些元数据,具体情况取决于浏览器所在的硬件设备,这些元数据包括海拔、海拔准确度、行驶方向和速度等。如果这些元数据不存在则返回null。
25.1.3 位置信息来源
HTML5 Geolocation API不指定设备使用哪种底层技术来定位应用程序的用户。相反,它只是用于检索信息的API,而且通过该API检索到的数据只具有某种程度的准确性,它并不能保证设备返回的实际位置是精确的。设备可以使用下列数据。
☑ IP地址
☑ 三维坐标
▶ GPS全球定位系统。
▶ 从RFID、Wi-Fi和蓝牙到Wi-Fi的MAC地址。
▶ GSM或CDMA手机的ID。
☑ 用户自定义数据
为了保证更高的准确度,许多设备使用一个或多个数据源的组合。
25.1.4 IP定位
在HTML5 Geolocation API之前,基于IP地址的地理定位方法是获得位置信息的唯一方式,但其返回的位置信息通常并不靠谱,基于IP地址的地理定位的实现方式是,自动查找用户的IP地址,然后检索其注册的物理地址。因此,如果用户的IP地址是ISP提供的,其位置往往就由服务供应商的物理地址决定,该地址可能距离用户数千米。
优点:
☑ 任何地方都可用。
☑ 在服务器端处理。
缺点:
☑ 不精确,一般精确到城市级。
☑ 运算代价大,并经常出错。
许多网站会根据由IP地址得到的位置信息来做广告,所以在实际中可能会遇到这样的情况:你到其他国家旅行,访问非本地网站时却突然看到了本地广告,基于访问网站所在国家或地区的IP地址。
25.1.5 GPS定位
GPS定位是通过收集运行在地球周围的多个GPS卫星的信号实砚的。但GPS定位时间可能较长,因此它不适合需要快速响应的应用程序。因为获取GPS定位数据需要时间可能较长,所以开发人员可能需要异步查询用户位置。可以添加一个状态栏以显示正在重新获取应用程序用户的位置。
优点:
☑ 比较精确。
缺点:
☑ 定位时间长,耗电量大。
☑ 室内效果不好。
☑ 需要硬件设备支持。
25.1.6 Wi-Fi定位
基于Wi-Fi的地理定位信息是通过三角距离计算得出的,这个三角距离指的是用户当前位置到已知的多个Wi-Fi接入点的距离。不同于GPS,Wi-Fi在室内也非常准确。
优点:
☑ 精确。
☑ 可在室内使用。
☑ 可以简单、快捷定位。
缺点:
☑ 适合在大城市,在乡村等地区由于无接入点,或者接入点较少的地区效果不好。
25.1.7 手机定位
基于手机的地理定位信息是通过用户到一些基站的三角距离确定的。这种方法可提供相当准确的位置结果。这种方法通常同基于Wi-Fi和基于GPS的地理定位信息结合使用。
优点:
☑ 相当准确。
☑ 可在室内使用。
☑ 可以简单、快捷定位。
缺点:
☑ 在基站较少的偏远地区效果不好。
25.1.8 自定义定位
除了通过编程计算出用户的位置外,也可以允许用户自定义其位置。应用程序可能允许用户输入它们的地址、邮政编码和其他一些详细信息。应用程序可以利用这些信息来提供位置感知服务。
优点:
☑ 可以获得比程序定位服务更准确的位置数据。
☑ 允许地理定位服务的结果作为备用位置信息。
☑ 用户自行输入可能比自动检测更快。
缺点:
☑ 可能不准确,特别是当用户位置变更后。
25.2 使用GeolocationAPI
本节将更详细地探讨HTML5 Geolocation API的使用方法。在HTML5中,为window.navigator对象新增了一个geolocation属性,可以使用Geolocation API对该属性进行访问,window.navigator对象的geolocation属性存在3个方法,利用这些方法可以实现位置信息的读取。
25.2.1 检查浏览器支持性
各浏览器对HTML5 Geolocation的支持程度不同,并且还在不断更新。在HTML5的所有功能中,HTML5 Geolocation是第一批被全部接受和实现的功能之一,这对于开发人员来说是个好消息。相关规范已达到一个非常成熟的阶段,不大可能做大的改变。各浏览器对HTML5 Geolocation的支持情况如表25-1所示。
表25-1 浏览器支持概述

由于浏览器对它的支持程度不同,在使用之前最好先检查浏览器是否支持HTML5 Geolocation API,确保浏览器支持其所要完成的所有工作。这样当浏览器不支持时,就可以提供一些替代文木,以提示用户升级浏览器或安装插件来增强现有浏览器功能。
【示例】检测浏览器支持。

在上面代码中,loadDemo函数测试了浏览器的支持情况,这个函数是在页面加载时被调用的。如果存在地理定位对象,navigator.geolocation调用将返回该对象,否则将触发错误。页面上预先定义的support元素会根据检测结果显示支持情况的提示信息。
25.2.2 获取当前地理位置
使用getCurrentPosition()方法可以取得用户当前的地理位置信息,该方法的用法如下:
void getCurrentPosition(onSuccess, onError, options) ;
第一个参数为获取当前地理位置信息成功时所执行的回调函数,第二个参数为获取当前地理位置信息失败时所执行的回调函数,第三个参数为一些可选属性的列表。其中,第二、三个参数为可选属性。
getCurrentPosition方法中的第一个参数为获取当前地理位置信息成功时所执行的回调函数。该参数的使用方法如下:

在获取地理位置信息成功时执行的回调函数中,用到了一个参数position,它代表一个position对象。
getCurrentPosition方法中的第二个参数为获取当前地理位置信息失败时所执行的回调函数。如果获取地理位置信息失败,可以通过该回调函数把错误信息提示给用户。当在浏览器中打开使用了Geolocation API来获得用户当前位置信息的页面时,浏览器会询问用户是否共享位置信息。如果在该画面中拒绝共享,也会引起错误的发生。
该回调函数使用一个error对象作为参数,该对象具有以下两个属性:
☑ code属性
code属性包含3个值,简单说明如下:
▶ 当属性值为1时,表示用户拒绝了位置服务。
▶ 当属性值为2时,表示获取不到位置信息。
▶ 当属性值为3时,表示获取信息超时错误。
☑ message属性
message属性为一个字符串,在该字符串中包含了错误信息,这个错误信息在开发和调试时将很有用。因为有些浏览器中不支持message属性,如Firefox。
【示例1】在getCurrentPosition方法中使用第二个参数捕获错误信息的具体使用方法如下:

getCurrentPosition方法中的第三个参数可以省略,它是一些可选属性的列表,这些可选属性说明如下。
☑ enableHighAccuracy
是否要求高精度的地理位置信息,这个参数在很多设备上设置了都没用,因为使用在设备上时需要结合设备电量、具体地理情况来综合考虑。因此,多数情况下把该属性设为默认,由设备自身来调整。
☑ timeout
对地理位置信息的获取操作做一个超时限制(单位为毫秒)。如果在该时间内未获取到地理位置信息,则返回错误。
☑ maximumAge
对地理位置信息进行缓存的有效时间的单位为毫秒。例如,maximumAge:120000(1分钟是60000),如果10点整的时候获取过一次地理位置信息,10:01的时候,再次调用navigator.geolocation. getCurrentPosition重新获取地理位置信息,则返回的依然为10:00时的数据(因为设置的缓存有效时间为2分钟)。超过这个时间后缓存的地理位置信息被废弃,尝试重新获取地理位置信息。如果该值被指定为0,则无条件重新获取新的地理位置信息。
【示例2】对于这些可选属性的具体设置方法如下:

25.2.3 监视位置信息
使用watchPosition方法可以持续获取用户的当前地理位置信息,它会定期地自动获取。watchPosition()方法基本语法如下:
int watchPosition(onSuccess, onError, options) ;
该方法参数的说明与使用与getCurrentPosition()方法相同。调用该方法后会返回一个数字,这个数字的用法与JavaScript脚本中setInterval()方法的返回值用法类似,可以被clearWatch()方法使用,以停止对当前地理位置信息的监视。
25.2.4 停止获取位置信息
使用clearWatch()方法可以停止对当前用户的地理位置信息的监视。具体用法如下:
void clearWatch(watchld);
参数watchld为调用watchCurrentPosition()方法监视地理位置信息时的返回参数。
25.2.5 隐私保护
HTML5 Geolocation规范提供了一套保护用户隐私的机制。除非得到用户明确许可,否则不可获取位置信息。
【示例】具体设置步骤如下:
第1步,用户从浏览器中打开位置感知应用程序。
第2步,应用程序Web页面加载,然后通过Geolocation函数调用请求位置坐标。浏览器拦截这一请求,然后请求用户授权。
第3步,如果用户同意,浏览器从其宿主设备中检索坐标信息,如IP地址、Wi-Fi或GPS坐标,这是浏览器的内部功能。
第4步,浏览器将坐标发送给受信任的外部定位服务,它返回一个详细位置信息,并将该位置信息发回给HTML5 Geolocation应用程序。
提示:应用程序不能直接访问设备,它只能请求浏览器来代表它访问的设备。
访问使用HTML5 Geolocation API的页面时,会触发隐私保护机制。如果仅是添加HTML5 Geolocation代码,而不被任何方法调用,则不会触发隐私保护机制。只要所添加的HTML5 Geolocation代码被执行,浏览器就会提示用户应用程序要共享位置。执行HTML5 Geolocation的方式很多。例如,调用navigator.geolocation.getCurrentPosition方法等。
除了询问用户是否允许共享其位置之外,Firefox等一些浏览器还可以让用户选择记住该网站的位置服务权限,以便下次访问时不再弹出提示框,类似于在浏览器中记住某些网站的密码。
25.2.6 处理位置信息
因为位置数据属于敏感信息,所以接收到之后,必须小心地处理、存储和重传。如果用户没有授权存储这些数据,那么应用程序应该在相应任务完成后立即删除它。如果要重传位置数据,建议先对其进行加密。在收集地理定位数据时,应用程序应该着重提示用户以下内容:
☑ 会收集位置数据。
☑ 为什么收集位置数据。
☑ 位置数据将保存多久。
☑ 怎样保证数据的安全。
☑ 位置数据怎样共享,如果同意共享。
☑ 用户怎样检查和更新他们的位置数据。
25.2.7 使用position对象
如果获取地理位置信息成功,则可以在获取成功后的回调函数中通过访问position对象的属性来得到这些地理位置信息。position对象具有如下这些属性。
☑ latitude:当前地理位置的纬度。
☑ longitude:当前地理位置的经度。
☑ altitude:当前地理位置的海拔高度(不能获取时为null)。
☑ accuracy:获取到的纬度或经度的精度(以米为单位)。
☑ altitudeAccurancy:获取到的海拔高度的精度(以米为单位)。
☑ heading:设备的前进方向。用面朝正北方向的顺时针旋转角度来表示(不能获取时为null)。
☑ speed:设备的前进速度(以米/秒为单位,不能获取时为null)。
☑ timestamp:获取地理位置信息时的时间。
【示例】本示例使用getCurrentPosition()方法获取当前位置的地理信息,并且在页面中显示position对象中的所有属性。


这段代码运行结果在不同设备的浏览器上也各不相同,具体运行结果取决于运行浏览器的设备。
25.3 案例实战
在前面几节中主要讨论了Geolocation的基本使用。下面使用Geolocation技术构建简单有用的Web应用程序,通过这些应用程序可以了解到HTML5 Geolocation API的强大之处。
25.3.1 使用Google地图
本节介绍如何在页面上显示一幅Google地图,并且把用户的当前地理位置标注在地图上面,如果用户的位置发生改变,将把之前在地图上的标记自动更新到新的位置上。当然,要在页面中使用Google地图,需要使用Google Map API。
【示例】具体操作步骤如下。
第1步,在页面中导入Google Map API的脚本文件,导入方法如下:
<script type="text/JavaScript" src=http://maps.google.com/maps/api/js?sensor=false />
第2步,设定地图参数,设定方法如下:

本例将用户当前位置的纬度、经度设定为页面打开时Google地图的中心点。
第3步,创建地图,并在页面中显示。
var map1= new google.maps.Map(document.getElementById("map"), myOptions);
上面代码将地图显示在id为“map”的div元素中。
第4步,在地图上创建标记。

第5步,设置标注窗口并指定标注窗口中的注释文字。

第6步,打开标注窗口。
infowindow.open(map1, marker);
整个示例的完整代码如下:

25.3.2 跟踪行走速度
要想快速确定在一定时间内的行走距离,通常可以使用GPS导航系统或计步器这样的专用设备。基于HTML5 Geolocation提供的强大服务,开发人员可以创建一个网页跟踪从网页被加载的地方到目前所在位置所经过的距离。只要在手机浏览器中打开本示例页面并授予其位置访问的权限,每隔几秒钟,应用程序就会根据刚才走过的距离更新,并将其增加到总距离中。
【示例】本示例使用watchPosition()函数,每当有新的位置返回,就将其与最后保存的位置进行比较以计算距离。具体操作步骤如下。
第1步,创建示例程序的HTML显示代码。这部分代码比较简单,就不再说明,因为我们重点介绍处理数据的脚本,并把所有最新的数据以简单的表格形式展示,分行显示纬度、经度、准确度和以ms为单位的时间。此外,还会显示一些文本类统计信息,以便用户能够看到走过距离的概况。

表中的数值都是默认值。开始接收到数据后,应用程序会进行相应的更新。
第2步,处理Geolocation数据。在Geolocation数据处理部分,第一段JavaScript代码会检测浏览器是否支持HTML5 Geolocation,然后将检测结果显示在页面上。最后,代码会请求监测用户位置。

第3步,对于距离跟踪器而言,这些出错处理已经足够用了。我们将检查收到的所有错误编号,并更新页面上的状态信息。

注意:将位置监测中的maximumAge选项设置为:{maximumAge:20000}。这将告诉定位服务,所有缓存的位置数据的生命期都不能大于20s(或20000ms),设置此选项可以使页面处于定期更新状态。
用户可以随意调整参数的大小,并试着同时调整缓存的大小。
第4步,大部分工作都将在updateLocation()函数中实现,此函数中将使用最新数据来更新页面并计算路程。

收到一组最新坐标数据后,首先要做的是记录所有信息。我们收集纬度、经度、准确度和时间,然后将这些数据更新到表格中。
应用程序可能选择不显示时间。时间主要供程序使用,它对最终用户没有多大意义,所以可以替换成更便于用户识别的时间指示器,或将其完全拆除。
准确度是以m为单位的,任何数据都依赖于其准确度。即使不显示给用户,也应该在代码中考虑准确度。显示不准确的值会向用户提供错误的位置信息。因此,将过滤掉所有低精度的位置更新数据。

第5步,计算移动的距离。假设我们前面已经至少收到了一个准确的位置,将更新移动的总距离并将其显示给用户,同时还将存储当前值以备后面做比较。为了使我们的界面不太乱,在计算数值时可采用四舍五入或截断的方式。

示例代码的内容就这么多。包括错误处理在内,代码总共不到200行,在这么简短的HTML和脚本中,我们构建了一个能够持续监测用户位置变化的示例应用程序,几乎完整地演示了Geolocation API的使用。尽管示例不适用于台式机,但是不妨在支持地理定位功能的手机或移动设备上实践。
整个示例的完整代码如下:


