H5唤起地图导航总结

9,277 阅读2分钟

前言

最近在做一个h5项目,有涉及一个唤起三大地图(高德、腾讯、百度)导航的功能,说白了,就是找官方文档,调用API,真·API调用工程师🙃

但是呢,官方文档真的很乱……【找文档两小时,写代码五分钟>_<】,而且,随着官方文档的更新,不免有些坑😤

所以,本着踩过的坑不能再踩的原则,记录如下

项目需求

在H5页面中唤起地图导航

根据用户gps定位获取成功失败两种情况,目的地经纬度是确定已知的

  • 成功

    • 设备已安装APP,直接打开APP导航
    • 设备未安装APP,唤起地图H5导航
  • 失败

    • 设备已安装APP,打开APP单点标注目的地
    • 设备未安装APP,唤起地图H5单点标注目的地

问题关键点

  • 设备是IOS还是安卓(调用的API不一样)
  • 判断设备是否安装APP,是调用APP的API还是H5的API
  • 根据用户GPS是否获取成功,进入不同模式(路线规划or单点标注)

调用的API

高德
  • 官方文档 lbs.amap.com/api/uri-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`;
    }
  };
腾讯
  • 官方文档 lbs.qq.com/uri_v1/guid…

  • 无需区分设备是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);
  };
百度
 // 百度地图地址坐标系转换
  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;
    });
  };
  // 百度地图根据经纬度获取始发城市名称
  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接口进行判断