微赞 H5 唤起小程序支付 —— APP 端接入方案

背景:APP 内嵌微赞 H5 直播页,用户在直播页下单支付。下单时微赞 H5 调用 APP 注入的原生方法,由 APP 用微信 launchMiniProgram 唤起小程序完成支付(仅易宝支付)。

参考:微信开放平台 launchMiniProgram 接口。

一、已确认的前提

  • 微信应用 appId:wx074c1f0cf5a0ecf4(见 manifest.json app-plus.distribute.sdkConfigs.share.weixin / oauth)。
  • UA 标识:需注入 webchatPay/wx074c1f0cf5a0ecf4。
  • 唤起目标小程序:username(原始 ID)、path 由微赞 H5 下单时**动态传回**,APP 不写死,直接透传给 launchMiniProgram。
  • JSBridge 方式:必须按文档原生方式,H5 侧写死为
  • 安卓:window.android.jumpToMiniProgramPay(JSON.stringify(params))
  • iOS:window.webkit.messageHandlers.jumpToMiniProgramPay.postMessage(JSON.stringify(params))
  • params:{ orderId: string, miniprogramType: 0, path: string, username: string }
  • 现有能力:项目已用 plus.share.getServices + launchMiniProgram(见 pages/home/home.vue),已大量用 plus.android/plus.ios.importClass 直接调原生(见 utils/webview-cache.js)。

二、核心技术障碍

uni-app 标准 <web-view> 组件(当前 pages/webview/webview.vue 用的)**两点都做不到**:
1. 无法自定义 UA;
2. 无法接住原生 window.android / window.webkit.messageHandlers 调用(它只支持 uni.postMessage 的 @message)。

因此进入微赞直播间的 webview 必须从"组件式 <web-view>"改为"命令式 plus.webview.create",并对底层原生 WebView 做 UA 设置 + JSBridge 注册。

说明:仅"微赞直播间"这一个入口需要特殊 webview;其它普通外链继续用现有 <web-view> 页面,避免全量风险。建议**新建独立页面** pages/weizanLive/weizanLive.vue 承载,不动通用 webview.vue。

三、实施步骤

步骤 1:新建微赞直播专用页面(命令式 webview)

新增 pages/weizanLive/weizanLive.vue:
- onLoad 拿到后端换取的直播 URL(沿用现有 createLiveRoomEntry 返回的 url)。
- 进入前调用 clearWebViewData()(复用现有清缓存逻辑)。
- 用 plus.webview.create 创建原生 webview,设置 UA,append 到当前页面。
- 注册 JSBridge,onUnload 时 close/销毁 webview 并反注册。

页面 pages.json 注册该路由。home.vue 的 goWeiZanLive 跳转目标从 /pages/webview/webview?... 改为 /pages/weizanLive/weizanLive?url=...。

步骤 2:UA 注入

创建 webview 时设置带 webchatPay/{appId} 的 UA。5+ 有两种方式:

