http://www.iirr.info/blog/?p=1265
前言
从苹果、安卓等智能手机快速普及的那一天起,由于国内各种特别的行情,有关手机定位的问题一直困扰着普通用户和开发者。比如,安卓手机为什么总不能使用网络定位?NetworkLocation.apk是什么?为什么外国app的地图显示出来的总是偏移的?本文试图以回答这些问题,给普通用户和开发者(尤其是移动开发者)一些指引,并且提出一些自己的思考。由于本人并非GIS从业者,所以也许会有错漏,敬请指正。
本文阅读人群:
智能手机普通用户、移动应用从业者(开发者)
================================================
如果是安卓手机/平板的深度使用用户,必定会对许多手机定位(尤其是冷启动定位)的速度不敢恭维、甚至说基本是废的(除了某些专用于导航的安卓设备);雪上加霜的是,由于各种行情,手机中的网络定位许多也不能正常工作的。论坛上各种标榜“秒定”(秒速定位)的rom随处可见,究竟是如何做到的?
这系列的第一篇,主要讲的是安卓系统中,网络定位的那些事情。在此之前,先对全系列的一些要点提前解读。
GPS、GLONASS、北斗和GNSS
说起定位,大家第一时间联想到的是美国的GPS。但实质上,俄罗斯的GLONASS、中国的北斗、欧盟的Galileo等也在做一样的事情。其实,他们都同属GNSS(Global Navigation Satellite System、全球导航卫星系统)的领域下。
一些GNSS的简要介绍如下:
(1)GPS(Global Positioning System)是美国的全球定位系统,其坐标系是WGS-84。
(2)GLONASS是俄罗斯的格洛纳斯系统,其坐标系是PZ-90。[1]
(3)中国的北斗,其坐标系是CGS2000。
……
现在集成GPS + GLONASS的双GNSS定位芯片和设备已经成为了某些设备的新卖点,比如小米手机2[2]、Garmin eTrex 30[3]等。展望未来,混搭GNSS会是主流方向(甚至已经出现了MT3332/MT3333五合一方案[4]),有GIS从业者也提出应该让“GNSS”取代“GPS”成为新的定位名词[5]。
但是…….鉴于当前许多设备还是基于GPS芯片和系统运行,许多用户还是更熟悉“GPS”而不是“GNSS”这个名词,故而下面,也就只讲述GPS和与之相关的定位技术了。
网络定位、A-GPS和GPS的关系
要讨论安卓智能手机的定位,一定离不开三个词:网络定位、A-GPS和GPS。他们之间的关系如下:
网络定位(此处特指安卓“设置”中给出的概念)(包括非卫星参与的移动基站定位、WiFi定位) | A-GPS(Assisted GPS) | GPS | |
设备是否需要联网(WIFI/2G/3G等) | 需要 | 需要 | 不需要 |
定位源/数据源 | 移动基站、wifi等无线基站信息 | 移动基站、wifi等无线基站信息 | 卫星 |
系统独立性 | 可单独使用 | 目标是为了令GPS定位更快更精准,不可单独使用 | 可单独使用 |
定位速度 | 快(需视乎网络速度、与位置服务器连接的情况) | 目标是为了令GPS定位更快更精准,不能比较(辅助GPS的速度:需视乎网络速度、与位置服务器连接和通讯的质量) | 相对其它两个较慢(如果A-GPS工作良好,也比较快) |
定位精度 | 低(需要视乎数据源提供商) | 目标是为了令GPS定位更快更精准,不能比较(辅助GPS的精度:需要视乎数据源提供商) | 高(需视乎定位芯片和天线接收质量) |
(安卓)所属开发层 | 应用程序框架层(<=4.0.x / 4.1.x / 4.2.x三大开发方式接入LocationProviderProxy) + platform级签名 | Linux内核层(驱动级开发)(需搭配GPS驱动一并开发) | Linux内核层 + 应用程序框架层(需继承LocationProvider派生出GpsLocationProvider等)(驱动级开发) |
以上的关系,后面再展开阐述。现在进入本文的主题:网络定位。
网络定位简介
在安卓的设置中,“网络定位”是指利用手机基站信息、wifi信息等(一般有网络制式、MCC、MNC、MAC、WIFI SSID等维度;ip极少参与其中)发送到指定的位置服务器;位置服务器接收后,直接返回粗略的经纬度和精度信息。整个过程中其实就是“根据IP地址获取地址”的高级版,而且手机端无需定位卫星的信号,做到低耗电定位(所以说,网络定位的本质,其实和GPS乃至AGPS都没什么关系)。
(网络定位在HTML5的例子,手机点此链接访问该页面,可测试网络定位是否正常)
从上面可以看到,要实现网络定位,位置服务器是必须的,但这部分一般都在地图资源商的手中,手机/平板制造商不可能有这种资源。他们只能通过和地图资源商进行商务合作或者取得授权,才能够合法地放入网络定位的相关底层应用和分发使用权,否则会被视为侵权使用。国内常见的网络定位目前有两种:
(1)Google GMS(Google Mobile Service)中的网络定位服务(许多人可能更加熟悉NetworkLocation.apk)。但国内行货由于众多原因,目前没有一家通过GMS认证,所以一定不会有这个服务(换句话讲,也不会有这个文件)。即使有,其实也是在灰色使用状态,不能太声张——之前曾有一次,小米放入这个文件,结果引发同行批评[7]。也有rom制作者与刷机发烧友等尝试自行刷入这个GMS的网络定位,这部分遇到的技术问题下文再表。
(2)百度地图的网络定位服务(一般为NetworkLocation_Baidu.apk或者BaiduNetworkLocation.apk)。目前有部分国行和部分rom采用。这满足了国行不能使用GMS、但又希望使用网络定位的需求。至于有没有坐标偏移,手头没有机器,没有测试。
网络定位的开发与故障
在应用开发上,要使用网络定位,必须要在AndroidManifest.xml申明“android.permission.ACCESS_COARSE_LOCATION”的uses-permission;同时也要求手机联网完成获取。但是如果网络定位服务不存在或者异常,则不会返回任何信息。典型的情况是,使用HTML5的navigator.geolocation.getCurrentPosition,总会返回PositionError.code为3的Timeout expired(即超时)。(注意:网络定位服务不可用并不影响HTML5对GPS设备的数据读取;如果GPS成功获取当前高精度坐标并正常运行、且html5代码申请了enableHighAccuracy: true,则HTML5也能正常读取GPS的数据并显示)
在底层开发上,要实现网络定位,不同的安卓版本、甚至不同的机型都有不同的实现方式。但归根到底都要最终实现“以Provider+Service方式接入LocationProviderProxy”的目标,而且相关接入应用必须以platform级别证书签名,否则不能运行。从大版本来看,有三大实现模式,有兴趣的开发者可照附录一的简表自行查看源代码。
附录一:网络定位的底层开发简表
LocationManagerService类重要关注方法:
android版本 | LocationManagerService类重要关注方法 | 源代码位置(相对于https://android.googlesource.com/platform/frameworks/base/+/ 或者 https://github.com/android/platform_frameworks_base/tree/ ) | 反编译的文件和位置 |
<= 4.0.x | LocationManagerService(Context context);_loadProvidersLocked(); | /{<=4.0.x的分支}/services/java/com/android/server/LocationManagerService.java | (暂未找寻) |
4.1.x | LocationManagerService(Context context);findBestPackage(String serviceIntentName, String sigPackageName);_loadProvidersLocked(); | /{4.1.x的分支}/services/java/com/android/server/LocationManagerService.java | (暂未找寻) |
4.2.x | LocationManagerService(Context context);loadProvidersLocked();ensureFallbackFusedProviderPresentLocked(ArrayList<String> pkgs); | /{4.2.x的分支}/services/java/com/android/server/LocationManagerService.java | (暂未找寻) |
网络定位配置:
android版本 | 配置字符串 | 源代码位置(相对于https://android.googlesource.com/platform/frameworks/base/+/ 或者 https://github.com/android/platform_frameworks_base/tree/ ) | 反编译/system/framework/framework_res.apk位置 |
<= 4.0.x | config_networkLocationProvider | /{<=4.0.x的分支}/core/res/res/values/config.xml | /res/values/strings.xml |
4.1.x | config_networkLocationProviderPackageName | /{4.1.x的分支}/core/res/res/values/config.xml | /res/values/strings.xml |
4.2.x | config_locationProviderPackageNames | /{4.2.x的分支}/core/res/res/values/config.xml | /res/values/arrays.xml |
从4.1.x开始,网络定位还必须实现统一指定的Intent Action,否则不予运行:
android版本 | 统一指定的Intent Action | 源代码位置(相对于https://android.googlesource.com/platform/frameworks/base/+/ 或者 https://github.com/android/platform_frameworks_base/tree/ ) | 反编译的文件和位置 |
4.1.x | public static final String SERVICE_ACTION = “com.android.location.service.NetworkLocationProvider”; | /{4.1.x的分支}/services/java/com/android/server/location/LocationProviderProxy.java | (暂未找寻) |
4.2.x | private static final String NETWORK_LOCATION_SERVICE_ACTION = ”com.android.location.service.v2.NetworkLocationProvider”;private static final String FUSED_LOCATION_SERVICE_ACTION = ”com.android.location.service.FusedLocationProvider”; | /{4.2.x的分支}/services/java/com/android/server/LocationManagerService.java | (暂未找寻) |
[1]GPS、GLONASS卫星坐标计算和导航应用研究:http://wenku.baidu.com/view/5c00b92a0066f5335a8121d8.html
[2]小米手机2:http://www.xiaomi.com/mi2
[3]Garmin eTrex 30:http://www.garmin.com.cn/products/onthetrail/etrex301Outdoor/
[4]联发科技发布全球首颗支持中国北斗卫星的五合一全球导航卫星系统接收器SoC解决方案(2013-01-28):http://www.mtk.com.tw/_cn/03_news/01-2_newsDetail.php?sn=1094
[5]“应该用GNSS全面代替GPS名词”:http://weibo.com/2154494070/ztN2ZjrsG
[6]利用Google接口实现网络定位NetworkLocation(基站定位、WiFi定位):http://my.oschina.net/u/617626/blog/71043