前言
最近在做一个h5项目,有涉及一个唤起三大地图(高德、腾讯、百度)导航的功能,说白了,就是找官方文档,调用API,真·API调用工程师🙃
但是呢,官方文档真的很乱……【找文档两小时,写代码五分钟>_<】,而且,随着官方文档的更新,不免有些坑😤
所以,本着踩过的坑不能再踩的原则,记录如下
项目需求
在H5页面中唤起地图导航
根据用户gps定位获取成功失败两种情况,目的地经纬度是确定已知的
-
成功
- 设备已安装APP,直接打开APP导航
- 设备未安装APP,唤起地图H5导航
-
失败
- 设备已安装APP,打开APP单点标注目的地
- 设备未安装APP,唤起地图H5单点标注目的地
问题关键点
- 设备是IOS还是安卓(调用的API不一样)
- 判断设备是否安装APP,是调用APP的API还是H5的API
- 根据用户GPS是否获取成功,进入不同模式(路线规划or单点标注)
调用的API
高德
-
无须区分设备是IOS还是安卓,都用一个接口
-
也无需手动判断是是否安装APP,官方提供callnative属性,先自动唤起H5,当设置callnative=1,装有APP的设备会被自动唤起,且调用的都是一个API
// 跳转高德地图
openGMap = () => {
const { latEnd, lonEnd, destination } = this.props;
const { usrLat, usrLon } = this.getGPSInfo();
// 获取到用户定位信息,走导航模式;未获取到用户定位信息,走单点标注模式
if (usrLat && usrLon) {
window.location.href = `https://uri.amap.com/navigation?from=${usrLon},${usrLat},我的位置&to=${lonEnd},${latEnd},${destination}&mode=driving&policy=1&src=mypage&coordinate=gaode&callnative=1`;
} else {
window.location.href = `https://uri.amap.com/marker?position=${lonEnd},${latEnd}&name=${destination}&src=mypage&coordinate=gaode&callnative=1`;
}
};
腾讯
-
无需区分设备是IOS还是安卓
-
需要区分设备是否安装APP,先尝试打开APP,利用延时,一秒后未打开,则认为设备未安装APP,打开H5
-
API中终点名称是必须的,终点的经纬度是可选的
// 跳转腾讯地图
openTMap = () => {
const { latEnd, lonEnd, destination } = this.props;
const { usrLat, usrLon } = this.getGPSInfo();
let mobileUrl = '';
let h5Url = '';
// 获取到用户定位信息,走导航模式;未获取到用户定位信息,走单点标注模式
if (usrLat && usrLon) {
mobileUrl = `qqmap://map/routeplan?type=drive&from=我的位置&fromcoord=${usrLat},${usrLon}&to=${destination}&tocoord=${latEnd},${lonEnd}&referer=${TMAP_KEY}`;
h5Url = `https://apis.map.qq.com/uri/v1/routeplan?type=drive&from=我的位置&fromcoord=${usrLat},${usrLon}&to=${destination}&tocoord=${latEnd},${lonEnd}&policy=1&referer=${TMAP_KEY}`;
} else {
mobileUrl = `qqmap://map/marker?marker=coord:${latEnd},${lonEnd};title:${destination};addr:${destination}&referer=${TMAP_KEY}`;
h5Url = `https://apis.map.qq.com/uri/v1/marker?marker=coord:${latEnd},${lonEnd};title:${destination};addr:${destination}&referer=${TMAP_KEY}`;
}
window.location.href = mobileUrl;
window.setTimeout(() => {
window.location.href = h5Url;
}, 1000);
};
百度
- 官方文档 lbsyun.baidu.com/index.php?t…
- 需要区分设备是IOS还是安卓
- 需要区分设备是都安装APP
- 需要地址转换 百度地图有自己的一套坐标系,需要或许密钥 lbsyun.baidu.com/index.php?t…
// 百度地图地址坐标系转换
transformH5Map = () => {
const { lonEnd, latEnd } = this.props;
const { usrLat, usrLon } = this.getGPSInfo();
fetchJsonp(`https://api.map.baidu.com/geoconv/v1/?coords=${lonEnd},${latEnd}&from=1&to=5&ak=${BMAP_KEY}`).then(res => res.json()).then((data) => {
this.lonStart = data.result[0].x;
this.latStart = data.result[0].y;
this.getCityStart();
this.getCityEnd();
}).catch(() => {
this.lonStart = usrLon;
this.latStart = usrLat;
});
fetchJsonp(`https://api.map.baidu.com/geoconv/v1/?coords=${usrLon},${usrLat}&from=1&to=5&ak=${BMAP_KEY}`).then(res => res.json()).then((data) => {
this.lonEnd = data.result[0].x;
this.latEnd = data.result[0].y;
this.getCityStart();
this.getCityEnd();
}).catch(() => {
this.lonEnd = lonEnd;
this.latEnd = latEnd;
});
};
- API需要参数需要起点和终点的城市名 lbsyun.baidu.com/index.php?t… 项目已知经纬度,需要根据经纬度获取城市名称
// 百度地图根据经纬度获取始发城市名称
getCityStart = () => {
fetchJsonp(`https://api.map.baidu.com/reverse_geocoding/v3/?ak=${BMAP_KEY}&location=${this.latStart},${this.lonStart}&output=json`).then(res => res.json()).then((data) => {
this.cityStart = data.result ? data.result.addressComponent.city : '深圳';
}).catch(() => {
this.cityStart = '深圳';
});
};
// 跳转百度地图
openBMap = () => {
const {
latStart, lonStart, latEnd, lonEnd, cityStart, cityEnd,
} = this;
const { destination } = this.props;
const sys = getSys();
// 获取到用户定位信息,走导航模式;未获取到用户定位信息,走单点标注模式
const urlCollect = {};
if (latStart && lonStart) {
const uri = `direction?origin=latlng:${latStart},${lonStart}|name:我的位置
&destination=latlng:${latEnd},${lonEnd}|name:${destination}&mode=driving&origin_region=${cityStart}&destination_region=${cityEnd}`;
urlCollect.H5 = `https://api.map.baidu.com/${uri}&src=webapp.baidu.openAPIdemo&output=html`;
urlCollect.Android = `bdapp://map/${uri}&src=andr.baidu.openAPIdemo`;
urlCollect.IOS = `baidumap://map/${uri}&src=ios.baidu.openAPIdemo`;
} else {
const uri = `marker?location=${latEnd},${lonEnd}&title=${destination}&content=${destination}`;
urlCollect.H5 = `https://api.map.baidu.com/${uri}&output=html&src=webapp.baidu.openAPIdemo`;
urlCollect.Android = `bdapp://map/${uri}&src=andr.baidu.openAPIdemo`;
urlCollect.IOS = `baidumap://map/${uri}&src=ios.baidu.openAPIdemo`;
}
window.location.href = urlCollect[sys];
if (sys === 'H5') return;
// 未安装app的补偿机制
window.setTimeout(() => {
window.location.href = urlCollect.H5;
}, 1000);
};
可优化点
- H5无法直接判断设备是否安装APP,用延时实现可能存在误差,原生APP具有这种能力,项目后期考虑调用原生APP接口进行判断