收口宿主导航诊断日志
微信小程序导航失败日志改为固定标签 移动 WebView 进程失败日志不再输出 detail 对象 补充门禁和共享决策记录
This commit is contained in:
@@ -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}`);
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -109,6 +109,7 @@
|
||||
- 2026-06-21 微信 WebView 认证诊断日志收口:微信 `web-view` 壳解析认证结果、`wx.login`、小程序登录请求、手机号绑定请求、认证流程和手机号授权拒绝失败时,只记录 `[web-view] <stage>` 固定标签,不输出微信原生错误对象、HTTP response 或授权 detail;页面仍只展示稳定登录 / 绑手机号错误文案。
|
||||
- 2026-06-21 微信 WebView 页面事件诊断日志收口:微信 `web-view` 壳加载成功、加载失败和 H5 message 事件只记录 `[web-view] <stage>` 固定标签,不输出 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 <stage>` 固定标签,不输出计数、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 语义。
|
||||
|
||||
@@ -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}`);
|
||||
|
||||
@@ -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();
|
||||
});
|
||||
|
||||
|
||||
@@ -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));
|
||||
},
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user