微信内跳转地图导航方案梳理 (WeChat to Map App Navigation)
背景:通过微信打开一个网页,点击后跳转到地图 App(百度地图等)进行导航。核心难点在于微信内置浏览器对第三方 App 唤起(URL Scheme)的限制。
一、要解决什么问题
- 用户从微信里打开一个链接,最终要能在手机地图 App 里进入导航。
- 有现成 POI 数据(
campus_pois.json,613 个校园及周边点,坐标是百度 bd09ll 坐标系)。 - 目标地图 App 先用百度地图,后续要扩展高德、腾讯地图。
二、几套方案与结论
方案 A:百度地图 URI API(Web 端跳转)
- 官方文档
https://api.map.baidu.com/lbsapi/cloud/uri.htm,v2.0,免费、免 AK。 服务地址形如:
- 标点
api.map.baidu.com/marker - 地址解析
api.map.baidu.com/geocoder - POI 检索
api.map.baidu.com/place/search - POI 详情
api.map.baidu.com/place/detail - 路线规划
api.map.baidu.com/direction
- 标点
- 通用必填参数:
output=html(Web 端必填)、src=webapp.companyName.appName(统计必选)。 - 坐标系:默认 bd09ll。现有数据恰好是百度搜索接口返回的 bd09ll,无需转换直接落点。
- 实测:这些接口 302 重定向到
map.baidu.com,在普通浏览器里打开正常。 - 局限:跳转到的是「百度地图网页版」,不是直接唤起 App。
方案 B:自己建落地页 + URL Scheme 自动唤起
- 思路:详情页展示 POI 信息(图片、介绍、详情),点击后进入跳转页,跳转页用
baidumap://map/direction?...唤起百度地图 App。 - 结论:在真浏览器(Safari/Chrome)里
window.location = 'baidumap://...'能直接唤起;但在微信内置浏览器里,第三方 scheme 会被静默拦截,无法自动唤起。 - 落地页思路本身成立,但微信场景下不能自动唤起。
方案 C:微信开放标签 wx-open-launch-app(官方微信内跳 App 能力)
- 官方文档
https://developers.weixin.qq.com/doc/oplatform/Mobile_App/WeChat_H5_Launch_APP.html。 - 硬性条件:已认证服务号 + 已认证开放平台账号(同主体)+ 网页域名绑定为服务号 JS 接口安全域名 + 域名与移动应用绑定。
- 只能跳转自己审核通过的 App,不能唤起百度地图(第三方 App)。
- 结论:不适用于「跳百度地图」这个目标。
方案 D:应用宝微下载(microdown.yyb.qq.com)—— 最终采用
- 百度地图 URI 在微信内点击"打开地图"时,走的正是应用宝这条链路。
- 用手机 UA(微信内核)+ 无头浏览器实测,抓到了完整机制。
D 的核心机制(已实证)
应用宝页面不直接跳 baidumap://,而是通过微信注入的私有 JSBridge 方法完成,完整调用序列:
1. WeixinJSBridge.invoke("getInstallState", {packageName: "com.tencent.android.qqdownloader"}) // 查应用宝
2. WeixinJSBridge.invoke("getInstallState", {packageName: "com.baidu.BaiduMap"}) // 查百度地图
3. WeixinJSBridge.invoke("launch3rdApp", {}) // 试探权限
4. WeixinJSBridge.invoke("getInstallState", {packageName: "com.tencent.mm"}) // 查微信
5. WeixinJSBridge.invoke("launchApplication", { schemeUrl: "tmast://appdemo?...applink=<base64>" })第 5 步的 schemeUrl 关键字段:
tmast://appdemo?photonid=...¶ms=scene:40027, via:ANDROIDWXZ.YYB.WX.OPEN,
pkgName:com.baidu.BaiduMap, appName:百度地图,
applink:<base64>, autoOpen:trueapplink 解码后就是 baidumap://map/direction?mode=driving。
本质:tmast://appdemo 唤起应用宝 App,应用宝再执行 applink 里的 baidumap:// 唤起百度地图。这是「中转」而非直接唤起。
三条子路径
| 场景 | 微信内动作 | 走的 JSBridge 方法 |
|---|---|---|
| 已装百度地图 | 唤起 tmast:// 中转 → baidumap:// | launchApplication |
| 已装、需跳浏览器 | "离开微信"→系统浏览器→baidumap:// | openUrlByExtBrowser |
| 未装 | 微信安全下载 APK | download3rdApp + appdown.md.qq.com |
关键结论(真机实测确认)
- 这些 JSBridge 方法(
launchApplication、openUrlByExtBrowser、getInstallState)只在微信内置浏览器里、且仅对腾讯白名单域名(a.app.qq.com/microdown.yyb.qq.com/appdown.md.qq.com等)注入。 - 真机实测:在普通域名页面上,
WeixinJSBridge上根本不存在openUrlByExtBrowser等方法,只有基础的公开方法。第三方域名无法调用这些私有方法。 - 因此,「自己做一个类似应用宝的落地页来唤起」不可行——不是技术门槛,是微信服务端白名单。
三、最终确定的妥协
微信内跳地图,统一走应用宝微下载直连(microdown.yyb.qq.com/o/simple.jsp)。
- 不自己写后端做 scheme 唤起(微信私有 JSBridge 白名单问题,做不了)。
- 也不经
api.map.baidu.com → map.baidu.com中转,而是直接跳应用宝落地页,链路最短:微信 → microdown.yyb.qq.com → tmast:// 中转 → baidumap:// - 正确拼法(关键:整个 scheme 必须整体 URL 编码):
https://microdown.yyb.qq.com/o/simple.jsp
?pkgname=com.baidu.BaiduMap
&android_schema=<整个 baidumap scheme 整体 URL 编码>
&src=webapp.demo.campus其中 android_schema 的值是一整个 URL 编码后的 scheme:
baidumap://map/direction?mode=driving&destination=name:终点|latlng:29.822838,121.568971&coord_type=bd09ll- 不传起点:
baidumap://里不带origin,由百度地图自行定位当前起点,减少一步输入。 - 编码坑(已实测):
destination(及origin)必须作为 scheme 的一部分整体编码塞进android_schema。若把它们写成 microdown 页面的独立参数(用&分开),microdown 不读取,最终 applink 会丢失起终点。实测:整体编码 → applink 解码含完整 destination;独立参数 → applink 只剩mode=driving。 - iOS 差异:
android_schema只对安卓生效;iOS 需要用ios_schema参数单独拼。 - 坐标体系:
baidumap://用 bd09ll,现有数据正好是 bd09ll,零转换;扩展高德/腾讯时换pkgname(com.autonavi.minimap)和 scheme 前缀(amapuri:///iosamap:///qqmap://),并把 bd09 → gcj02。
四、可复用的经验
- 微信内置浏览器对第三方 URL Scheme 静默拦截,任何普通网页都无法直接
location = 'baidumap://'唤起。 - 微信「离开微信、在浏览器打开」提示,不是网页 JS 触发的,是微信对白名单域名(腾讯系)的系统级能力。
- 应用宝微下载的本质是「tmast:// 中转 scheme + 微信私有 JSBridge」,整套只对腾讯域名开放。
- 微信公开 JSSDK 里没有「跳转外部浏览器」或「唤起任意第三方 App」的接口。
- 百度地图 URI API v2.0 仍有效、免 AK;
output=html和src在 Web 端必填;默认 bd09ll 坐标。 - 网络实测环境注意:本机 7890 代理端口抓百度地图接口返回 502,7897 端口可用;urllib 默认 UA 会被识别为爬虫返回 403,建议用 curl + 浏览器 UA 或无头浏览器。
五、补充:URL Scheme 双协议头 + WebView 拦截(2026-08 依据官方 uri/api 文档确认)
场景:网页/WebView 里点"百度地图"按钮调起 App 导航。上文方案 B 只确认了"真浏览器能唤起、微信被拦",本节补齐协议头本身就该分两套这一层。
5.1 native 与 web 用不同协议头
百度官方 uri/api 文档(实现原理一节)明确,Android 与 iOS 一致:
| 场景 | scheme | 由谁处理 |
|---|---|---|
| native(第三方 App 原生 Intent / WebView 壳内) | baidumap:// | 壳 shouldOverrideUrlLoading 拦截 → ACTION_VIEW Intent |
| web(浏览器 / 网页应用) | bdapp:// | 系统直接路由,不经过壳 |
网页应用调起 iOS/Android 百度地图路线规划(官方示例格式):
bdapp://map/direction?origin=纬度,经度&destination=纬度,经度&coord_type=bd09ll&mode=walking&src=webapp.companyName.appNameorigin/destination:裸坐标(先纬度后经度)或latlng:纬度,经度;iOS 端不认 Android 的latlng:..|name:..组合段,只有名称时也不带name:。coord_type:默认 bd09ll(本项目数据正好是 bd09ll,显式传更稳)。src:必填,ios/andr/webapp.companyName.appName,不传不保证服务。mode:支持 walking/driving/transit/riding 等,walking可直接用。- Android native(壳内)路径
baidumap://则认latlng:..|name:..组合格式(Android 文档示例origin=latlng:34.26,108.95|name:我的位置)。
5.2 WebView 壳必须拦截 scheme,否则跳报错页
WebView 默认不把自定义 scheme 交给系统——壳不拦,点外部地图就跳"网页无法打开"报错页(本项目实测到的现象)。拦截方式是 WebViewClient 覆写,不是 JS 桥(JS 桥 addJavascriptInterface 是给网页调原生能力用的,与调起第三方 App 无关):
- Android:
shouldOverrideUrlLoading拦下 scheme →startActivity(Intent(ACTION_VIEW, uri)),调起前resolveActivity判空(未装不 start,否则抛ActivityNotFoundException)。 - iOS:WKWebView
decidePolicyFor拦下 →UIApplication.open;App 内探测 scheme 还要 Info.plist 加LSApplicationQueriesSchemes(这才是 iOS 的"白名单",网页没有白名单概念)。
浏览器(Safari/Chrome)里不需要任何代码,系统直接路由 scheme;报错页只说明 App 没装 / scheme 没注册 / 协议头不对。
5.3 项目落地方案(校园导航)
前端导航页按"有无原生桥"自动二选一,而不是按 iOS/Android 分:
target = getNativeBridge() ? nativeSchema : webSchema
// 有 CampusNative 桥(壳)= baidumap:// + latlng:..|name:..(native)
// 无桥(浏览器,iOS 与 Android 通用)= bdapp:// + 裸坐标 + coord_type=bd09ll(web)学校桥接包 android/compass-bridge-for-school/ExternalMapLaunch.java:静态 handleExternalUrl(view, request, context),学校把它并进已有 WebViewClient 的 shouldOverrideUrlLoading 第一行即可,不覆盖其原有 https 放行逻辑。拦截名单:baidumap/bdapp/amapuri/qqmap/geo + https 降级域名(map.baidu.com / api.map.baidu.com / uri.amap.com)。调起结果回推 window.CampusNavigation.receiveExternalLaunch(success, scheme) 供前端 toast。
5.4 待真机验证 / 已知不可靠项
- 新版(2024-2026)iOS/Android 百度地图是否仍注册
bdapp://:官方文档如此规定,但新版 App 行为未实测;若失效可交叉试baidumap://头。 网页版导航降级链接实测(2026-08):
api.map.baidu.com/direction?destination=..&mode=walking®ion=..&output=html&src=webapp.xx.xx→ 200 可用,302 到http://map.baidu.com/mobile/?third_party=uri_api#place/linesearch/..(http 非 https)。- 三个坑:① 重定向到 http;②
mode参数会丢,用户到页面还要自己选步行/驾车/公交;③ 终点名称传递错乱(页面 word 恒显示"终点",坐标正确但名称不对)。 map.baidu.com/direction(不带 output=html)404、map.baidu.com/?qt=s403 反爬——必须走api.map.baidu.com/direction?...&output=html这套 v2.0 web URI。- 定位:这是"打开百度移动网页版路线页",不是唤起 App,无实时步行导航/语音引导。只能当微信内"能看路线、不报错"的兜底。
- iOS 微信内走应用宝 microdown 基本不可用(应用宝 iOS 版已停运),微信 iOS 场景需另想办法。
5.5 教训
iosSchema = androidSchema直接复用 Android 格式 → iOS 端失效。命名androidSchema/iosSchema本身就是误导,真实维度是 native vs web,应命名nativeSchema/webSchema。
六、补充:微信 iOS 侧——microdown 为什么死 + 微信 iOS 跳第三方 App 机制(2026-08)
6.1 microdown 是纯 Android 链路,iOS 无中转
上文方案 D 的完整调用序列依赖两个 Android 专有环节:
microdown 页 → WeixinJSBridge.launchApplication({schemeUrl:"tmast://appdemo?applink=<base64 的 baidumap://>"})
→ 唤起应用宝 App → 应用宝执行 baidumap:// → 百度地图tmast://scheme 是应用宝 App 注册的协议头。应用宝 iOS 版早已停运(2016 前后下架,苹果不允许第三方应用商店),iOS 上没有任何 App 认领tmast://,中转第一步就断。launchApplication这套私有 JSBridge 是 Android 微信对腾讯白名单域名注入的,iOS 微信没有这套 tmast 中转方法。
结论:microdown.yyb.qq.com 在 iOS 上最多显示一个下载引导页,ios_schema 参数无人执行,死链。
6.2 iOS 微信跳第三方 App 的机制(与 Android 本质不同)
iOS 微信内核是 WKWebView。网页 location.href = "baidumap://" 触发 WKWebView 的 decidePolicyForNavigationAction,放不放行由微信(宿主 App)决定——微信在 WebView 层就拦截了,iOS 系统的 scheme 确认框都到不了。
| 方式 | iOS 微信内 | 原因 |
|---|---|---|
| microdown 应用宝中转 | ✗ | 应用宝 iOS 版下架,无 tmast:// 可中转 |
location.href = bdapp://(URL Scheme) | ✗(基本被拦) | 微信 WKWebView 拦截第三方 scheme(2023-12 起明显收紧,社区实测:点击无反应或提示"在浏览器中打开") |
| Universal Link(iOS 9+ 标准深度链接) | ✗ | 微信会"劫持" Universal Link:即使目标 App 配置了 apple-app-site-association,微信里也把它当普通网页打开,除非该 App 在微信开放平台关联并通过校验 |
wx-open-launch-app 开放标签 | 仅限"自己的 App" | 微信官方唯一认可路线,但要求已认证服务号/开放平台、且只能唤起自己审核通过的 App,无法唤起第三方百度地图 |
6.3 iOS 微信跳百度地图结论 + 兜底
iOS 微信里直接唤起百度地图 App,目前没有可靠技术路线。 兜底两条:
- 引导用户"右上角 ··· → 在浏览器中打开",浏览器里再跳
bdapp://(浏览器路径可用)。 - 降级成"复制终点名/坐标",让用户到百度地图里自己搜。
6.4 对项目 navi 页的建议
navigateExternal 现在微信场景(不论 iOS/Android)都走 microdown。建议:
- 检测到
iOS + 微信→ 不走 microdown,改为 toast 提示"请右上角'在浏览器中打开'后使用外部导航"(或直接复制坐标)。 - Android 微信的 microdown 链路也建议真机复测(依赖应用宝是否安装 + 微信白名单域名是否仍放行)。
相关笔记
本文归档于个人知识库 · 领域:CS & AI · 模块:04 Project_CS_AI/Web