From 5bd1fb1a8f6c754e0e3759b5a3e4334a82997dfd Mon Sep 17 00:00:00 2001 From: kdletters Date: Thu, 18 Jun 2026 08:23:48 +0800 Subject: [PATCH] =?UTF-8?q?=E5=88=87=E6=8D=A2=E7=A7=BB=E5=8A=A8=E5=A3=B3?= =?UTF-8?q?=E9=BB=98=E8=AE=A4=E4=B8=BB=E7=AB=99=E5=85=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Expo 移动壳默认 H5 地址改为线上主站 本机 Vite 地址仅通过环境变量显式启用 补充默认入口检查测试和架构文档 --- apps/mobile-shell/scripts/check-config.mjs | 14 ++++++++++++++ apps/mobile-shell/src/mobileShellDeepLink.test.ts | 2 +- apps/mobile-shell/src/mobileShellUrl.test.ts | 4 ++++ apps/mobile-shell/src/mobileShellUrl.ts | 2 +- docs/project-memory/shared-memory/decision-log.md | 1 + ...构】ExpoReactNative与Tauri宿主壳方案-2026-06-17.md | 2 ++ 6 files changed, 23 insertions(+), 2 deletions(-) diff --git a/apps/mobile-shell/scripts/check-config.mjs b/apps/mobile-shell/scripts/check-config.mjs index 7802e5f00..d10ba901f 100644 --- a/apps/mobile-shell/scripts/check-config.mjs +++ b/apps/mobile-shell/scripts/check-config.mjs @@ -8,6 +8,8 @@ const appPath = new URL('../App.tsx', import.meta.url); const appSource = fs.readFileSync(appPath, 'utf8'); const bridgePath = new URL('../src/mobileHostBridge.ts', import.meta.url); const bridgeSource = fs.readFileSync(bridgePath, 'utf8'); +const mobileShellUrlPath = new URL('../src/mobileShellUrl.ts', import.meta.url); +const mobileShellUrlSource = fs.readFileSync(mobileShellUrlPath, 'utf8'); const sharedContractPath = new URL( '../../../packages/shared/src/contracts/hostBridge.ts', import.meta.url, @@ -138,6 +140,18 @@ if (appSource.includes('process.env.EXPO_PUBLIC_GENARRATIVE_WEB_URL ||')) { throw new Error('mobile shell App must normalize EXPO_PUBLIC_GENARRATIVE_WEB_URL'); } +if ( + !mobileShellUrlSource.includes( + "DEFAULT_MOBILE_SHELL_WEB_URL = 'https://app.genarrative.world/'", + ) +) { + throw new Error('mobile shell default H5 URL must point to the production web app'); +} + +if (appSource.includes('127.0.0.1:3000')) { + throw new Error('mobile shell App must not hard-code localhost as the default H5 URL'); +} + for (const dependency of [ 'expo-file-system', 'expo-document-picker', diff --git a/apps/mobile-shell/src/mobileShellDeepLink.test.ts b/apps/mobile-shell/src/mobileShellDeepLink.test.ts index 62804b9d4..961170094 100644 --- a/apps/mobile-shell/src/mobileShellDeepLink.test.ts +++ b/apps/mobile-shell/src/mobileShellDeepLink.test.ts @@ -83,7 +83,7 @@ describe('buildMobileShellUrlFromDeepLink', () => { ), ); - expect(url.origin).toBe('http://127.0.0.1:3000'); + expect(url.origin).toBe('https://app.genarrative.world'); expect(url.pathname).toBe('/works/detail'); expect(url.searchParams.get('work')).toBe('PZ-1'); expect(url.searchParams.get('clientRuntime')).toBe('native_app'); diff --git a/apps/mobile-shell/src/mobileShellUrl.test.ts b/apps/mobile-shell/src/mobileShellUrl.test.ts index 9e9684fdc..47295938a 100644 --- a/apps/mobile-shell/src/mobileShellUrl.test.ts +++ b/apps/mobile-shell/src/mobileShellUrl.test.ts @@ -7,6 +7,10 @@ import { } from './mobileShellUrl'; describe('buildMobileShellUrl', () => { + test('默认 H5 地址指向真实主站', () => { + expect(DEFAULT_MOBILE_SHELL_WEB_URL).toBe('https://app.genarrative.world/'); + }); + test('为 H5 附加原生移动壳上下文', () => { const url = new URL( buildMobileShellUrl('https://app.test/works/detail?work=PZ-1', { diff --git a/apps/mobile-shell/src/mobileShellUrl.ts b/apps/mobile-shell/src/mobileShellUrl.ts index 308df5d48..a7064ac7e 100644 --- a/apps/mobile-shell/src/mobileShellUrl.ts +++ b/apps/mobile-shell/src/mobileShellUrl.ts @@ -9,7 +9,7 @@ export type MobileShellUrlOptions = { capabilities: HostBridgeCapability[]; }; -export const DEFAULT_MOBILE_SHELL_WEB_URL = 'http://127.0.0.1:3000/'; +export const DEFAULT_MOBILE_SHELL_WEB_URL = 'https://app.genarrative.world/'; export function resolveMobileShellBaseWebUrl(rawUrl: unknown) { if (typeof rawUrl !== 'string') { diff --git a/docs/project-memory/shared-memory/decision-log.md b/docs/project-memory/shared-memory/decision-log.md index e15171e99..f2ecc1693 100644 --- a/docs/project-memory/shared-memory/decision-log.md +++ b/docs/project-memory/shared-memory/decision-log.md @@ -40,6 +40,7 @@ - 2026-06-18 H5 图片上传接入宿主导入:`CreativeImageInputPanel` 在 `native_app` 且声明 `file.importImage` / `file.captureImage` 时,主图上传和描述参考图上传可分别调用 `importHostImageFile()` / `captureHostImageFile()`,并把宿主返回的 base64 图片转换为现有 `File` 回调;浏览器、小程序和未声明能力的裁剪壳继续走原生 `` 路径,不新增玩法侧上传分叉。 - 2026-06-18 移动壳安全区:Expo 壳根布局使用 `react-native-safe-area-context` 的 `SafeAreaProvider` 与四边 `SafeAreaView` 保护 WebView,避免 H5 主站内容贴进 iOS 刘海、底部 Home Indicator、Android 状态栏或横屏边缘;该能力属于宿主壳布局保护,不新增 H5 占位 UI,不改变玩法 runtime 或 HostBridge capability。 - 2026-06-18 移动壳启动 URL 归一:Expo 壳的 `EXPO_PUBLIC_GENARRATIVE_WEB_URL` 和 deep link 基准地址只接受 `http:` / `https:` 绝对 URL,空值、相对路径、`file:`、`javascript:` 等非法配置回退到默认 H5 地址后再附加 `native_app` 宿主上下文;deep link 仍只映射同源 H5 路径,禁止把外域或危险协议页面装进带完整 HostBridge 的 WebView。 +- 2026-06-18 移动壳默认入口:Expo 壳默认 H5 地址固定为 `https://app.genarrative.world/`,开发联调本机 Vite 必须显式设置 `EXPO_PUBLIC_GENARRATIVE_WEB_URL=http://127.0.0.1:3000/` 或其它允许的 `http:` / `https:` 地址;生产包不得在未配置环境变量时加载设备本机 localhost。 - 2026-06-18 桌面图片拖入接入主图槽位:`CreativeImageInputPanel` 在桌面壳声明 `file.imageDropped` 时订阅宿主拖入事件,只在拖入坐标命中当前主图卡片且未被上层元素遮挡时消费事件,避免窗口级拖入被多个创作面板同时接收;成功后仍转换为现有 `File` 上传回调。 - 2026-06-18 H5 背景音乐接入宿主生命周期:`useBackgroundMusic` 通过 `useHostLifecycleActive()` 消费 `subscribeHostAppLifecycle()` 的归一结果,宿主进入后台、inactive 或桌面窗口失焦时降低音量并暂停音频循环,同时 `suspend` WebAudio context;回到 `active + focused` 且用户原本开启音乐时再恢复播放,不改变用户音量设置。 - 2026-06-18 固定玩法音频接入宿主生命周期:前端新增 `useHostLifecycleActive()` 统一消费 `subscribeHostAppLifecycle()`,`useBackgroundMusic`、拼图运行态和抓大鹅运行态都只依赖该归一状态判断音频可播放性;宿主 inactive、background 或窗口失焦时暂停 `