由来
一个客户提出一个需求,想在xiunobbs中实现,发帖时显示 定位信息,然后在查看时 可以实现,如果是Android或IOS端安装了百度地图APP的可以唤起,否则就和网页PC端的一样,直接跳转到网页版的百度地图并定位到改点。
简单实现步骤:
发帖时增加按钮,可以选择是否获取定位
将获取到的经纬度数值 通过 百度JavaScript API来逆向解析,得到省、市、县、街道等信息。
查看帖子时,将经纬度再次拼接成URI,供客户端唤起服务。
大致步骤如上吧,具体如何制作的xiunobbs插件这里就不谈了。
geolocation对象
该对象有三个方法:
注册一个位置改变监听器,每当设备位置改变时,返回一个 long 类型的该监听器的ID值。
取消由 watchPosition()注册的位置监听器。
增加按钮
这个不是本篇主要内容,也就一笔带过吧。
image.png
hook了post_message_after.htm 这个位置加入了
使用位置Secondary
获取当前定位
利用getCurrentPosition()方法来获取位置得到经纬度。
语法
navigator.geolocation.getCurrentPosition(success, error, options)
参数
success
成功得到位置信息时的回调函数,使用Position 对象作为唯一的参数。
error 可选
获取位置信息失败时的回调函数,使用 PositionError 对象作为唯一的参数,这是一个可选项。
options 可选
于是简单写了下代码
$(".get-location").click(function () {
// $(this).preventDefault();
var options = {
enableHighAccuracy : true,
maximumAge : 1000
};
// alert('this is getLocation()');
if (navigator.geolocation) {
//浏览器支持geolocation
console.log('support');
$(".location-str").removeClass("d-none");
$(".location-str").text("正在获取中……")
navigator.geolocation.getCurrentPosition(onSuccess, onError, options);
} else {
//浏览器不支持geolocation
alert('您的浏览器不支持地理位置定位');
}
return false;
});
onSuccess和onError分别如下
function onSuccess(position) {
// 用户位置字符串
var locationStr = "";
//返回用户位置
//经度
var longitude = position.coords.longitude;
//纬度
var latitude = position.coords.latitude;
$(".location-str").text('当前地址的经纬度:经度' + longitude + ',纬度' + latitude);
}
function onError(error) {
switch (error.code) {
case 1:
alert("位置服务被拒绝");
break;
case 2:
alert("暂时获取不到位置信息");
break;
case 3:
alert("获取信息超时");
break;
case 4:
alert("未知错误");
break;
}
}
这样简单的就能获取到经纬度了。
结合百度地图逆向解析
它给出的示例代码如下
var map = new BMap.Map("l-map"); // 这个是显示的div class类名 如果不显示无需写
map.centerAndZoom(new BMap.Point(116.404, 39.915), 11);
// 创建地理编码实例
var myGeo = new BMap.Geocoder();
// 根据坐标得到地址描述
myGeo.getLocation(new BMap.Point(116.364, 39.993), function(result){
if (result){
alert(result.address);
}
});
image.png
image.png
完善一下之前的onSuccess函数
function onSuccess(position) {
// 用户位置字符串
var locationStr = "";
//返回用户位置
//经度
var longitude = position.coords.longitude;
//纬度
var latitude = position.coords.latitude;
$(".location-str").text('当前地址的经纬度:经度' + longitude + ',纬度' + latitude);
var point = new BMap.Point(longitude, latitude);
var gc = new BMap.Geocoder();
gc.getLocation(point, function(rs) {
locationStr = rs.address;
$(".location-str").text(locationStr);
$("#location").val(locationStr + "|" + longitude + "|" + latitude);
console.log($("#location").val());
});
}
将之前获取到的经纬度,传参进入,调用这个方法,然后拿到解析后的address地址内容。将id为location的这个内容赋值为address字符串内容。(这个是为了提交到后端,下次读取帖子时可以拿到。PS:这里得注意下XSS)
显示效果:
image.png
(PC端不准,还有其他因素,结果定位到洛杉矶了):)
点击唤起百度地图APP
简单的定位也拿到了,然后该显示了。
hook显示位
这里还是简单带过下显示的地方,hook了thread_plugin_before.htm这个点。
list($location_str,$lng,$lat) = explode('|',$first['location']);
// 网页版
$baidu_pc_map_url = 'http://api.map.baidu.com/geocoder?location='.$lat.','.$lng.'&output=html&src=webapp.baidu.openAPIdemo';
// 安卓端
$android_url = 'bdapp://map/geocoder?location='.$lat.','.$lng.'&src=andr.baidu.openAPIdemo';
// IOS端
$ios_url = 'baidumap://map/geocoder?location='.$lat.','.$lng.'&src=ios.baidu.openAPIdemo';
?>
href="<?php echo $baidu_pc_map_url;?>" style="text-decoration: none;color: #fff;" id="location_url"><?php echo $location_str;?>
下面的js操作是hook的thread_js.htm。
唤起应用
唤起的逻辑简单如下:
PC端:直接显示百度地图web地址
Mobile端:
Android端:Android的百度地图APP
IOS|iPhone|iPad端:iOS的百度地图APP
利用uri的反向地址解析来完成,从手册中可以查到三个分别是
http://api.map.baidu.com/geocoder 网页
bdapp://map/geocoder?location 安卓
baidumap://map/geocoder?location IOS
然后就是利用JavaScript来判断下:
var browser={
versions:function(){
var u = navigator.userAgent, app = navigator.appVersion;
return {//移动终端浏览器版本信息
trident: u.indexOf('Trident') > -1, //IE内核
presto: u.indexOf('Presto') > -1, //opera内核
webKit: u.indexOf('AppleWebKit') > -1, //苹果、谷歌内核
gecko: u.indexOf('Gecko') > -1 && u.indexOf('KHTML') == -1, //火狐内核
mobile: !!u.match(/AppleWebKit.*Mobile.*/), //是否为移动终端
ios: !!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/), //ios终端
android: u.indexOf('Android') > -1 || u.indexOf('Linux') > -1, //android终端或者uc浏览器
iPhone: u.indexOf('iPhone') > -1 , //是否为iPhone或者QQHD浏览器
iPad: u.indexOf('iPad') > -1, //是否iPad
webApp: u.indexOf('Safari') == -1 //是否web应该程序,没有头部与底部
};
}(),
language:(navigator.browserLanguage || navigator.language).toLowerCase()
}
$("#location_url").click(function (event) {
event.preventDefault();
var web_scheme = "<?php echo $baidu_pc_map_url;?>";
var scheme = '';
if(browser.versions.mobile || browser.versions.ios || browser.versions.android ||
browser.versions.iPhone || browser.versions.iPad){
console.log('mobile');
if (browser.versions.ios || browser.versions.iPhone || browser.versions.iPad) {
scheme = "<?php echo $ios_url;?>";
}else if (browser.versions.android) {
scheme = "<?php echo $android_url;?>";
}
}else{
scheme = "<?php echo $baidu_pc_map_url;?>";
console.log('pc',scheme);
}
// 轮询判断能否唤起,如果不能唤起 则使用网页版
window.location.href = scheme;
var startTime = Date.now();
var count = 0;
var endTime = 0;
var t = setInterval(function () {
count += 1;
endTime = Date.now() - startTime;
if (endTime > 800) {
clearInterval(t);
}
if (count < 30) return;
if (!(document.hidden || document.webkitHidden)) {
window.location.href = web_scheme;
}
}, 20);
})
然后就可以唤起应用并显示标注了地图上的点。
Reference