收紧移动壳导出产物门禁
移动壳 Expo export smoke 校验 Metro metadata 与 Hermes AppEntry bundle 形态 配置检查反查移动导出产物结构门禁 同步原生壳方案文档和共享决策记录
This commit is contained in:
@@ -663,6 +663,12 @@ for (const snippet of [
|
||||
"'hostVersion'",
|
||||
"'bridgeVersion'",
|
||||
'production bundle must include native host context token',
|
||||
'metadata.version !== 0',
|
||||
'Object.keys(fileMetadata)',
|
||||
'metadata must only include its platform',
|
||||
'metadata must include an assets array',
|
||||
'!bundlePath.startsWith(`_expo/static/js/${platform}/AppEntry-`)',
|
||||
"!bundlePath.endsWith('.hbc')",
|
||||
]) {
|
||||
if (!expoExportSmokeSource.includes(snippet)) {
|
||||
throw new Error(`mobile shell Expo export smoke must verify host context token ${snippet}`);
|
||||
|
||||
@@ -96,11 +96,26 @@ function readMetadata(platform) {
|
||||
}
|
||||
|
||||
const metadata = JSON.parse(fs.readFileSync(metadataPath, 'utf8'));
|
||||
if (metadata.version !== 0) {
|
||||
throw new Error(`Expo ${platform} export metadata version drifted`);
|
||||
}
|
||||
|
||||
if (metadata.bundler !== 'metro') {
|
||||
throw new Error(`Expo ${platform} export must use the Metro bundler`);
|
||||
}
|
||||
|
||||
const bundlePath = metadata.fileMetadata?.[platform]?.bundle;
|
||||
const fileMetadata = metadata.fileMetadata ?? {};
|
||||
const metadataPlatforms = Object.keys(fileMetadata);
|
||||
if (metadataPlatforms.length !== 1 || metadataPlatforms[0] !== platform) {
|
||||
throw new Error(`Expo ${platform} export metadata must only include its platform`);
|
||||
}
|
||||
|
||||
const platformMetadata = fileMetadata[platform];
|
||||
if (!Array.isArray(platformMetadata?.assets)) {
|
||||
throw new Error(`Expo ${platform} export metadata must include an assets array`);
|
||||
}
|
||||
|
||||
const bundlePath = platformMetadata?.bundle;
|
||||
if (typeof bundlePath !== 'string' || bundlePath.length === 0) {
|
||||
throw new Error(`Expo ${platform} export metadata is missing bundle path`);
|
||||
}
|
||||
@@ -119,7 +134,10 @@ function assertBundle(platform, bundlePath) {
|
||||
throw new Error(`Expo ${platform} bundle is unexpectedly small`);
|
||||
}
|
||||
|
||||
if (!bundlePath.includes(`/static/js/${platform}/AppEntry-`)) {
|
||||
if (
|
||||
!bundlePath.startsWith(`_expo/static/js/${platform}/AppEntry-`) ||
|
||||
!bundlePath.endsWith('.hbc')
|
||||
) {
|
||||
throw new Error(`Expo ${platform} bundle path does not target AppEntry`);
|
||||
}
|
||||
|
||||
|
||||
@@ -172,7 +172,7 @@
|
||||
- 2026-06-20 桌面 HostBridge command facade 单测边界:Tauri 唯一 `host_bridge_request` command 必须先通过 `prepare_host_bridge_request(...)` 做 envelope、method 和 request id 校验,再进入 `HostBridgeReplayState` reserve / wait / execute;`apps/desktop-shell/src-tauri/src/host_bridge/mod.rs` 的单测必须覆盖非法 envelope 在 replay 前返回 `invalid_request` 且不会占用对应 request id 的 replay slot,桌面配置检查会反查该测试存在。
|
||||
- 2026-06-20 桌面 HostBridge replay 内部失败边界:Tauri `HostBridgeReplayState` 的 cache lock、slot lock 和 condvar wait 异常不得 panic,也不得把 Rust 内部错误细节回传给 H5;桌面壳只写 `desktop host bridge replay failed for ...` stderr 观测日志,并统一返回 `host_error: desktop host bridge request failed`。桌面配置检查反查 `reserve(...)` 的 `Result` 出口、稳定错误响应和 poison lock 单测。
|
||||
- 2026-06-20 移动 HostBridge runtime 能力回包边界:Expo `host.getRuntime` 回包里的 `capabilities` 必须直接等于共享契约 `HOST_BRIDGE_EXPO_MOBILE_BASE_CAPABILITIES` 或 `HOST_BRIDGE_EXPO_MOBILE_IOS_CAPABILITIES`,并使用与 `platform` 字段一致的归一平台值选择 profile;移动壳 runtime 单测和配置检查反查精确 profile 断言,避免 H5 实际消费的能力回包与入口 URL 能力 query 或共享 profile 分叉。
|
||||
- 2026-06-20 移动 production bundle 宿主上下文边界:`apps/mobile-shell/scripts/check-expo-export.mjs` 必须读取 iOS / Android Metro export bundle,确认可分发 bundle 包含共享生产 H5 URL、`native_app`、`expo_mobile`、`hostCapabilities`、`hostVersion` 和 `bridgeVersion`,且不包含本机开发 H5 URL;移动壳配置检查反查 export smoke 的这些 token,避免生产 bundle 丢失宿主上下文或混入本机入口。
|
||||
- 2026-06-20 移动 production bundle 宿主上下文边界:`apps/mobile-shell/scripts/check-expo-export.mjs` 必须读取 iOS / Android Metro export bundle,确认可分发 bundle metadata 是 Metro version 0、只包含当前平台 `fileMetadata`、指向 Hermes `AppEntry-*.hbc`,且 bundle 包含共享生产 H5 URL、`native_app`、`expo_mobile`、`hostCapabilities`、`hostVersion` 和 `bridgeVersion`,并不包含本机开发 H5 URL;移动壳配置检查反查 export smoke 的这些 token 和 metadata 结构门禁,避免 production bundle 丢失宿主上下文、混入本机入口或导出形态漂移。
|
||||
- 2026-06-20 桌面 release 主窗口宿主上下文边界:Tauri release 配置只保留基础 `index.html`,Rust app 装配层必须在主窗口启动配置单测里断言补齐 `clientRuntime`、`clientType`、`hostShell`、`hostPlatform`、`hostVersion`、`bridgeVersion` 和 `hostCapabilities`;桌面单端配置检查反查这些断言存在,避免首屏 H5 丢失桌面壳运行态 query 后只靠 runtime 回读补救。
|
||||
- 2026-06-20 移动壳协议 helper 单测边界:`apps/mobile-shell/src/host-bridge/protocol.test.ts` 直接覆盖 Expo 移动壳 HostBridge JSON 解析、envelope 和 request id 校验、未知 method 拒绝、ok / failure 响应包装、unsupported / invalid_request 错误构造,以及 native helper 错误归一时只透传共享错误码与字符串 message,不泄露非法错误码、nativeStack 或其它私有字段;根级 `npm run check:native-shells` 会把该测试文件列入移动桥接层结构清单,避免协议边界只靠完整 bridge 流程间接覆盖。
|
||||
- 2026-06-20 移动扫码 overlay 单测边界:`apps/mobile-shell/src/shell/QrScannerOverlay.test.tsx` 直接覆盖移动扫码 overlay 的相机权限请求、二维码扫码成功、权限拒绝失败和关闭取消;单端配置检查会反查该组件测试存在,根级 `npm run check:native-shells` 会把该测试文件列入移动 shell 层结构清单,避免扫码 UI 容器只靠 `ShellApp.test.tsx` 的完整 HostBridge 流程间接覆盖。
|
||||
|
||||
@@ -513,7 +513,7 @@ GameBridge 禁止:
|
||||
|
||||
2026-06-18 追加:移动壳 Expo managed config 烟测进入统一验收。`npm run check:native-shells` 会执行 `npm run mobile-shell:config`,在 `apps/mobile-shell` 目录内调用 `expo config --type public --json`,校验 Expo CLI 实际解析结果中的包名、scheme、深链、ATS / cleartext / backup / 相机与麦克风权限、启动页、adaptive icon、插件配置和 HostBridge 版本没有漂移。
|
||||
|
||||
2026-06-18 追加:移动壳 Metro export 烟测进入统一验收。`npm run check:native-shells` 会执行 `npm run mobile-shell:export`,用 Expo CLI 分别为 Android 和 iOS 生成 production bundle,校验 Metro metadata 与 `AppEntry` bundle 已产出后清理临时 `.expo-export-smoke/` 目录。该烟测不生成 APK、AAB 或 IPA,也不写商店资料,只证明移动壳入口、Expo/RN 依赖和平台差异代码能被真实生产 bundler 打包。
|
||||
2026-06-18 追加:移动壳 Metro export 烟测进入统一验收。`npm run check:native-shells` 会执行 `npm run mobile-shell:export`,用 Expo CLI 分别为 Android 和 iOS 生成 production bundle,校验 Metro metadata 版本、单平台 `fileMetadata`、Hermes `AppEntry-*.hbc` bundle 路径、assets 数组、生产 H5 URL 和原生宿主上下文 token 后清理临时 `.expo-export-smoke/` 目录。该烟测不生成 APK、AAB 或 IPA,也不写商店资料,只证明移动壳入口、Expo/RN 依赖和平台差异代码能被真实生产 bundler 打包。
|
||||
|
||||
2026-06-20 追加:移动壳新增 EAS 原生包构建 profile。`apps/mobile-shell/eas.json` 固定 EAS CLI 下限、使用本地 `app.json` 版本字段,并提供 Android `production` 本地构建脚本产出可安装 APK、iOS `production-simulator` 本地构建脚本产出 release simulator 包;两者都设置 `EXPO_NO_DOTENV=1`,避免本机 `.env` 把开发 H5 URL 或私密配置带进可分发包。当前仍不写商店提交 profile、签名凭据来源、自动递增、OTA runtimeVersion 或 releaseChannel;`npm run check:native-shells` 只跑 `mobile-shell:build-config` 校验构建 profile、脚本、本地 `eas-cli` devDependency 和从 `apps/mobile-shell` 目录解析到的 EAS CLI 版本,真实 `mobile-shell:build:android` / `mobile-shell:build:ios` 作为具备 Android SDK、Xcode / simulator 环境和 EAS 本地构建依赖时的分发构建命令。
|
||||
|
||||
|
||||
Reference in New Issue
Block a user