由来

一个客户提出一个需求,想在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