锁定移动壳加载失败测试门禁

移动壳配置检查反查加载失败同源和非主页面测试

共享决策同步移动壳错误页验收边界
This commit is contained in:
2026-06-20 09:31:23 +08:00
parent b921c46afe
commit 888c4bc4d5
2 changed files with 23 additions and 0 deletions
@@ -143,6 +143,11 @@ const webViewHistoryPath = new URL('../src/shell/webViewHistory.ts', import.meta
const webViewHistorySource = fs.readFileSync(webViewHistoryPath, 'utf8');
const loadFailurePath = new URL('../src/shell/loadFailure.ts', import.meta.url);
const loadFailureSource = fs.readFileSync(loadFailurePath, 'utf8');
const loadFailureTestPath = new URL(
'../src/shell/loadFailure.test.ts',
import.meta.url,
);
const loadFailureTestSource = fs.readFileSync(loadFailureTestPath, 'utf8');
const runtimePath = new URL('../src/shell/runtime.ts', import.meta.url);
const runtimeSource = fs.readFileSync(runtimePath, 'utf8');
const safeAreaTestPath = new URL('../src/shell/safeArea.test.ts', import.meta.url);
@@ -1434,6 +1439,23 @@ for (const snippet of [
}
}
for (const snippet of [
"describe('loadFailure'",
"test('归一化同源 HTTP 加载失败'",
"test('忽略外域和非页面加载失败'",
"test('只展示当前主页面失败'",
"url: 'https://example.com/'",
"url: 'about:blank'",
"url: 'javascript:alert(1)'",
"url: '/favicon.ico'",
"url: 'https://app.genarrative.world/assets/main.js'",
"https://app.genarrative.world/creation/puzzle",
]) {
if (!loadFailureTestSource.includes(snippet)) {
throw new Error(`mobile shell load failure tests missing ${snippet}`);
}
}
for (const snippet of [
'MOBILE_WEBVIEW_BLOCKED_DOWNLOAD_PROTOCOLS',
'HOST_BRIDGE_MOBILE_WEBVIEW_BLOCKED_DOWNLOAD_PROTOCOLS',
@@ -75,6 +75,7 @@
- 2026-06-18 原生壳网络状态:新增 `network.status``network.statusChanged` HostBridge capabilityExpo 壳通过 `expo-network` 查询和订阅真实系统网络状态,Tauri 壳从 `WEB_APP_ORIGIN` 解析主站 host / port 后做短超时 TCP 可达性查询,并通过 WebView `online` / `offline` 注入变化事件;H5 统一使用 `getHostNetworkStatus()` / `subscribeHostNetworkStatusChange()`,不得直接读取 Expo / Tauri 私有网络 API。
- 2026-06-19 移动壳本地通知边界:Expo `notification.showLocal` 的 payload 归一、权限确认、iOS 仅 alert 且不请求 badge/sound、Android 固定 channel、即时调度、通知 handler 和成功响应包装统一收口在 `apps/mobile-shell/src/host-bridge/notifications.ts``dispatch.ts` 只负责把 HostBridge request 委托给 `showMobileHostBridgeLocalNotification(...)`,不得直接调用 `expo-notifications` 调度或权限 API,不得重新做通知 payload 归一,也不得包装本地通知成功响应。移动壳配置检查会覆盖该模块结构、固定 channel、即时调度形态和 dispatch 委托关系,避免后续混入远程推送、后台推送或散落的本地通知实现。
- 2026-06-18 移动壳 WebView 状态重放:Expo WebView 每次同源主站页面成功加载后都会补发当前 `app.lifecycle``network.statusChanged` 状态,覆盖首载、受控刷新、H5 刷新和系统回收 WebView 进程后的新 JS 上下文;补发不新增 HostBridge capability,也不向 `about:blank`、外域或错误页注入宿主状态。
- 2026-06-20 移动壳加载失败边界:Expo 壳 `onError` / `onHttpError` 只对同源 H5 主页面展示原生失败兜底层,外域、`about:blank`、危险协议、favicon 和非当前主页面资源失败不得触发兜底。移动壳配置检查会反查 `loadFailure.test.ts` 的同源、favicon 和当前主页面测试,避免错误页策略漂移。
- 2026-06-18 桌面壳 WebView 状态重放:Tauri 主 WebView 每次页面加载完成后都会回放当前 `app.lifecycle` 并重新安装 `network.statusChanged` 监听脚本,覆盖托盘刷新、`app.reloadWebView` 和 H5 自刷新后的新 JS 上下文;桌面 runtime 同步声明 `host.events` 表示该真实事件通道可用,但仍不开放 Tauri event 插件或额外 command。
- 2026-06-18 桌面壳 H5 返回栈事件:Tauri 壳开始声明 `navigation.canGoBack`,但只通过固定注入脚本追踪当前 H5 文档内的 `pushState` / `replaceState` / `popstate` 路由栈并派发 HostBridge event;不把该能力实现为 request method,不开放 H5 到 Tauri 的 event 写入通道,也不声明跨文档 native back-forward list 真相。
- 2026-06-18 移动壳 H5 返回栈事件:Expo 壳开始用固定 WebView 注入脚本追踪当前 H5 文档内的 `pushState` / `replaceState` / `popstate` 路由栈,并通过内部 `genarrative.mobile.historyState` 消息回传给壳层;壳层把该状态与 `react-native-webview` 原生 `canGoBack` 合成为 HostBridge `navigation.canGoBack` 事件。Android 返回键优先回退 H5 当前文档路由栈,H5 不可回退时才走 WebView 原生 `goBack()`;该内部消息不是 HostBridge request method,不开放通用 H5 -> 原生事件通道,外域 / 危险页面消息仍在进入 HostBridge 前丢弃。