From dd2e3f4db10c5661e11be0d645af39a1ee52dc70 Mon Sep 17 00:00:00 2001 From: kdletters Date: Fri, 19 Jun 2026 17:03:23 +0800 Subject: [PATCH] =?UTF-8?q?=E9=94=81=E5=AE=9A=E7=A7=BB=E5=8A=A8=E5=A3=B3?= =?UTF-8?q?=E6=9D=83=E9=99=90=E8=AF=B4=E6=98=8E=E6=96=87=E6=A1=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 要求相册权限说明只描述选择图片导入 要求相机权限说明分别对应拍摄素材和二维码扫描 同步移动壳权限文案防漂移决策记录 --- apps/mobile-shell/scripts/check-config.mjs | 21 +++++++++++++------ .../scripts/check-expo-config.mjs | 18 ++++++++-------- .../shared-memory/decision-log.md | 2 +- 3 files changed, 25 insertions(+), 16 deletions(-) diff --git a/apps/mobile-shell/scripts/check-config.mjs b/apps/mobile-shell/scripts/check-config.mjs index 316156035..48765dd5f 100644 --- a/apps/mobile-shell/scripts/check-config.mjs +++ b/apps/mobile-shell/scripts/check-config.mjs @@ -1348,11 +1348,17 @@ if (!imagePickerPlugin) { if (Array.isArray(imagePickerPlugin)) { const pluginOptions = imagePickerPlugin[1] ?? {}; - if (typeof pluginOptions.photosPermission !== 'string') { - throw new Error('mobile shell image picker photo permission text is missing'); + if ( + pluginOptions.photosPermission !== + '允许 Genarrative 读取你选择的图片,用于导入创作素材和参考图。' + ) { + throw new Error('mobile shell image picker photo permission text must describe selected creative image import'); } - if (typeof pluginOptions.cameraPermission !== 'string') { - throw new Error('mobile shell image picker camera permission text is missing'); + if ( + pluginOptions.cameraPermission !== + '允许 Genarrative 使用相机拍摄创作素材和参考图。' + ) { + throw new Error('mobile shell image picker camera permission text must describe creative image capture'); } if ( pluginOptions.microphonePermission !== @@ -1371,8 +1377,11 @@ if (!cameraPlugin) { if (Array.isArray(cameraPlugin)) { const pluginOptions = cameraPlugin[1] ?? {}; - if (typeof pluginOptions.cameraPermission !== 'string') { - throw new Error('mobile shell camera permission text is missing'); + if ( + pluginOptions.cameraPermission !== + '允许 Genarrative 使用相机扫描二维码。' + ) { + throw new Error('mobile shell camera permission text must describe QR scanning'); } if ( pluginOptions.microphonePermission !== diff --git a/apps/mobile-shell/scripts/check-expo-config.mjs b/apps/mobile-shell/scripts/check-expo-config.mjs index cb1597d91..2375a55e5 100644 --- a/apps/mobile-shell/scripts/check-expo-config.mjs +++ b/apps/mobile-shell/scripts/check-expo-config.mjs @@ -292,14 +292,14 @@ if (!Array.isArray(imagePickerPlugin)) { throw new Error('Expo config image picker plugin is missing options'); } assertEqual( - typeof imagePickerPlugin[1]?.photosPermission, - 'string', - 'image picker photo permission text type', + imagePickerPlugin[1]?.photosPermission, + '允许 Genarrative 读取你选择的图片,用于导入创作素材和参考图。', + 'image picker photo permission text', ); assertEqual( - typeof imagePickerPlugin[1]?.cameraPermission, - 'string', - 'image picker camera permission text type', + imagePickerPlugin[1]?.cameraPermission, + '允许 Genarrative 使用相机拍摄创作素材和参考图。', + 'image picker camera permission text', ); assertEqual( imagePickerPlugin[1]?.microphonePermission, @@ -312,9 +312,9 @@ if (!Array.isArray(cameraPlugin)) { throw new Error('Expo config camera plugin is missing options'); } assertEqual( - typeof cameraPlugin[1]?.cameraPermission, - 'string', - 'camera permission text type', + cameraPlugin[1]?.cameraPermission, + '允许 Genarrative 使用相机扫描二维码。', + 'camera permission text', ); assertEqual( cameraPlugin[1]?.microphonePermission, diff --git a/docs/project-memory/shared-memory/decision-log.md b/docs/project-memory/shared-memory/decision-log.md index 8654ea4dc..099d7dc56 100644 --- a/docs/project-memory/shared-memory/decision-log.md +++ b/docs/project-memory/shared-memory/decision-log.md @@ -2417,7 +2417,7 @@ ## 2026-06-18 原生壳身份与 capability 作用域门禁 - 背景:Expo 移动壳和 Tauri 桌面壳已经具备首批真实 HostBridge 能力,但如果包身份、桥版本、Android 默认权限、Tauri 窗口列表或 capability 文件在后续迭代中漂移,会把 H5 主站装进更宽的宿主权限面。 -- 决策:移动壳配置门禁固定 Expo `name`、`slug`、`userInterfaceStyle`、`assetBundlePatterns`、`extra.genarrativeHostBridgeVersion`;Android 源 `app.json.permissions` 只能手写 `RECORD_AUDIO` 供同源 H5 实时声音玩法使用,`CAMERA` 必须只由真实 `expo-camera` / `expo-image-picker` 插件为扫码和拍摄能力生成到最终 Expo public config,仍通过 `blockedPermissions` 阻断当前不需要的高风险权限;`apps/mobile-shell/scripts/check-config.mjs` 检查源 `app.json`,`apps/mobile-shell/scripts/check-expo-config.mjs` 检查 Expo CLI 最终解析出的 public config,防止 config plugin 或解析阶段引入身份、资源或权限漂移。新增权限必须先有真实宿主能力、系统权限说明和 H5 fallback。桌面壳配置门禁固定唯一 `label=main` 主窗口,`src-tauri/capabilities/` 只能存在 `main.json`,且该 capability 只能绑定 `windows=["main"]`、`permissions=["allow-host-bridge-request"]`,继续只暴露 `host_bridge_request` 一个受控入口。 +- 决策:移动壳配置门禁固定 Expo `name`、`slug`、`userInterfaceStyle`、`assetBundlePatterns`、`extra.genarrativeHostBridgeVersion`;Android 源 `app.json.permissions` 只能手写 `RECORD_AUDIO` 供同源 H5 实时声音玩法使用,`CAMERA` 必须只由真实 `expo-camera` / `expo-image-picker` 插件为扫码和拍摄能力生成到最终 Expo public config,仍通过 `blockedPermissions` 阻断当前不需要的高风险权限;相册、相机、麦克风权限说明必须锁定为对应真实能力的最小描述,不能退化成泛化采集或后台能力说明;`apps/mobile-shell/scripts/check-config.mjs` 检查源 `app.json`,`apps/mobile-shell/scripts/check-expo-config.mjs` 检查 Expo CLI 最终解析出的 public config,防止 config plugin 或解析阶段引入身份、资源、权限和权限文案漂移。新增权限必须先有真实宿主能力、系统权限说明和 H5 fallback。桌面壳配置门禁固定唯一 `label=main` 主窗口,`src-tauri/capabilities/` 只能存在 `main.json`,且该 capability 只能绑定 `windows=["main"]`、`permissions=["allow-host-bridge-request"]`,继续只暴露 `host_bridge_request` 一个受控入口。 - 影响范围:`apps/mobile-shell/scripts/check-config.mjs`、`apps/mobile-shell/scripts/check-expo-config.mjs`、`apps/desktop-shell/scripts/check-config.mjs`、Expo / Tauri HostBridge 方案文档。 - 验证方式:`npm run check:native-shells`、`npm run typecheck`、`npm run check:encoding`、`git diff --check`。