From 72def61f2e806a8042e155998ca19e87ec7e789e Mon Sep 17 00:00:00 2001
From: hejianhao <15708179461@qq.com>
Date: 星期五, 21 八月 2026 17:31:56 +0800
Subject: [PATCH] fix0806: 微赞H5唤起小程序支付-接入方案.md
---
doc/微赞H5唤起小程序支付-接入方案.md | 145 ++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 145 insertions(+), 0 deletions(-)
diff --git "a/doc/\345\276\256\350\265\236H5\345\224\244\350\265\267\345\260\217\347\250\213\345\272\217\346\224\257\344\273\230-\346\216\245\345\205\245\346\226\271\346\241\210.md" "b/doc/\345\276\256\350\265\236H5\345\224\244\350\265\267\345\260\217\347\250\213\345\272\217\346\224\257\344\273\230-\346\216\245\345\205\245\346\226\271\346\241\210.md"
new file mode 100644
index 0000000..71878c4
--- /dev/null
+++ "b/doc/\345\276\256\350\265\236H5\345\224\244\350\265\267\345\260\217\347\250\213\345\272\217\346\224\257\344\273\230-\346\216\245\345\205\245\346\226\271\346\241\210.md"
@@ -0,0 +1,145 @@
+# 微赞 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 反射不通,评估上原生插件。
--
Gitblit v1.7.1