写在最前面~
这篇文章是对前端定位方案的一篇总结,平日我们在前端开发过程中针对定位问题不会专门专注内部的实现原理,会直接调用封装好的库去实现定位能力。这样就会出现一个问题,当线上报出定位问题的时候,我们一时不知所措,搞不清楚到底哪个环节出现了定位 bug,这在排查过程中也会增加我们的定位问题的成本,此时了解前端定位的方法和原理就变得尤为重要,这会帮助你快速搞清楚定位的大致方法和解决方案,快速解决问题。
一天,产品找到我沟通:PM:XX, 你看下这个问题,为什么这个定位页面手动定位不能成功了?我:这个? 嗯。。。是不是没有开定位?PM:这个已经确认过了,开着呢!我:(哦?我当然不信啊,自己手动确认一下)哦,是开着呢。那~~~,是不是缓存等其他手机问题呢?PM:我清理一下(吭哧吭哧清理),没有效果呢,没有关系吧!我:嗯!应该没关系!(尴尬着急中,为啥不能定位呢?)那这个应该需要看下源码定位下了!PM:嗯,多久可以修复呢?我:(额。。。)这个我要看下。PM:行吧,那你尽快排出修复一下。我:(慌神中。。。为啥呢?会是神马问题导致的呢?)PM:可以吧?我: 哦~,可以,我马上来看下!
看到没,这段对话中,我几乎处于懵逼的状态,产生这种状态的原因就是:我对于定位这一套流程不了解,不知道定位机制,有哪些问题导致定位失败,定位这个模型对我来说是黑盒,所以我习惯性的从黑盒以外的方面给 PM 反馈可能不成功的原因(找手机本身的问题),除此之外给不出任何建议。
于是开始介入排查工作,当我看到定位代码的时候心情是这样的:
定位方案 hin 多 hin 乱,定位代码 hin 长,感觉是个投机主义者,哪个成功用谁,这也太不负责了吧,关键这样了还可能不成功~
首先看下手机定位方案都有哪些?
基站(手机信号塔)构成一个信号网络,我们要进行通信的时候需要连接到其中一个基站,也就是手机要有信号,此时我们即可在这样一个信号网络里进行通信。我们通过基站位置,设备连接时间、信号强弱以及角度来定位设备的位置。定位速度快,精准度低,100m-1000m,依赖信号塔的密度。
具体可以参考下面这张图片进行理解:
每一个 Wi-Fi 热点都有一个独一无二的 MAC 地址,智能手机等设备开启 Wi-Fi 后就会自动扫描附近热点并上传它们的地理位置信息,这样就建立了一个庞大的热点位置数据库。反过来讲,如果你的设备连上了某个 Wi-Fi 热点,那么就可以调用服务器或离线数据中附近所有热点的地理位置信息,而服务器会参考每个热点的信号强弱计算出设备的大致地理位置,最后再返回给用户。Wi-Fi 定位精度为 20 米左右。
具体可以参考如下图片:
GPS 定位需要 GPS 硬件支持,直接和卫星交互来获取当前经纬度与准确时间。接收机在户外接收到天上的定位卫星发射出来的信号,得到卫星的位置,推算出接收机到每颗卫星的距离,进而推算出手机的位置。通过 GPS 方式定位准确度是最高的(10 米左右,取决于芯片),但是从 GPS 模块启动到获取第一次定位数据(冷启动),可能需要比较长的时间,并且 GPS 模块耗电量大,且在室内几乎无法使用。
具体可以参考如下图片:
AGPS 利用网络,首先将基站定位或者 WIFI 定位获得的大概位置发到远程服务器,有服务器进行查询和计算,得出这个位置下当前卫星信息,反馈给设备,设备就可以直接用这些信息来接受卫星信号,不用等待漫长的卫星轨道信息广播完毕后,才能知道卫星的位置,大大缩短搜星时间。GPS 解决方案的优势主要体现在其定位精度上,在室外等空旷地区,其精度在正常的 GPS 工作环境下,可以达到 10 米左右,堪称目前定位精度最高的一种定位技术。该技术的另一优点为:首次捕获 GPS 信号的时间一般仅需几秒,不像 GPS 的首次捕获时间可能要 2~3 分钟。
各种类型定位优缺点对比
除了在定位方案上不同,对于不同的手机系统在定位方面也有不同的处理方式
iOS 设备能提供 3 种不同途径进行定位:Wi-Fi、蜂窝式移动电话基站、GPS 卫星(包括 AGPS)。
iOS 不像 Android 系统在定位服务编程时,可以指定采用哪种途径进行定位。iOS 的 API 把底层这些细节屏蔽掉了,开发人员和用户并不知道现在设备是采用哪种方式进行定位的,iOS 系统会根据设备的情况和周围的环境,采用一套最佳的解决方案。如果能够接收 GPS 信息,那么设备优先采用 GPS 定位,否则采用 Wi-Fi 或蜂窝基站定位。在 Wi-Fi 和蜂窝基站之间优先使用 Wi-Fi,如果无法连接 Wi-Fi 才使用蜂窝基站定位。
Android 系统 API 提供基站 ID 和 WIFI 的 mac 地址获取接口,开发者自行维护基站、mac 数据库,自行查询推算位置。而 GPS 定位信息则可以直接调用系统 API 获得。
除了自行维护数据库之外,也可以使用百度、高德等地图厂商自行实现的定位 SDK。该定位 SDK 的作用就是通过系统接口读取到原始定位信息,然后借助于各家自行部署维护的数据库,查询到当前扫描到的基站、WIFI 的位置,最终计算出更准确的定位结果,通过 SDK 的接口,返回给开发者。
我们在开发过程中还会经常看到一些格式的坐标系,需要将这个坐标系转换成那个坐标系,那个坐标系转成这个坐标系,那么这些格式的坐标系都是怎么来的呢?分别都有什么意义呢?我们在使用过程中应该如何选择?
WGS84 是为 GPS 全球定位系统使用而建立的坐标系统,最基础的坐标系。
GCJ02 是由中国国家测绘局(G 表示 Guojia 国家,C 表示 Cehui 测绘,J 表示 Ju 局)制订的地理信息系统的坐标系统。它是一种对经纬度数据的加密算法,即加入随机的偏差。国内出版的各种地图系统(包括电子形式),必须至少采用 GCJ-02 对地理位置进行首次加密。
百度基于国标坐标进行加密生成的一套坐标系 ,百度系的产品都是使用这个坐标系。
是一种投影坐标,它不是用经纬度来表示的,等角,多用于航海图、航空图。关于墨卡托可以参考下面这张图片(在地球中心打开一盏灯,光透过球体投射到外面圆柱体上,将这个圆柱体摊开就是投射的地图坐标)。
本次项目的定位流程如下:
通过之前定位留下的 cookie 信息直接获取定位信息,快速精准的完成定位的过程,否则走之后的定位流程。
lightApp 是百度提供的一套供前端快速接入开发的能力库,定位就是包含在其中的一个能力库。
在封装的这样一个定位能力中,定位方面的能力大致分端能力,map 定位以及 h5 的 geolocation 定位。定位系统会根据定位的场景自动区分先调用哪个能力,例如在手百里,优先自动获取手百的定位能力,在 android 系统里优先使用端上一个定位能力等。最后会有一个 h5 的 geolocation 置底。
微信定位通过 wxjsbridge 进行定位,在网上没有查找到 wxjsbridge 的源码,不过大致可以推断定位跑不出端能力、h5 定位或者自定义的一种后端能力。
本需求中针对手百进行了 native 定位。baidubox 定位流程大致这样:找到 cookie('BAIDULOC') 获取定位信息,然后坐标信息的格式转换成墨卡托格式返回即可。
h5 的定位,设备里的各种定位资源都是获取定位信息渠道,自主依据环境状况获取定位信息并返回。
cookie 在定位中显得十分重要,这个 cookie 信息会直接屏蔽掉定位能力而直接获取定位信息,既快速又精确。前提是保证 cookie 信息的准确性,及时更新!很多定位系统会在定位最开始获取 cookie 信息来优化定位方案。这对于定位的两大特性——成功率和速率,都有很大的帮助。
很多的 APP 本身提供了定位能力,很多前端的业务都是在 app 打开之后执行,因此如果有很好的 bridge 实现调用端上能力去定位,这会增加定位的成功率,不过会增加开发成本。甚至有些时候我们将端上的定位结果存储在 webview 的 cookie 里也是帮助快速定位的一种方案。
三方库的定位能力基本都是封装完备的一套系统,兼容各种场景各种系统的定位能力,也就是这节讨论的其他定位技术的组合,因此不太提倡使用三方库,因为我们本身就是在制订一个策略,这样会让定位能力重复,但是会在某种程度上增加成功率。
h5 定位是移动端前端几乎必备的一个定位技术,首先是调用 api 便捷,定位能力较好,很多时候这种定位方案会成为多种定位方案之后的最终保险方案。h5 会自动根据当前环境情况去取舍应该通过哪种定位方案获取定位信息并返回。
服务端定位是需要前后端配合的一种方案,例如我们在启动 webview 的时候向后端发送一个请求,后端可以通过 IP 来获取位置信息返回,不过这种定位强烈依赖网络 IP,因此存在错误风险。
说了这么多的定位方案和前端定位技术,那么我们要怎么按需组织我们的定位方案呢?其实我们只需要把握好两个方面就可以了——成功率和高速率,从这两个特性上找到平衡即可。
那么我们有什么方案去提高成功率呢?
增加定位方案,根据实际开发场景,如果有端上定位能力,那么我们可以先调用端能力并且定位成功存 cookie,例如在手百、微信场景里;与后端协商增加服务端定位方案,这样增加一种定位保险;实现 cookie 共享,例如 app 中的定位信息可以共享给前端,前端直接获取提高定位成功率。
那高速定位呢?
提高定位速度这件事情更加需要结合需求本身以及 APP 特性,在基于这些定位能力灵活组合,确保定位成功率和定位效率;这些定位为方案并行执行,多种方案同时定位,哪种方案先获取定位结果就使用哪种方案。
所以最后可以总结一套基础定位结果方案:
总结到这里我就明白了为什么定位方案给人看起来总是那么多,那么杂。当我们了解移动端定位方案和定位技术以后,我们再次面对上面 PM 的问题:
PM:定位不成功...我:嗯,定位不成功,那就一定是所有方案都没成功。那就是没有 cookie,目前场景不在微信不在手百,那所以这些也都不用看,那就是 h5 定位了。PM:所以咋处理?我:h5 定位失败的话,如果手机网络和信号都很好,同时允许打开了定位,一般是协议问题,或者定位时间长度太短,很多老机器不能在规定时间内定位成功。我去查下这两个问题。
不久就查到是因为协议问题导致了定位不成功。h5 定位在 ios 只支持 https 协议;同时部分低端 android 手机性能问题,定位时长设定太短的时候,没有来得及获取数据。
很明显,当我们了解了定位技术以后可以帮助我们很快的找到定位 Bug 的原因,缩小查询问题范围,快速找到问题答案;同时了解定位技术和定位方案也会帮助我们在以后制订定位方案的时候做取舍,按需找到最适合的一套方案。
PS:
最后最后,有个不成熟的小建议!!!
我们在组合定位的时候最好在每个定位技术里进行埋点或者做标记,这样就更容易帮助我们去统计各个定位方法的成功率和失败率,基于这些数据进行优化定位策略,也可以帮助我们快速去定位失败问题。