From c0624e15767a1dfd050251b0f314194a8fb4ce71 Mon Sep 17 00:00:00 2001 From: kdletters Date: Sun, 21 Jun 2026 16:51:40 +0800 Subject: [PATCH] =?UTF-8?q?=E6=94=B6=E5=8F=A3=E5=AE=BF=E4=B8=BB=E5=AF=BC?= =?UTF-8?q?=E8=88=AA=E8=AF=8A=E6=96=AD=E6=97=A5=E5=BF=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 微信小程序导航失败日志改为固定标签 移动 WebView 进程失败日志不再输出 detail 对象 补充门禁和共享决策记录 --- apps/mobile-shell/scripts/check-config.mjs | 15 +++++---------- apps/mobile-shell/src/shell/ShellApp.test.tsx | 14 ++++++-------- apps/mobile-shell/src/shell/ShellApp.tsx | 5 +---- docs/project-memory/shared-memory/decision-log.md | 1 + scripts/check-native-shells.mjs | 4 ++++ src/services/host-bridge/hostBridge.test.ts | 2 +- src/services/host-bridge/hostBridge.ts | 7 ++----- 7 files changed, 20 insertions(+), 28 deletions(-) diff --git a/apps/mobile-shell/scripts/check-config.mjs b/apps/mobile-shell/scripts/check-config.mjs index 41ca9dbbf..734dede5b 100644 --- a/apps/mobile-shell/scripts/check-config.mjs +++ b/apps/mobile-shell/scripts/check-config.mjs @@ -1526,7 +1526,7 @@ for (const snippet of [ 'MOBILE_WEBVIEW_PROCESS_FAILURE_WINDOW_MS', 'MOBILE_WEBVIEW_PROCESS_FAILURE_RELOAD_LIMIT', 'handleWebViewProcessFailure', - "console.warn('mobile WebView process failed'", + 'mobile WebView process failed for', "handleWebViewProcessFailure('content_process_terminated')", "handleWebViewProcessFailure('render_process_gone')", 'normalizeMobileShellLoadFailure', @@ -1608,13 +1608,8 @@ if (shellAppSource.includes('catch(() => undefined)')) { throw new Error('mobile shell ShellApp must not hide async navigation failures'); } -if ( - shellAppSource.includes("console.warn('mobile WebView process failed', {") && - shellAppSource.includes( - "console.warn('mobile WebView process failed', {\n count: nextFailureWindow.count,\n label,\n url: webUrl,", - ) -) { - throw new Error('mobile shell WebView process diagnostics must not log H5 URLs'); +if (shellAppSource.includes("console.warn('mobile WebView process failed', {")) { + throw new Error('mobile shell WebView process diagnostics must not log detail objects'); } if (!shellAppTestSource.includes('blocked WebView file downloads are logged for host diagnostics')) { @@ -2750,10 +2745,10 @@ for (const snippet of [ 'runtime deep link rejections are logged and fall back to a safe WebView URL', "'mobile shell deep link failed for runtime_url.rejected'", 'first WebView process failure reloads the current page once', - 'mobile WebView process failed', + 'mobile WebView process failed for content_process_terminated', 'repeated WebView process failures show the load failure panel and retry clears the failure window', "expect(screen.getByText('页面已停止')).toBeTruthy()", - "expect(warnSpy).toHaveBeenCalledWith('mobile WebView process failed', {", + 'mobile WebView process failed for render_process_gone', ]) { if (!shellAppTestSource.includes(snippet)) { throw new Error(`mobile shell ShellApp HostBridge event test missing ${snippet}`); diff --git a/apps/mobile-shell/src/shell/ShellApp.test.tsx b/apps/mobile-shell/src/shell/ShellApp.test.tsx index ffdc9f298..3331a71ca 100644 --- a/apps/mobile-shell/src/shell/ShellApp.test.tsx +++ b/apps/mobile-shell/src/shell/ShellApp.test.tsx @@ -733,10 +733,9 @@ describe('ShellApp HostBridge event injection', () => { }); expect(shellHarness.reloadWebView).toHaveBeenCalledTimes(1); - expect(warnSpy).toHaveBeenCalledWith('mobile WebView process failed', { - count: 1, - label: 'content_process_terminated', - }); + expect(warnSpy).toHaveBeenCalledWith( + 'mobile WebView process failed for content_process_terminated', + ); warnSpy.mockRestore(); nowSpy.mockRestore(); @@ -765,10 +764,9 @@ describe('ShellApp HostBridge event injection', () => { expect(screen.getByText('页面已停止')).toBeTruthy(); }); expect(shellHarness.reloadWebView).toHaveBeenCalledTimes(1); - expect(warnSpy).toHaveBeenLastCalledWith('mobile WebView process failed', { - count: 2, - label: 'render_process_gone', - }); + expect(warnSpy).toHaveBeenLastCalledWith( + 'mobile WebView process failed for render_process_gone', + ); act(() => { screen.getByText('重试').click(); diff --git a/apps/mobile-shell/src/shell/ShellApp.tsx b/apps/mobile-shell/src/shell/ShellApp.tsx index afae6a714..28a580f5e 100644 --- a/apps/mobile-shell/src/shell/ShellApp.tsx +++ b/apps/mobile-shell/src/shell/ShellApp.tsx @@ -425,10 +425,7 @@ export default function ShellApp() { firstFailureAt: now, }; webViewProcessFailureRef.current = nextFailureWindow; - console.warn('mobile WebView process failed', { - count: nextFailureWindow.count, - label, - }); + console.warn(`mobile WebView process failed for ${label}`); if (nextFailureWindow.count <= MOBILE_WEBVIEW_PROCESS_FAILURE_RELOAD_LIMIT) { reloadCurrentWebView(); diff --git a/docs/project-memory/shared-memory/decision-log.md b/docs/project-memory/shared-memory/decision-log.md index 8604fa14f..df97f00bf 100644 --- a/docs/project-memory/shared-memory/decision-log.md +++ b/docs/project-memory/shared-memory/decision-log.md @@ -109,6 +109,7 @@ - 2026-06-21 微信 WebView 认证诊断日志收口:微信 `web-view` 壳解析认证结果、`wx.login`、小程序登录请求、手机号绑定请求、认证流程和手机号授权拒绝失败时,只记录 `[web-view] ` 固定标签,不输出微信原生错误对象、HTTP response 或授权 detail;页面仍只展示稳定登录 / 绑手机号错误文案。 - 2026-06-21 微信 WebView 页面事件诊断日志收口:微信 `web-view` 壳加载成功、加载失败和 H5 message 事件只记录 `[web-view] ` 固定标签,不输出 WebView `event.detail`;分享目标解析继续走结构化 message payload,但生产日志不得回吐原生事件体。 - 2026-06-21 原生壳生产替身词门禁同步:根级 `check:native-shells`、Expo 移动壳单端 `check-config` 和 Tauri 桌面壳单端 `check-config` 都必须拒绝生产壳源码出现 mock / fake / placeholder / stub / TODO / FIXME / 占位 / 模拟 / 伪造 / 未实现 / 临时 / 后续 等替身或未来式占位词;真实未接能力只能通过明确 unsupported 语义表达。 +- 2026-06-21 HostBridge 导航与移动 WebView 进程诊断收口:H5 微信小程序 `navigateTo.fail` 只记录 `[host-bridge] wechat mini program navigation failed` 固定标签,不输出微信原生失败对象;Expo 移动壳 WebView content / render process failure 只记录 `mobile WebView process failed for ` 固定标签,不输出计数、URL、native event 或 detail 对象。 - 2026-06-19 微信壳路由一致性门禁:`npm run check:native-shells` 必须反查 `miniprogram/app.json.pages`、`miniprogram/host-bridge/protocol.js`、H5 `src/services/host-bridge/hostBridge.ts` 小程序页面常量、H5 `src/services/wechatMiniProgramSubscribe.ts` 订阅授权页面常量、`miniprogram/host-bridge/webView.js` 分享入口 / 分享消息类型、`miniprogram/config.js` source query / 域名格式、`miniprogram/shell/webView.js` 请求头来源标记、H5 runtime parser 和 H5 路由保留字段。新增或调整小程序页面、登录派生 URL、支付页、九宫切图页、订阅页、WebView 来源标记、H5 入口域名、API base URL 或宿主上下文 query 字段时,必须同步这几处常量并保持生产 / 开发域名都显式配置为纯 HTTPS domain;运行时开发域名回退生产域名只作为异常兜底。 - 2026-06-18 登录 / 支付能力禁伪声明:`auth.requestLogin` 和 `payment.request` 保留在共享 HostBridge 契约中供未来真实接入,但 Expo / Tauri 壳在真实 SDK、渠道流程和后端契约落地前不得声明这些 capability,也不得把它们写入入口 URL `hostCapabilities`;两端检查脚本会拒绝伪声明,请求实际到达壳层时必须返回明确 `unsupported_method` 并让 H5 fallback,两端壳测试直接覆盖这两个 method。 - 2026-06-20 桌面壳未声明 method 禁伪成功:Tauri 桌面壳只声明真实可用 capability;共享 HostBridge method 白名单中未进入桌面 capability profile 的 method,例如 `auth.requestLogin`、`payment.request`、`file.captureImage`、`scanner.scanQrCode` 和 `haptics.impact`,请求实际到达桌面壳时必须统一返回明确 `unsupported_method`,不得伪造成功或半接入。桌面 Rust 测试必须从 `HOST_BRIDGE_METHODS` 与 `capabilities()` 差集派生 unsupported 覆盖清单,桌面单端配置检查会反查该派生路径,后续共享契约新增 method 时必须同步声明真实桌面能力或补进 unsupported 语义。 diff --git a/scripts/check-native-shells.mjs b/scripts/check-native-shells.mjs index 5dd9a0078..1d3dfbc7d 100644 --- a/scripts/check-native-shells.mjs +++ b/scripts/check-native-shells.mjs @@ -1600,6 +1600,9 @@ function assertH5HostBridgePayloadBoundaries() { "'[host-bridge] wechat mini program navigation failed'", ) || !h5HostBridgeSource.includes('reject(new Error(errorMessage));') || + h5HostBridgeSource.includes( + "console.error(\n '[host-bridge] wechat mini program navigation failed'", + ) || h5HostBridgeSource.includes('reject(new Error(error?.errMsg || errorMessage));') ) { throw new Error( @@ -1611,6 +1614,7 @@ function assertH5HostBridgePayloadBoundaries() { "errMsg: 'navigateTo:fail private native detail'", "rejects.toThrow(\n '请在微信小程序内完成登录',", "rejects.not.toThrow(\n 'private native detail',", + "expect(consoleError.mock.calls.flat()).not.toContain(navigationError)", ]) { if (!h5HostBridgeTestSource.includes(snippet)) { throw new Error(`H5 HostBridge navigation failure test must include ${snippet}`); diff --git a/src/services/host-bridge/hostBridge.test.ts b/src/services/host-bridge/hostBridge.test.ts index d242cd125..3bd0db326 100644 --- a/src/services/host-bridge/hostBridge.test.ts +++ b/src/services/host-bridge/hostBridge.test.ts @@ -796,8 +796,8 @@ describe('hostBridge', () => { ); expect(consoleError).toHaveBeenCalledWith( '[host-bridge] wechat mini program navigation failed', - navigationError, ); + expect(consoleError.mock.calls.flat()).not.toContain(navigationError); consoleError.mockRestore(); }); diff --git a/src/services/host-bridge/hostBridge.ts b/src/services/host-bridge/hostBridge.ts index 583cadc3a..6daa92ac8 100644 --- a/src/services/host-bridge/hostBridge.ts +++ b/src/services/host-bridge/hostBridge.ts @@ -495,11 +495,8 @@ export async function navigateWechatMiniProgramPage( success() { resolve(); }, - fail(error) { - console.error( - '[host-bridge] wechat mini program navigation failed', - error, - ); + fail(_error) { + console.error('[host-bridge] wechat mini program navigation failed'); reject(new Error(errorMessage)); }, });