ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

微信小程序路线规划导航全攻略:从地图绘制到唤起高德百度App

微信小程序路线规划导航全攻略:从地图绘制到唤起高德百度App 微信小程序里的“路线规划导航”这个需求我做了好几轮了从最早的自营配送业务到后来帮客户做的门店到店导航几乎每一次都会踩到同一个坑你以为是要在小程序里做个导航实际上用户真正想要的是“路线有人帮我算好然后把车导到目的地”。整个微信小程序的定位能力、路线规划能力、以及调起第三方导航App的能力其实是三件事很多人一上来就混在一起做结果卡在权限、坐标、配置这些细节上反复折腾。这篇文章就把我沉淀下来的一整套做法完整拆开讲清楚。适合正在做同城配送、到店导航、地图关联类小程序的同学参考哪怕你连腾讯位置服务都没接听过照着走也能把“小程序内看路线 一键唤起高德/百度导航”这条路打通。文章里会涉及具体参数、接口选择、坐标转换还有一些只有真机跑过才会知道的隐性坑。1. 先想清楚小程序里做导航到底该走哪条路很多产品经理提需求的时候只说一句“在小程序里加个导航”但落到开发头上就麻烦了。导航这个词在小程序里有三种完全不同的解释理解错了后面全是返工。1.1 三种“导航”的边界第一种叫地图展示就是在地图上打一个点告诉用户“店在这里”一般用wx.openLocation就够了一个API搞定不用接任何第三方地图SDK。这种方式做得最浅但它解决不了“用户不知道路怎么走”的问题。第二种叫路线规划意思是用户有起终点我给他算出一条驾车或者步行路线在地图上画出这条线同时告诉他“大约8.5公里预计25分钟过路费10块”。路线规划在小程序内就能完成腾讯位置服务、高德地图、百度地图都提供了对应的JavaScript SDK前端直接调用不需要自己写复杂的地理计算。第三种才是真正的导航也就是实时语音播报、路口放大、车道级引导这一整套。这种能力不可能在小程序内完整实现就算做出来体验也极差。行业里的通用做法是小程序负责把起点、终点、路线类型这些参数算好然后通过URL Scheme、Universal Link或者辅助功能把用户引导到高德App、百度地图App里去完成最终导航。微信小程序的核心价值是“最后一公里的连接”不是“全程导航”。小程序提供位置上下文、路线预览和决策信息真正的导航交给更专业的App去做这才是用户愿意用的产品形态。1.2 先确认你的场景该做多深接需求的时候先问清楚这几个问题它们直接决定你的开发量用户是步行的访客还是开车的司机步行就直接调wx.openLocation兜底不需要复杂的路线绘制驾车场景才需要考虑路线方案推荐和调起App。起终点是否固定门店类的小程序起点通常取用户当前定位终点是门店坐标如果是配送类两端都是动态坐标就需要在服务端算或多点路线。用户需要看到几条备选路线吗腾讯位置服务和百度地图都能返回多条路线方案如果你产品上只展示一条“推荐路线”代码量会少很多。需要跨平台兼容吗你的小程序如果同时跑在安卓和iOS上调起App的逻辑必须分开处理因为两个系统的跳转协议不一样。我的建议是第一条版本先做“小程序内路线绘制成功 高德/百度 App 唤起成功”把最高频的路径打通后续再根据用户反馈迭代方案选择、途经点、语音包这些锦上添花的功能。任何复杂度的路线规划导航在微信小程序里绕不开两个底层依赖地图服务商的选择、以及位置相关权限的开通。这两块准备不好后面写什么代码都是白搭。2. 地图服务接入的底层准备2.1 选择哪个地图服务商微信小程序里可以用的地图提供商有好几家但选择逻辑其实很简单你主要使用微信生态就必须考虑和wx系列的API兼容性首选腾讯位置服务。为什么这么说小程序里最常用的地图能力接口是wx.getLocation拿用户坐标和wx.openLocation打开内置地图这两个API走的是腾讯的地图数据。如果你在腾讯位置服务申请的Key坐标系直接统一不用做转换如果选了百度地图你拿到的wx.getLocation坐标是GCJ-02坐标系而百度地图用的是BD-09坐标系中间还要做一步坐标转换代码凭空多一堆Bug源。当然如果你的业务强依赖百度地图的某个能力比如百度路况数据、百度POI检索那也可以用百度地图小程序SDK无非就是多处理一次坐标系转换。高德在小程序端没有官方JavaScript SDK通常要封装Rest API灵活度高一些但开发量也更大。我自己的选择是能力点首选方案备选方案小程序内获取定位wx.getLocation腾讯系高德/百度定位SDK逆地址解析坐标转文字腾讯位置服务 WebService API高德 Rest API路线规划驾车/步行/骑行腾讯位置服务小程序JavaScript SDK百度地图小程序SDK调起第三方App导航高德/百度/腾讯的URL Schemeweb-view 方案兜底能力wx.openLocation内置地图组件这里有个使用上的小提醒腾讯位置服务里路线规划能力虽然在小程序JavaScript SDK里可以调用但这个API需要你在腾讯位置服务控制台开通“WebServiceAPI”权限并且把域名加入小程序后台的request合法域名。很多同学第一次调用报invalid sign或者request:fail url not in domain list十有八九就是这两步没配。2.2 权限与隐私相关配置微信小程序对位置信息的管控非常严格不只是前端调wx.getLocation时弹个授权框那么简单。首先小程序后台的功能页面里“位置信息”接口必须在“设置-接口设置”中申请开通。如果你调wx.getLocation没反应先去看是不是这个接口没被审核通过。首次提交代码时会有一个“用户隐私保护指引”的填写其中“位置信息”这一项必须勾选并说明用途比如“用于展示附近门店并规划路线”。这块拖着不填真机调试时wx.getLocation会直接返回fail而且报错信息在模拟器里看不见很误事。其次Android端有些用户手机里关闭了“精确定位”或者微信的定位权限被系统限制这些都不是小程序代码能解决的问题要能在异常回调里给用户提示“请在系统设置中开启精确定位”并引导用户去门店页看地址文字信息避免用户卡死在授权页。我一直坚持在页面加载前就处理好这块而不是等到用户点击“导航”才去授权。把位置权限放在页面级尽早触发用户心智上觉得这是“为了帮你找店”而不是“为了获取你隐私”转化率会好很多。3. 核心实现在小程序内完成路线预览场景理清楚了底层准备也做完了这一章进入真正的代码实现。我会以腾讯位置服务为主要示范因为整体链路最顺同时在关键节点讲讲百度地图版本的差异方便你迁移。3.1 引入地图组件与SDK第一步是在页面的JSON文件里声明地图组件{ navigationBarTitleText: 路线规划, usingComponents: {}, disableScroll: true }然后在 WXML 中放置地图组件map idrouteMap classroute-map latitude{{currentLat}} longitude{{currentLng}} scale{{mapScale}} show-location{{true}} markers{{markers}} polyline{{polyline}} bindregionchangeonRegionChange /map地图组件的polyline绑定的是绘制路线的数据组markers用来标记起点、终点和途经点。注意图中的箭头图标之类可以用iconPath配置本地或者网络图标网络图标需要在小程序后台配 downloadFile 合法域名。接着在小程序项目中引入腾讯位置服务的小程序JavaScript SDK。这个SDK官方叫qqmap-wx-jssdk.min.js下载下来放到项目的utils目录里然后在页面里引入const QQMapWX require(../../utils/qqmap-wx-jssdk.min.js); const qqmapsdk new QQMapWX({ key: 你的腾讯位置服务Key });这里有个细节qqmap-wx-jssdk的旧版本曾经有一些Promise兼容问题在较新版本的基础库里已经处理过了但如果你用了比较旧的基础库建议把回调改成Promise包裹的方式避免回调地狱。3.2 获取当前定位组装路线请求参数进入页面后第一步永远是先拿用户当前位置。用wx.getLocation拿到的是经纬度但这个坐标是 GCJ-02 火星坐标不要直接拿它和 GPS 原始坐标去算距离否则结果会差几百米到几公里不等。wx.getLocation({ type: gcj02, isHighAccuracy: true, highAccuracyExpireTime: 4000, success: (res) { this.setData({ currentLat: res.latitude, currentLng: res.longitude }); this.loadRoute(); }, fail: () { wx.showToast({ title: 获取定位失败, icon: none }); } });拿到坐标之后调腾讯位置服务的路线规划接口。这里需要特别说明腾讯位置服务的JavaScript SDK支持direction系列接口比如qqmapsdk.direction()但更推荐的是qqmapsdk.calculateDrivingRoute()或者calculateWalkingRoute()因为它们的参数更语义化返回结构也更稳定。loadRoute() { const endLat this.data.endLat; const endLng this.data.endLng; qqmapsdk.calculateDrivingRoute({ mode: driving, from: { latitude: this.data.currentLat, longitude: this.data.currentLng }, to: { latitude: endLat, longitude: endLng }, success: (res) { this.handleRouteResult(res); }, fail: (err) { console.error(路线规划失败, err); } }); }这个接口返回的数据里res.result.routes是路线方案数组每个方案里包含distance、duration、tolls以及polyline字符串。polyline是编码后的坐标串需要在客户端解码成[{latitude, longitude}, ...]才能给地图组件的polyline属性使用。3.3 解码polyline并绘制路线解码逻辑在腾讯位置服务官方Demo里就有本质上是Google Encoded Polyline 算法的变体只是加了一个36进制的偏移处理。腾讯返回的polyline是enc:xxxxx开头官方SDK里有decode()方法直接调用即可handleRouteResult(res) { const route res.result.routes[0]; const points qqmapsdk.decode(route.polyline); const coors points.map(p ({ latitude: p.latitude, longitude: p.longitude })); this.setData({ polyline: [{ points: coors, color: #228BFF, width: 6, arrowLine: true }], markers: this.buildMarkers(), distanceText: this.formatDistance(route.distance), durationText: this.formatDuration(route.duration), tollText: route.tolls ? 收费约${route.tolls}元 : 免费路线 }); }这里要特别提醒decode出来的坐标点数量可能上千个一次性全部setData会导致渲染卡顿尤其是在低端安卓机上。我实际项目里的处理是如果coors.length 200就隔一个点取一个或者用抽稀算法保留关键形状点。路线绘制追求的是形状正确不是点数量多抽稀后视觉差异很小但性能天差地别。地图的markers我通常在起点和终点各放一个图标颜色区分开终点用callout展示门店名称这样用户一眼就能看懂规划结果。3.4 展示路线概要信息和切换方案路线规划接口返回的不止一条路线方案默认会有多条比如“推荐路线”“备选路线”。从产品体验上讲最好把距离、时间、费用这些关键信息展示出来让用户可以选择。我做得比较多的一种交互是底部弹出一个半透明的卡片里面展示三套方案每套一行展示“距离 / 预计时间 / 费用”用户点某一行地图上就切换绘制对应的polyline。这个交互对用户的决策帮助很大因为很多时候用户愿意多开500米去避开一段收费路。在代码层面就是把handleRouteResult里的逻辑改成保存所有routes点击方案时重新设置setData({ polyline: [...] , activeIndex })而已。核心注意点在于切换时地图的scale要把整条路线包进视野里否则用户会迷路。我习惯做法是调用地图上下文的includePoints方法const mapCtx wx.createMapContext(routeMap, this); mapCtx.includePoints({ points: coors, padding: [60, 60, 60, 60] });这样不管路线多长都能完整显示在屏幕里。这里有个小坑includePoints必须在路线绘制完成后调用否则空白一闪而过。所以一定要让polyline设置完成后再执行includePoints可以用wx.nextTick包一层。到此为止小程序内的路线预览已经完成。接下来就是整篇文章的重头戏如何把这套路线接出去让用户一键打开高德或者百度App去真正导航。这一步涉及的平台配置比较多也是很多团队最后卡住的地方。4. 核心实现拉起第三方导航App微信小程序在唤起第三方App这件事上限制比H5网页大得多。H5里你用window.location.href跳一个androidamap://协议可能就生效了但小程序里想调到高德App必须走正经路子。4.1 三种主流的唤起路径路径一wx.openLocation兜底。它只能打开微信自带的地图页面里面会有一个“导航”按钮点击后会唤起用户手机上已安装的第三方地图。这个方案的优点是不用任何额外配置缺点是你无法控制唤起的是哪家App也无法把路线方案的偏好传进去。适合作为活动页、分享页的低成本兜底。路径二使用navigator组件的open-typelaunchApp。这是小程序官方推荐的唤起App方式需要你在小程序后台的“关联设置”里把目标App比如高德地图关联进来同时App侧要处理好微信开放平台的 Universal Link。这个方案稳定性最高但你得有高德App的控制权并且要拿到微信开放平台的配置权限。实际开发中普通开发者在公司内申请App关联权限是非常耗时的很多人在这里卡了几周。路径三通过 URL Scheme / Universal Link 直接跳。高德、百度、腾讯地图都提供了开放平台的调起协议。在小程序里可以用条件编译或wx.navigateToMiniProgram如果是跳小程序之外的方式通过location.href或web-view内跳转来触发。遗憾的是微信会拦截非白名单的 scheme所以纯web-view里调高德方案在iOS端的表现经常是不可用。真正在生产环境比较稳定的是组合方案登录控制走 launchApp降级方案走 wx.openLocation。我的经验是如果你的核心诉求是“用户点导航之后能拿到好的体验”不要试图在小程序内直接强制唤起App而是做一个“导航方式选择页”——让用户在高德、百度、腾讯地图里挑一个能唤起App的最好唤起不了就跳H5地图页面继续。4.2 各家地图的唤起参数假设你决定直接通过URL Scheme来唤起第三方导航App下面是三家常用的参数规则。高德地图高德地图的调起协议是androidamap://navi?sourceApplication你的应用名lat39.983424lon116.322987poiname目的地名称dev0style2其中dev0表示传入坐标是GCJ-02坐标系style2表示使用高德推荐路线。这个协议在安卓上可以直接用window.location.href触发在iOS上需要搭配配置好的 Universal Link否则微信内置浏览器会拦截。从微信小程序里安全触发的做法是用wx.navigateToMiniProgram跳到高德地图的小程序版不对高德没有小程序。实际用的是以下两种之一用web-view加载一个自己写的H5页面H5页面里再location.href androidamap://...但微信对web-view里的跳转拦截非常强iOS上基本无解。是走微信的“小程序跳转App”链路也就是open-typelaunchApp让用户授权后唤起高德App。这是目前小程序端唯一被官方认可的稳定方式。简单总结小程序里想直接跳进高德/百度App别指望纯前端方案一定要在微信后台做好目标App的关联。百度地图百度地图的调起协议baidumap://map/direction?destinationlatlng:43.073145,12.554564|name:目的地名coord_typegcj02modedrivingsrc你的应用名这个协议和上面高德类似唯一提醒的是coord_type参数默认是bd09ll如果你传入的是GCJ-02坐标必须显式写coord_typegcj02否则位置会偏移几百米。很多人在这个参数上翻车。腾讯地图腾讯地图的调起协议qqmap://map/routeplan?typedrivefrom我的位置fromcoord39.914889,116.391387to目的地名称tocoord39.983424,116.322987referer你的应用名腾讯地图支持从当前定位开始规划fromcoord可以不传相对更宽容。4.3 实现“选择导航App”交互既然直接唤起App在大多数场景下做不到全自动我们就要在产品层做出取舍。我现在的默认交互是这样设计的用户点击“开始导航”按钮先判断wx.getSystemInfoSync().platform。在安卓端尝试直接调用第三方App的URL Scheme记录canIUse或加了超时失败判断。在iOS端因为微信拦截直接引导用户使用wx.openLocation自带导航按钮简单可靠。同时页面底部展示一行提示“如果您手机上装有高德/百度地图可在系统浏览器中打开本页面唤起导航。”这个方案的优点是把复杂度拆分到平台层避免一个方案跑崩了整个流程。用户体验上虽然多了一个选择步骤但不容易出现“点了没反应”的致命问题。如果你想要更强大的App唤起能力可以了解一下微信的WeixinJSBridge或云开发能力但它们要么依赖宿主App装微信SDK要么需要后端配合对纯前端小程序来说成本偏高不展开。5. 权限、隐私与真机调试的避坑清单这一章是真正把项目从demo推到线上会遇到的摩擦地带。我把自己踩过的问题整理成一个checklist每一个都是真实项目里跑出来的可以对照检查。5.1 隐私保护指引不填就失败小程序在调用wx.getLocation、wx.chooseLocation这类接口时微信会检查你是否已经更新了用户隐私保护指引。如果你进入“小程序后台-设置-服务内容声明-用户隐私保护指引”发现没有勾选“位置信息”并填写用途那么真机上的wx.getLocation会大概率失败报错是fail api scope is not declared in the privacy agreement。这个报错在开发工具模拟器里有时候不出现但真机调试一定会遇到。所以我的习惯是在接入位置相关功能的第一天就把隐私保护指引先更新掉避免后续联调时到处排查。5.2 合法域名趋严的趋势腾讯位置服务的WebService API、以及如果你的地图数据有部分要自己服务器下发都必须在小程序后台配置request合法域名。调wx.request时如果报url not in domain list就是这里没配。这里多说一句开发工具里可以勾选“不校验合法域名”来临时调试但千万别在开发环境之外长期依赖这个选项。曾经有一个项目就是因为一直靠这个选项跑真机调试上线后用户端全部请求失败排查了很久才发现正式环境没配域名。5.3 苹果手机位置错误与坐标漂移热词里出现了“苹果手机位置错误”这一点确实很典型。iOS上wx.getLocation返回的精度受多因素影响包括系统定位服务开关、是否开启了“精确位置”、网络定位的缓存等。我遇到的情况是用户手机在室内通过Wi-Fi定位返回的坐标漂了快一公里路线规划结果自然完全不对。针对这个问题尽量用isHighAccuracy: true并配合highAccuracyExpireTime参数虽然会稍微增加功耗但位置准确度提升明显对路线规划类功能至关重要。如果用户还是反馈位置不准在页面上提供一个“重新定位”按钮同时把终点门店地址文字展示出来让用户自己判断当前定位是否合理。还有一个细节iOS 14之后系统弹窗里的“精确定位”如果不打开位置误差能扩大到几公里。这个在小程序代码里是无解的只能在授权回调失败或者精度阈值低于预期时主动提示用户去系统设置里检查定位权限。5.4 真机调试请求无法到达后端这个坑我也遇到过小程序真机调试时接口请求发起后迟迟没有响应后端日志也没有任何记录最后发现是开发调试的url写成了localhost或者内网地址。真机上localhost指的是手机自身根本访问不到你电脑上的服务。排查思路很明确先用手机浏览器访问一下你的服务地址能打开再排查小程序如果服务在电脑本地跑着用http://局域网IP:端口号代替localhost并且在手机和电脑同一个局域网下。还有一点微信开发者工具的“真机调试”和“预览”模式对域名校验的逻辑略有差别有时候预览模式下能请求通真机调试反而失败这样的环境差异要心里有数。5.5 地图缩放与路线重绘的性能优化路线比较长时polyline包含的坐标点很多地图渲染压力大低端机上滑动页面会有明显掉帧。我做了两个优化效果很好第一路线点抽稀保留形状但减少坐标点数量。简单的容差抽稀就能把点数从1000降到200左右视觉几乎无差。第二地图scale不建议固定写死用includePoints动态计算视野。固定scale14在短距离路线里看着太大长距离路线又看不全动态视野最稳妥。5.6 从热词里看还有哪些隐藏需求准备材料时我顺手看了一下搜索热词其实很多人在搜“微信小程序反编译”“微信小程序抓包”这类词这通常是运营或测试想看别人是怎么实现类似导航功能的。这种思路我理解但更建议把精力放在代码层的需求拆解上。比如有人搜“微信小程序顶部导航栏高度”“基础库版本从哪设置”其实就是想在视觉上适配不同机型。对路线规划导航页面来说底部卡片高度、地图全屏显示、顶部返回按钮这些视觉细节确实会影响最终体验有条件的话做一套基础库版本判断在高版本上用更现代的组件形态低版本就保守布局别让老机型用户一脸懵。6. 写在最后我踩过的最值得说的一坑项目里最让我记忆深刻的一次线上故障不是唤起App失败也不是路线绘制不对而是所有用户在部分Android机型上点击“开始导航”后毫无反应连缓存日志都没打出来。查了半天最后发现是wx.openLocation和华米ov某款手机的默认地图应用冲突系统把打开地图的隐式Intent弹窗拦截了微信内的openLocation直接无响应。后来我在点击导航前加了平台判断和备用跳转逻辑同时把“复制终点地址”做成一个备用操作终于让服务可用性稳定了下来。那次之后我养成了个习惯地图导航类能力永远都要有“Plan B”。主路径唤起第三方App备选路径wx.openLocation再不行就直接展示文字地址和电话。哪怕是代码看起来重复了一点但用户在任何机型上都不会走投无路。再分享一个小技巧联调阶段可以把起点坐标写死在开发环境经常用模拟器快速调路线渲染不用每次都真的走到户外。等到开发得差不多了再用真机走一遍定位、授权、路线规划、唤起App的完整链路。这样能省掉很多排队等定位的时间开发效率提升很明显。做导航类小程序最忌讳一开始就闷头写代码。先把地图数据链路、坐标体系、平台限制理清楚再动手也不迟。希望这篇内容能帮你把微信小程序的路线规划导航这条路走通少踩几个我已经替你趟过的雷。
返回列表