LBS应用中的定位问题


这个问题是我在做一次LBS课程设计时遇到的问题,前后纠结了我好久。最后终于得以解决,畅快之余,还是想将整个过程记录下来,以备将来遇到了类似的问题来回顾

定位问题

问题的缘由

大四下的LBS课程设计中,我设想的方案是一款签到应用。当我前后忙活了近三个星期终于把这款应用完工时,却发现其定位系统效果很不好。我总共是做了三个版本,一个pc一个演示用移动端,还有一个是发布在服务器上的移动端。三个版本的定位精度都不尽如人意。在宿舍还好,时好时坏,但是在教室给老师演示时却屡屡失误。众所周知,LBS应用的核心就在于定位上,这个问题不解决,整个应用都白搭。

定位的原理

要想彻底解决这个问题,就需要首先搞明白它运作的原理。我是在高德地图的api的基础上进行二次开发的(因为我在比较了国内现行的比较大型的类似产品之后觉得高德的api文档做得最好)。我们首先来看一下高德官方对它定位原理的解释

JS-API的Geolocation定位插件,融合了HTML5 Geolocation定位接口、精确IP定位服务,以及安卓定位sdk定位。其中与安卓定位sdk的结合使用适用于开发安卓系统的H5应用,需同时使用安卓定位sdk和JS-API。

PC端,因为原生接口成功率很低,JS-API会优先调用精确IP定位服务,在IP定位失败的时候,尝试使用浏览器原生定位接口进行定位,如果原生定位接口也定位失败,则返回error事件或回调error信息。定位成功之后我们会对浏览器定位的经纬度结果进行向高德坐标的转化,并对所有有效定位结果融合地址信息后返回complete事件或者回调complete信息。

移动端,如果开发者开启了sdk辅助定位,那么安卓手机上我们会优先尝试调用sdk的定位接口,失败之后优先调用浏览器原生定位接口进行定位,浏览器定位失败之后尝试进行精确IP定位,如果以上三种定位全部尝试失败则返回error事件或回调error信息,否则和PC端的一样,定位成功之后进行高德坐标转化和地址融合。

也就是说,本质上高德定位有两套方案,一个是ip定位,另一个是html5定位。在pc端,优先调用ip(精度差,但一般都能调到),移动端则完全相反。下面是html5定位的解释(实际上就是一个杂糅)

geolocation的位置信息来源包括GPS、IP地址、RFID、WIFI和蓝牙的MAC地址、以及GSM/CDMS的ID等等。规范中没有规定使用这些设备的先后顺序,在HTML5的实现中,手机等移动设备当然优先使用GPS定位,而笔记本和部分平板,最准的定位是WIFI,至于网线上网的台式机,一般就只能使用IP来定位了,这个准确度最低。

对于目前情况的剖析

我目前的设置

将定位里设置一个参数geoLocationFirst设置为true之后,现在我的应用的定位策略变成了无论是pc还是移动端,都是优先h5,然后是ip

我目前的定位结果

对于pc端和演示版移动端(也是在pc上运行),在宿舍里80%的概率能够h5定位成功,这种情况下,地理位置还是比较精确的。但是,对于部署在服务器上的移动端版本,始终定位失败。当我把移动端的ip定位禁掉之后,它竟然什么数据都定位不了了。之后我把error给alert出来了,问题描述为

geoLocation permission denied

关于这个问题的错误具体情况描述可以参考这篇文章,总之我的问题出现在chrome和safari等浏览器不再支持来自非安全域的定位请求,但是它们不会拒绝类似localhost形式的文件的请求

解决方案

网上给出来的解决方法是升级站点至https,这又是一项浩大的工程,不仅是站点升级麻烦,另外一个原因是我这个HTML里有很多http的资源(比如图床和一些外部加载的js),而且这些资源都不太可能更改为https协议的,这意味着,如果我把我自己的网站更改为https,这些http的外部资源都会被block掉(我自己试了一下,用https来访问,确实如此)。问题到此仿佛一下子陷入了绝境,直到我看到了这篇文章,这篇文章里提到了这样一段话

我这时候有点绝望了,疯狂的找解决方案,最后还真让我找到了——腾讯地图。我一直觉得腾讯很坑爹,网页游戏都被人骂,但是这次不得不感谢它。腾讯地图也是使用html5定位技术但人家是https请求,所以腾讯抓住了这个机会,建立一个类似中转站的请求转发(我个人的理解)。我们的请求会到腾讯的中转站(https)然后在(https)返回给我们这样我们的请求就是https请求IOS用户端就会为我们的定位提供地理位置定位服务了,这次测试终于过了

这个时候就体现出功能板块化的好处了,如果腾讯地图真的如它所言能够帮我解决这个问题的话,我完全可以只把定位这个版块的功能交给腾讯来处理。

这里不得不吐槽一句,腾讯地图api的官网虽然UI挺不错的,但是api文档真的是水,连百度也不如。完全没有高德那么清晰易懂。随便梳理一下都有下面一些缺点:

  • 官网上只有干巴巴几个例子,连可编辑的demo都没有
  • 接口没有具体的参数描述
  • error回调函数没有任何参数输入(这意味着不能知道错误类型)
  • 调用位置服务时,不知道为什么总是调用error的回调函数

正当我绝望时,我突然发现它们还有一个官方论坛,我不得不说,虽然腾讯地图官方的api写得烂,但是它们这个论坛是真的不错,比如我在论坛里才明白了(我看到一个人出现了跟我一样的错误)

腾讯位置定位组件这个js的api是用来给移动端准备的!pc上根本运行不了

真是要吐血了,这么重要的消息为什么不在官网上说明,我就奇怪为什么不管怎么定位最后都是调用onError函数。不过还是有好消息的,腾讯地图和高德地图的坐标系都是通用的,不需要转换。最后,我战战兢兢地git push了一下,在手机上测试了一下,发现定位效果非常好。但是还是要注意,这个只针对移动端有效,pc端的定位还是存在很大的问题。

后续的问题

我又在室外测试了一天,发现一半的情况下,腾讯提供的h5定位效果还不错,但是又有大概一半的情况下,定位数据出现了延后的情况,也就是说现在定位的是上一个地点的定位点。我想着我的代码里好像没有这样的设定,上论坛搜了一下,很多人也反映这个问题。应该是h5定位的技术特点,这个技术设定如果此时h5获取定位获取不到,就会返回上一次缓存的成功定位的地址信息。这个就比较尴尬了,因为这意味着如果你在一个定位效果很差的地方(比如食堂,我在食堂测试时,无论是网页的高德地图还是我自己写的程序定位都是失败),那么你无论如何都不能自辨清白了,想了一下,比较好的解决方案是增加一个定时上传信息的功能,在后台每隔一段时间就获取一次位置信息,保证上一次成功定位的地点和你现在的位置接近。