部分国行Android手机缺少谷歌GMS服务包导致HTML5 Geolocation无法定位的问题

转载 2014年09月11日 22:54:15

最近项目上用到HTML5的geolocation用于定位,用Chrome和手头的手机测试好好的功能,到终端用户那里反馈一些手机不能定位,最后确定出是部分三星、摩托的部分国行Android手机“阉割”了谷歌GMS服务包,导致HTML5的geolocation无法使用wifi和基站定位服务导致。

值得一提的是前期在stackoverflow和google groups里搜到对症描述的解决方案(貌似Android 2.*或者三星自身的问题)全部失效,因为介是个“中国特色”的问题-_lll

首先介绍下HTML5的Geolocation功能。通常情况下,我们是先判断浏览器是否支持geolocation, 如果不支持,可以提示错误,或者进入其他逻辑处理流程,现在移动端的智能手机浏览器绝大部分都是支持的。

if( navigator.geolocation ){
    navigator.geolocation.getCurrentPosition(
        updateLocation, handleLocationError,
        {maximumAge:60000, timeout:50000, enableHighAccuracy:true}
        );
}else{
    alert( "对不起,您的浏览器不支持html5定位");
}

但是navigator.geolocation为true只是代表浏览器支持,浏览器还是要通过调用手机的定位功能来实现,所以上面的getCurrentPosition后面,分别后updateLocation和handleLocationError两个分支,分别对应成功而和失败的后续处理,这篇文章提到的由于缺少谷歌GMS服务包造成geolcation失效的情况就是走到了handleLocationError分支。

function handleLocationError(error) {
    switch(error.code){
        case 0:
          alert("获取位置信息出错!");
          break;
        case 1:
          alert("您设置了阻止该页面获取位置信息!");
          break;
        case 2:
          alert("浏览器无法确定您的位置!");
          break;
        case 3:
          alert("获取位置信息超时!");
          break;
    }
}

具体的返回值可以查手册,缺少谷歌GMS服务包的手机,会进入case 2,其实是“无法使用定位服务”。

写到这里,只是说明了原因,那有没有什么解决方案呢。搜索了下,原来提供地图和定位相关服务的不止是google一家,还有百度、高德、搜狗,下面介绍下百度的api

(1)百度地图javascript API geolocation

http://developer.baidu.com/map/jshome.htm

咋一看,百度js api也有自己的geolocation(http://developer.baidu.com/map/reference/index.php?title=Class:%E6%9C%8D%E5%8A%A1%E7%B1%BB/Geolocation) 这个取代html5自带的不就可以了么,经过实验,真是图样图森破了,原来所有的javascript API都还是调用的浏览器自身的geolocation进行封装实现的,也就是说如果原本不能wifi+基站定位,用百度、高德的javascript api的效果是一样的。

这里要说明的是,如果是开发Android原生软件的话,可以在APP里封装百度地图定位的SDK,这个是可以解决没有谷歌GMS服务包无法定位的问题的,因为百度地图定位SDK实际上是起到和谷歌服务包里面的定位模块一样的作用,由这里也可以看到HTML5 Webapp和原生APP的一个差别,不是一个层面的解决方案。

(2)使用百度的LocalCity() 根据IP定位到城市

既然上面说的HTML5自带的geolocation和百度Javascript API的geolocation都不能用了,那么就完全不能定位了么,我们这里暂时采用了一个方案,就是使用百度的LocalCity接口,进行IP定位,可惜这个只能返回城市和市中心的坐标,对于需要精确定位的LBS产品基本没有意义(根源上IPv4时代通过IP定位的想法本来就不是很靠谱吧),但是对我们的产品不失为一种可以接收的降级方案,当然用户体验上需要通过文字说明或者弹窗的形式告知用户一。

function myFun(result){
    var latitude = result.center.lat;
    var longitude = result.center.lng;
 
    //doSomething(latitude,longitude);
}
var myCity = new BMap.LocalCity();
myCity.get(myFun);

(3)使用百度的IP定位API

http://developer.baidu.com/map/ip-location-api.htm

var ajaxObj = createXHR();
ajaxObj.onreadystatechange = function() {
    if (ajaxObj.readyState == 4) {
        if ((ajaxObj.status >= 200 && ajaxObj.status < 300) || ajaxObj.status == 304) {
            var jsonObj = eval("(" + ajaxObj.responseText + ")");
            var point_x=jsonObj.content.point.x;
            var point_y=jsonObj.content.point.y;
            var axis = new BMap.MercatorProjection().pointToLngLat(new BMap.Pixel(point_x,point_y));
 
            var latitude = axis.lat;
            var longitude = axis.lng;
 
        //doSomething(latitude,longitude);
        }
    }
};
ajaxObj.open("POST", "http://www.awebird.com/get_ip.php", true);
ajaxObj.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
ajaxObj.send("sendmessage=");

这理论上讲应该是个更好的解决方案,但是从实际使用测试来看,由于IP定位的局限性,实际上虽然返回的坐标不是市中心,但是也基本没有参考价值,所以只是把实现方法列一下,或许等到IPv6时代会有用吧。

这个api有几个值得注意的地方

(1)由于安全起见,所以Javascript是不支持直接获取IP地址的,所以需要服务器端,此外,如果手机程序是webapp或者和服务器不在一个域的话,还需要跨域支持,我们这里使用的是CORS跨域,get_ip.php如下(包括获取IP地址,和根据IP请求百度IP定位API获得城市信息)

<?php
    $client_ip = getRealIpAddr();
    $baidu_result = file_get_contents('http://api.map.baidu.com/location/ip?ak=6227cb21d6ab31a87a5ae231f7xxxxxx&ip='.$client_ip);
    //注意上面的ak最后6位略去,需要使用自己免费注册的百度api的ak
    header("Access-Control-Allow-Origin: *"); //CROS跨域
    header("Content-Type:text/html; charset=utf-8");
    echo $baidu_result;
 
    function getRealIpAddr(){
        if (!empty($_SERVER['HTTP_CLIENT_IP'])){
            $ip=$_SERVER['HTTP_CLIENT_IP'];
        }elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])){
            $ip=$_SERVER['HTTP_X_FORWARDED_FOR'];
        }else{
            $ip=$_SERVER['REMOTE_ADDR'];
        }
        return $ip;
    }

