HTML5提供了地理位置定位功能(Geolocation API),能确定用户位置,我们可以借助HTML5的该特性开发基于地理位置信息的应用。本文结合实例给大家分享如何使用HTML5,借助百度、谷歌地图接口来获取用户准确的地理位置信息。 查看演示 下载源码 如何使用HTML5地理位置定位功能 定位功能(Geolocation)是HTML5的新特性,因此只有在支持HTML5的现代浏览器上运行,特别是手持设备如iphone,地理定位 更加精确。首先我们要检测用户设备浏览器是否支持地理定位,如果支持则获取地理信息。注意这个特性可能侵犯用户的隐私,除非用户同意,否则用户位置信息是 不可用的,所以我们在访问该应用时会提示是否允许地理定位,我们当然选择允许即可。 function…
部分国行Android手机缺少谷歌GMS服务包导致HTML5 Geolocation无法定位的问题
最近项目上用到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的,暂时没有时间,以后可能会补充上来
原文地址: http://awebird.com/blog/art/24