From 44d0507d98799a0b9009e79e23c735969ca78332 Mon Sep 17 00:00:00 2001 From: kdletters Date: Thu, 18 Jun 2026 11:06:28 +0800 Subject: [PATCH] =?UTF-8?q?=E6=94=B6=E7=B4=A7=E7=A7=BB=E5=8A=A8=E5=A3=B3?= =?UTF-8?q?=E9=80=9A=E7=9F=A5=E6=9D=83=E9=99=90=E8=BE=B9=E7=95=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 移动壳 Android 包配置阻断重启和精确定时通知权限 移动壳配置检查拒绝远程推送 token 和通知响应监听流程 宿主壳方案和共享决策记录即时本地通知边界 --- apps/mobile-shell/app.json | 5 ++- apps/mobile-shell/scripts/check-config.mjs | 37 ++++++++++++++----- .../scripts/check-expo-config.mjs | 11 ++++++ .../shared-memory/decision-log.md | 1 + ...ExpoReactNative与Tauri宿主壳方案-2026-06-17.md | 3 ++ 5 files changed, 46 insertions(+), 11 deletions(-) diff --git a/apps/mobile-shell/app.json b/apps/mobile-shell/app.json index 5f5d54e6e..3774817df 100644 --- a/apps/mobile-shell/app.json +++ b/apps/mobile-shell/app.json @@ -52,7 +52,10 @@ "allowBackup": false, "softwareKeyboardLayoutMode": "resize", "blockedPermissions": [ - "android.permission.RECORD_AUDIO" + "android.permission.RECORD_AUDIO", + "android.permission.RECEIVE_BOOT_COMPLETED", + "android.permission.SCHEDULE_EXACT_ALARM", + "android.permission.USE_EXACT_ALARM" ], "adaptiveIcon": { "foregroundImage": "./assets/icon.png", diff --git a/apps/mobile-shell/scripts/check-config.mjs b/apps/mobile-shell/scripts/check-config.mjs index d6e7fe30f..9061999be 100644 --- a/apps/mobile-shell/scripts/check-config.mjs +++ b/apps/mobile-shell/scripts/check-config.mjs @@ -38,6 +38,12 @@ const devScaffoldTerms = [ '模' + '拟', '伪' + '造', ]; +const blockedAndroidPermissions = [ + 'android.permission.RECORD_AUDIO', + 'android.permission.RECEIVE_BOOT_COMPLETED', + 'android.permission.SCHEDULE_EXACT_ALARM', + 'android.permission.USE_EXACT_ALARM', +]; function extractStringArrayExport(source, exportName) { const match = source.match( @@ -267,18 +273,16 @@ if (appConfig.android?.softwareKeyboardLayoutMode !== 'resize') { throw new Error('mobile shell Android keyboard layout must resize the WebView'); } -if ( - !appConfig.android?.blockedPermissions?.includes( - 'android.permission.RECORD_AUDIO', - ) -) { - throw new Error('mobile shell Android package must block microphone permission'); +for (const permission of blockedAndroidPermissions) { + if (!appConfig.android?.blockedPermissions?.includes(permission)) { + throw new Error(`mobile shell Android package must block ${permission}`); + } } -if ( - appConfig.android?.permissions?.includes('android.permission.RECORD_AUDIO') -) { - throw new Error('mobile shell Android package must not request microphone'); +for (const permission of blockedAndroidPermissions) { + if (appConfig.android?.permissions?.includes(permission)) { + throw new Error(`mobile shell Android package must not request ${permission}`); + } } if ( @@ -398,6 +402,19 @@ if (Array.isArray(notificationsPlugin)) { } } +for (const forbiddenNotificationSnippet of [ + 'getExpoPushTokenAsync', + 'getDevicePushTokenAsync', + 'addPushTokenListener', + 'addNotificationResponseReceivedListener', +]) { + if (bridgeSource.includes(forbiddenNotificationSnippet)) { + throw new Error( + `mobile shell must not register remote or background notification flow: ${forbiddenNotificationSnippet}`, + ); + } +} + for (const snippet of [ 'file.exportText', 'file.importText', diff --git a/apps/mobile-shell/scripts/check-expo-config.mjs b/apps/mobile-shell/scripts/check-expo-config.mjs index 1e235d36d..27c854e83 100644 --- a/apps/mobile-shell/scripts/check-expo-config.mjs +++ b/apps/mobile-shell/scripts/check-expo-config.mjs @@ -130,6 +130,17 @@ assertIncludes( 'android.permission.RECORD_AUDIO', 'Android blocked permissions', ); +for (const permission of [ + 'android.permission.RECEIVE_BOOT_COMPLETED', + 'android.permission.SCHEDULE_EXACT_ALARM', + 'android.permission.USE_EXACT_ALARM', +]) { + assertIncludes( + expoConfig.android?.blockedPermissions, + permission, + 'Android background notification blocked permissions', + ); +} assertEqual( expoConfig.android?.adaptiveIcon?.foregroundImage, './assets/icon.png', diff --git a/docs/project-memory/shared-memory/decision-log.md b/docs/project-memory/shared-memory/decision-log.md index e3dceef33..da640d5ca 100644 --- a/docs/project-memory/shared-memory/decision-log.md +++ b/docs/project-memory/shared-memory/decision-log.md @@ -50,6 +50,7 @@ - 2026-06-18 H5 背景音乐接入宿主生命周期:`useBackgroundMusic` 通过 `useHostLifecycleActive()` 消费 `subscribeHostAppLifecycle()` 的归一结果,宿主进入后台、inactive 或桌面窗口失焦时降低音量并暂停音频循环,同时 `suspend` WebAudio context;回到 `active + focused` 且用户原本开启音乐时再恢复播放,不改变用户音量设置。 - 2026-06-18 固定玩法音频接入宿主生命周期:前端新增 `useHostLifecycleActive()` 统一消费 `subscribeHostAppLifecycle()`,`useBackgroundMusic`、拼图运行态和抓大鹅运行态都只依赖该归一状态判断音频可播放性;宿主 inactive、background 或窗口失焦时暂停 `