(2)百度IP定位API获得的坐标point需要经过坐标系转换成lat lng采用和其它接口公用

参见上面js里的

var axis = new BMap.MercatorProjection().pointToLngLat(new BMap.Pixel(point_x,point_y));
 
var latitude = axis.lat;
var longitude = axis.lng;

好了,本来还准备放一个DEMO的,暂时没有时间,以后可能会补充上来

关于cordova开发中安卓定位不精确的解决方案

在使用cordova开发移动app的时候会遇到定位的问题,cordova提供了自己的cordova-plugin-geolocation插件,这个插件在ios上面定位不会出现问题,但是在安卓手机上会出...
  • u010730897
  • u010730897
  • 2016-07-28 15:30:34
  • 3774

高德地图 AMap.Geolocation

AMap.Geolocation:定位插件,整合了浏览器定位、精确IP定位、sdk辅助定位多种手段 官方说明:AMap.Geolocation定位服务插件。融合了浏览器定位、高精度IP定位、安卓定...
  • ooiuy450
  • ooiuy450
  • 2017-03-27 22:40:32
  • 3116

使用百度地图定位当前城市,在浏览器中可以,但是在安卓webview中定位失效

使用百度地图,定位当前所在城市,发现在浏览器中,定位很快,但是把html页面放到webview中,就一直定位不到坐标function getCurPosition() { var error_msg...
  • u010394015
  • u010394015
  • 2016-07-29 10:03:52
  • 5581

Android使用WebView无法定位问题的解决方法

网页端能够实现定位 但是移植到手机app上使用webview访问时定位失败 解决方法如下: //启用数据库 webSettings.setDatabaseEnabled(true);...
  • sosohotsummer
  • sosohotsummer
  • 2015-01-07 09:36:57
  • 4112

完美解决window.navigator.geolocation.getCurrentPosition,在IOS10系统中无法定位问题

目前由于许多用户都将电话升级到了IOS系统,苹果的iOS 10已经正式对外推送,相信很多用户已经更新到了最新的系统。然而,如果web站没有及时支持https协议的话,当很多用户在iOS 10下访问...
  • for12
  • for12
  • 2016-10-13 09:33:41
  • 21373

android webview 获取geolocation

1.permission               2.             webview = (WebView) findViewById(R.id.。。。)...
  • fhy_2008
  • fhy_2008
  • 2011-11-16 16:46:17
  • 4817

部分国行Android手机缺少谷歌GSM服务包导致HTML5 Geolocation无法定位的问题

最近项目上用到HTML5的geolocation用于定位,用Chrome 和手头的手机测试好好的功能,到终端用户那里反馈一些手机不能定位,最后确定出是部分三星、摩托的部分国行Android手机“阉割”...
  • kaosini
  • kaosini
  • 2013-07-18 13:24:14
  • 2883

iphone手机微信端html5 Geolocation定位失效的问题

使用Geolocation方法存在错误信息error.POSITION_UNAVAILABLE 其实问题不局限于微信端而是iphone升级到ios10后,对获取地理位置信息作出了限制,只有https的...
  • sinat_33157758
  • sinat_33157758
  • 2016-10-20 10:49:26
  • 6476

使用navigator.geolocation来获取用户的地理位置信息

来源:http://js8.in/672.html W3C 中新添加了一个名为 Geolocation的 API 规范,Geoloaction API的作用就是通过浏览器获取用户的地理位置。我们...
  • load_life
  • load_life
  • 2012-02-20 09:26:46
  • 735

html5 geolocation / 百度地图api Geolocation 定位当前城市信息

今日开端:  根据当前所处位置 定位所在城市信息    刚开始采用html5的 geolocation 来获取当前所在经纬度   折腾一番终不能获取城市信息 只能获取到当前的经纬度    查找...
  • Q718330882
  • Q718330882
  • 2015-08-07 11:53:53
  • 21374
收藏助手
不良信息举报
您举报文章:部分国行Android手机缺少谷歌GMS服务包导致HTML5 Geolocation无法定位的问题
举报原因:
原因补充:

(最多只允许输入30个字)