地理位置可以找到你在这个世界上的位置,如果你愿意,还可以将这个信息分享给你的朋友。我们有很多种方法来找出你所在的位置:IP 地址,无线网络的连接(我们可以根据你的手机连接到哪个基站来识别出位置),或者是设备中的 GPS 模块。
Q: 地理位置听起来很恐怖,我可以关闭吗?
A: 与远程服务器共享你的物理位置的确是一件涉及隐私的问题。地理位置 API 明确要求:“User Agent 不能够在不经用户允许的情况下发送位置信息。”换句话说,分享你的位置是可选的。如果你不愿意,不要分享就好了。
地理位置 API
地理位置 API 可以让你同信任的网站分享位置信息。页面的 JavaScript 可以获取纬度和经度信息,这些信息可以发送到远程服务器上,以便完成一些与位置相关的操作,比如本地商业信息或者在地图上显示你的位置等。
下面的表格显示,地理位置 API 在绝大多数桌面和手机浏览器上都可以使用。另外,老版本的浏览器或设备也可以使用第三方库来实现类似的功能,这一点我们会在后面详细讲述。
IE | Firefox | Safari | Chrome | Opera | iPhone | Android |
9.0+ | 3.5+ | 5.0+ | 5.0+ | 10.6+ | 3.0+ | 2.0+ |
除了支持标准的地理位置 API,一些移动设备还支持某些特殊的 API。我们在后面的内容中也会对此有所阐述。
从代码说起
地理位置 API 会在全局navigator
对象增加一个新的属性:navigator.geolocation
。使用 API 最简单的代码类似这样:
function get_location() { navigator.geolocation.getCurrentPosition(show_map); }
我们的代码没有检测信息,没有错误处理,没有各种选项。正式的 web 程序至少应该包含这里所说的前两个。为了检测地理位置 API,我们可以使用 Modernizr:
function get_location() { if (Modernizr.geolocation) { navigator.geolocation.getCurrentPosition(show_map); } else { // no native support; maybe try Gears? } }
你自己要决定,如果地理位置不能使用该怎么办。一会儿我们将解释 Gears 的 fallback 选项,但现在我们先来说说在调用getCurrentPosition()
的时候究竟会发生什么。就像我们前面所说的,地理位置是可选的。这意味着浏览器不会强制向服务器发送你的当前物理位置。不同浏览器的处理是不一样的。在 Mozilla Firefox 中,调用getCurrentPosition()
函数将在浏览器窗口顶部弹出提示栏,类似下面的截图:
我们来解释一下这个提示。作为一个最终用户,这个提示会告诉你这几个信息:
- 有网站想要你的位置信息;
- 哪个网站想要你的位置信息;
- “了解更多…” 是 Mozilla 的帮助页面,这个页面会解释下面将会发生什么(小故事:Google 会按照其 Location Service Privacy Policy 提供和存储你的数据);
- 可以选择分享你的位置;
- 可以选择不分享你的位置;
- 可以选择“永远共享”,“永不共享”和“暂不”
另外,这个提示:
- 非模态的,所以你不必担心不能切换到其他窗口或标签页;
- 独立于标签页,因此当你切换浏览器窗口或标签页的时候,这个标记将会消失,切换回来的时候又会出现;
- 不可控的,所以没有办法绕过
- 阻塞的,因此只要你不做出选择,网站就不能做出任何操作。
刚刚见到的是使用 JavaScript 代码显示这个提示框。这是一个简单的函数调用,接受一个回调函数(这里我们的回调函数就是show_map
)。getCurrentPosition()
的调用会立即返回,但是这并不意味着你马上可以访问用户位置信息。你第一次能够获得位置信息的地方是在这个回调函数里面。回调函数看上去是这样子的:
function show_map(position) { var latitude = position.coords.latitude; var longitude = position.coords.longitude; // let's show a map or do something interesting! }
回调函数接受一个参数,这是一个有两个属性的对象:coords
和timestamp
。timestamp
是计算出来位置信息的时刻。(因为这个过程是异步的,我们不能知道究竟是什么时候获得的这个数据。用户阅读这个提示框,以及他们同意共享位置都需要一定的时间。带有 GPS 模块的设备也需要一段时间去连接 GPS 卫星。)coords
有像latitude
和longitude
这样的属性,用来给出用户的物理位置信息。
position 对象 | ||
属性 | 类型 | 说明 |
coords.latitude | double | 纬度:十进制浮点数,单位-度 |
coords.longitude | double | 经度:十进制浮点数,单位-度 |
coords.altitude | double 或 null | 海拔:高于参考椭球,单位-米 |
coords.accuracy | double | 精度:单位-米 |
coords.altitudeAccuracy | double 或 null | 海拔精度:单位-米 |
coords.heading | double 或 null | 与正北方向的偏移角度:顺时针方向,单位-度 |
coords.speed | double 或 null | 移动速度:单位-米/秒 |
timestamp | DOMTimeStamp | 同 Date() 一样 |
只有三个属性是必须要有值的:coords.latitude
,coords.longitude
和coords.accuracy
。其余的可能是null
,这取决于你的设备和后端位置服务器的能力。如果有的话,heading
和speed
属性则要根据你先前的位置计算出来。
处理错误
地理位置很复杂,可能会出错。我们曾经提到过要求“用户同意”。如果你的程序需要用户位置信息,但是用户却不同意,那你就郁闷了。用户选择肯定要放在第一位。那么我们的代码怎么写呢?这就用到了getCurrentPosition()
的第二个参数:错误处理的回调函数:
navigator.geolocation.getCurrentPosition(show_map, handle_error)
如果有什么出错了,这个错误处理函数就会被调用,其参数是PositionError
对象。
PositionError 对象 | ||
属性 | 类型 | 说明 |
code | short | 枚举类型 |
message | DOMString | 对最终用户而言是不友好的 |
其中,code
是枚举类型,其值为:
PERMISSION_DENIED
(1):用户点击“不要共享”按钮,或者有其他原因无法获取位置信息;POSITION_UNAVAILABLE
(2):网络错误,或者无法连接到卫星;TIMEOUT
(3):网络是畅通的,但是花费很长时间计算用户位置。多长算“很长”?我们以后会详细解释这个问题。UNKNOWN_ERROR
(0):其他错误。
function handle_error(err) { if (err.code == 1) { // user said no! } }
Q: 地理位置 API 可以在国际空间站上使用吗?可以在月球上或者其他星球上用吗?
A: 地理位置标准是这样阐述的:“地理坐标参考系的属性值来自大地测量系统(World Geodetic System (2d) [WGS84])。不支持其他参考系。”国际空间站位于地球轨道上,所以宇航员可以使用经纬度和海拔来描述其位置。但是,大地测量系统是以地球为中心的,因此也就不能使用这个系统来描述月球或者其他星球的位置了。