背景:APP 内嵌微赞 H5 直播页,用户在直播页下单支付。下单时微赞 H5 调用 APP 注入的原生方法,由 APP 用微信
launchMiniProgram唤起小程序完成支付(仅易宝支付)。参考:微信开放平台
launchMiniProgram接口。
wx074c1f0cf5a0ecf4(见 manifest.json app-plus.distribute.sdkConfigs.share.weixin / oauth)。webchatPay/wx074c1f0cf5a0ecf4。username(原始 ID)、path 由微赞 H5 下单时**动态传回**,APP 不写死,直接透传给 launchMiniProgram。window.android.jumpToMiniProgramPay(JSON.stringify(params))window.webkit.messageHandlers.jumpToMiniProgramPay.postMessage(JSON.stringify(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。
新增 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=...。
创建 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。**这是需要真机验证的第一个点。**
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)。**
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 |
不动,通用外链继续用它 | — |
webchatPay/wx074c1f0cf5a0ecf4(H5 靠它开启唤起支付逻辑)。方式 A/B 需真机试。window.android / window.webkit.messageHandlers 能否触达 APP。这是成败关键,**建议第一步就和微赞联调这一环**,不通则需上原生插件。launchMiniProgram 需微信 SDK 支持,确认现有分享 SDK 版本可用(现有测一测功能已在用,基本可复用)。