记录移动返回栈同步失败

移动 WebView 返回栈注入脚本写入 history state 失败时记录日志

移动壳测试和配置检查拒绝返回栈脚本空 catch

共享决策日志补充移动返回栈同步失败边界
This commit is contained in:
2026-06-20 10:13:14 +08:00
parent 77a2bacb7a
commit 7c8ef52e86
4 changed files with 44 additions and 1 deletions
@@ -1520,12 +1520,20 @@ for (const snippet of [
'genarrative.mobile.historyState',
'__genarrativeMobileHistoryIndex',
'__GENARRATIVE_MOBILE_POST_NAVIGATION_STATE__',
"console.warn('mobile navigation state sync failed', error)",
]) {
if (!webViewPolicySource.includes(snippet)) {
throw new Error(`mobile shell WebView policy missing ${snippet}`);
}
}
if (
webViewPolicySource.includes('catch (error) {}') ||
webViewPolicySource.includes('catch (_error) {}')
) {
throw new Error('mobile shell WebView policy must not hide injected script failures');
}
if (
webViewPolicySource.includes("['blob:'") ||
webViewPolicySource.includes("'filesystem:'")
@@ -169,6 +169,32 @@ describe('TRACK_MOBILE_WEBVIEW_HISTORY_SCRIPT', () => {
);
});
test('路由栈状态写入失败时记录日志', () => {
const postMessage = vi.fn();
const syncError = new Error('history state blocked');
const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => undefined);
window.ReactNativeWebView = {
postMessage,
};
window.history.replaceState = vi.fn(() => {
throw syncError;
}) as typeof window.history.replaceState;
window.eval(TRACK_MOBILE_WEBVIEW_HISTORY_SCRIPT);
expect(warnSpy).toHaveBeenCalledWith(
'mobile navigation state sync failed',
syncError,
);
expect(postMessage).toHaveBeenCalledWith(
JSON.stringify({
type: 'genarrative.mobile.historyState',
canGoBack: false,
}),
);
warnSpy.mockRestore();
});
test('重复注入时回放当前 H5 路由栈状态', () => {
const postMessage = vi.fn();
window.ReactNativeWebView = {
+3 -1
View File
@@ -176,7 +176,9 @@ export const TRACK_MOBILE_WEBVIEW_HISTORY_SCRIPT = `
'',
window.location.href
);
} catch (error) {}
} catch (error) {
console.warn('mobile navigation state sync failed', error);
}
}
window.history.pushState = function(state, title, url) {
@@ -2958,6 +2958,13 @@
- 影响范围:`apps/mobile-shell/src/shell/ShellApp.tsx``apps/mobile-shell/src/shell/ShellApp.test.tsx``apps/mobile-shell/scripts/check-config.mjs`
- 验证方式:`npm run mobile-shell:test -- src/shell/ShellApp.test.tsx``npm run mobile-shell:typecheck``npm run check:native-shells``npm run check:encoding``git diff --check`
## 2026-06-20 移动壳返回栈状态同步失败不可静默
- 背景:Expo 移动壳通过 WebView 注入脚本追踪当前 H5 文档 history index 并回传 `navigation.canGoBack`;如果 `replaceState(...)` 写入 index 失败后静默吞掉,Android 返回键和 H5 返回按钮状态可能漂移且难以排查。
- 决策:`TRACK_MOBILE_WEBVIEW_HISTORY_SCRIPT``replaceCurrentState()` catch 路径必须输出 `mobile navigation state sync failed` 浏览器 console 警告,同时继续回传当前可返回状态;移动壳配置检查拒绝该注入脚本重新出现空 catch。
- 影响范围:`apps/mobile-shell/src/shell/webViewPolicy.ts``apps/mobile-shell/src/shell/webViewPolicy.test.ts``apps/mobile-shell/scripts/check-config.mjs`
- 验证方式:`npm run mobile-shell:test -- src/shell/webViewPolicy.test.ts``npm run mobile-shell:typecheck``npm run check:native-shells``npm run check:encoding``git diff --check`
## 2026-06-20 移动壳生命周期映射门禁
- 背景:Expo `AppState``active``background``inactive` 以及未知状态都会进入 `app.lifecycle` 事件;如果归一化映射漂移,H5 游戏循环、背景音乐和固定玩法音频会错误恢复或暂停。