方式 A(推荐,webview 级):plus.webview.create(url, id, styles, extras),styles 里指定:
js const appId = 'wx074c1f0cf5a0ecf4' const baseUA = plus.navigator.getUserAgent() const ua = baseUA + ' webchatPay/' + appId const wv = plus.webview.create(targetUrl, 'weizan-live-webview', { plusrequire: 'none', 'uni-app': 'none', // 关键:部分基座支持在 create styles 传 UA;若不支持见方式 B additionalHttpHeaders: {}, }) // 若 create styles 不支持 UA,则用下面全局设置法

方式 B(全局,需还原):进入前 plus.navigator.setUserAgent(ua, false),退出直播页时还原为 baseUA。缺点是设置期间新建的所有 webview 都带此 UA,需确保直播 webview 创建后立即还原,或接受该副作用。

⚠️ 待自测:优先试方式 A 的 create styles 是否支持 UA 字段(不同 HBuilderX 基座版本差异大);不支持再退方式 B。**这是需要真机验证的第一个点。**

步骤 3:注册原生 JSBridge jumpToMiniProgramPay

新增 utils/weizan-pay-bridge.js。

Android:通过 plus.android 反射,给底层 WebView addJavascriptInterface,暴露 window.android。
js // 伪代码骨架,真机联调时补全线程/回调细节 function registerAndroidBridge(webviewInstance, onPay) { const Interface = plus.android.implements('io.dcloud.js.WeizanPayJsInterface', { // H5 调 window.android.jumpToMiniProgramPay(str) 'jumpToMiniProgramPay': function (paramsJson) { // 注意:JS 接口回调在原生线程,需切回主线程再唤起 onPay(paramsJson) } }) const obj = plus.android.currentWebview() // 或从 webviewInstance 取底层 Android WebView plus.android.invoke(obj, 'addJavascriptInterface', Interface, 'android') }

iOS:给 WKWebView 注册 WKScriptMessageHandler,暴露 window.webkit.messageHandlers.jumpToMiniProgramPay。
js // iOS 需通过 plus.ios 取到 WKWebView 的 configuration.userContentController // addScriptMessageHandler:name:'jumpToMiniProgramPay' // 收到 didReceiveScriptMessage 后回调 onPay(message.body)

⚠️ 这是本方案**最高风险、最需要真机联调**的部分。Android addJavascriptInterface 走 plus.android 反射可行但要处理:JS 接口方法运行在非 UI 线程,唤起微信必须切回主线程。iOS 的 messageHandler 通过 plus.ios 反射注册较繁琐,可能需要拿到 dcloud 基座的 WKWebView 实例。**如果 plus 反射行不通,退路是写原生插件(uni native plugin)。**

步骤 4:唤起小程序(低风险,复用现有能力)

onPay(paramsJson) 收到后:
```js
function jumpToMiniProgramPay(paramsJson) {
let params
try { params = JSON.parse(paramsJson) } catch { return }
const { username, path, miniprogramType, orderId } = params || {}
if (!username) { uni.showToast({ title: '支付参数缺失', icon: 'none' }); return }

// 切主线程后执行(Android JS 接口回调在子线程)
plus.share.getServices((services) => {
    const wx = services.find((s) => s.id === 'weixin')
    if (!wx) { uni.showToast({ title: '当前环境不支持微信', icon: 'none' }); return }
    if (!wx.nativeClient) { uni.showToast({ title: '请先安装微信客户端', icon: 'none' }); return }
    wx.launchMiniProgram({
        id: username,                       // 小程序原始 ID(gh_ 开头)
        path: path || '',                   // 微赞传回的支付路径
        type: Number(miniprogramType) || 0, // 固定 0
    }, () => {
        console.log('[weizanPay] 唤起小程序成功, orderId=', orderId)
    }, (err) => {
        console.log('[weizanPay] 唤起失败', err)
        uni.showToast({ title: '唤起支付失败', icon: 'none' })
    })
}, (err) => {
    uni.showToast({ title: '微信服务不可用', icon: 'none' })
})

}
```

四、改动文件清单

文件 改动 风险
pages/weizanLive/weizanLive.vue(新增) 命令式 plus.webview 承载微赞直播 + UA + bridge 高
utils/weizan-pay-bridge.js(新增) 注册 Android/iOS 原生 JSBridge + 唤起小程序 高
pages.json 注册新路由 低
pages/home/home.vue goWeiZanLive 跳转目标改为新页面 低
pages/webview/webview.vue 不动,通用外链继续用它 —

五、必须真机验证 / 外部协调的点

  1. UA 是否生效:进入直播间后,让微赞 H5 侧确认收到的 UA 含 webchatPay/wx074c1f0cf5a0ecf4(H5 靠它开启唤起支付逻辑)。方式 A/B 需真机试。
  2. JSBridge 能否接住:需微赞 H5 提供测试下单入口,真机验证 window.android / window.webkit.messageHandlers 能否触达 APP。这是成败关键,**建议第一步就和微赞联调这一环**,不通则需上原生插件。
  3. 微信侧配置:APP 的微信 appId 需在微信开放平台配置好"可跳转的小程序"关联(launchMiniProgram 要求已关联的小程序才能拉起),否则会报 badprogram。
  4. 微赞后台:需完成"绑定微信商户号 + 申请易宝支付"(文档前期准备第 1 条,非 APP 端工作,需微赞/运营确认已就绪)。
  5. iOS 唤起小程序资质:iOS 端 launchMiniProgram 需微信 SDK 支持,确认现有分享 SDK 版本可用(现有测一测功能已在用,基本可复用)。

六、建议推进顺序

  1. 先和微赞确认「前期准备」1、2、3 已具备联调条件,拿到测试直播间 + 测试小程序原始 ID/path。
  2. 先做**步骤 4 唤起小程序**(复用现有,最易验证)——可先用一个测试按钮硬编码参数跑通 launchMiniProgram。
  3. 再做**步骤 2 UA**,让微赞 H5 确认识别到。
  4. 最后攻**步骤 3 JSBridge**,与微赞真机联调。若 plus 反射不通,评估上原生插件。