feat(background): implement user consent mechanism for auto-start functionality
Some checks failed
Frontend CI / ota (android) (push) Has been cancelled
Frontend CI / ota (ios) (push) Has been cancelled
Frontend CI / build-and-push-web (push) Has been cancelled
Frontend CI / build-android-apk (push) Failing after 7m23s

Add auto-start consent system that requires explicit user permission before enabling background sync services. Users can now choose between silent mode (no auto-start) or background mode (15-minute sync intervals).

- Add consent service with AutoStartMode enum and storage utilities
- Create withRemoveAutoStart Expo plugin to disable Android auto-start defaults
- Integrate consent checks into JPush service, background task manager, and foreground service
- Add auto-start consent UI in notification settings with descriptive dialog
- Update privacy policy with section 8 explaining auto-start scenarios and user controls
- Change default sync mode from BATTERY_SAVER to DISABLED
- Export reinitBackgroundService function for re-initializing after consent changes
- Merge OTA Android and iOS workflows into matrix build
- Add release signing config in withSigning plugin for Android
- Expand .dockerignore with native credential and build artifact exclusions
This commit is contained in:
lafay
2026-06-15 20:43:15 +08:00
parent d8ef51fa13
commit f3d54a3f4c
16 changed files with 746 additions and 173 deletions

View File

@@ -0,0 +1,87 @@
/**
* withRemoveAutoStart — 移除应用退出后的自启动/关联启动行为
*
* 整改 2.2.6 APP频繁自启动和关联启动存在风险
*
* 问题:以下 SDK 注册了 BOOT_COMPLETED 等 intent-filter
* 导致设备重启时应用被自动唤醒:
* - expo.modules.taskManager.TaskBroadcastReceiver
* - expo.modules.notifications.service.NotificationsService
* - androidx.work.impl.background.systemalarm.RescheduleReceiver
* - androidx.work.impl.background.systemalarm.ConstraintProxy* (多个)
*
* 本插件在 final manifest 合并阶段移除这些 intent-filter action
* 从根本上消除应用退出后的自启动行为。
*/
const { withAndroidManifest } = require('expo/config-plugins');
// 需要从 receivers 中移除的自启动相关 action
const AUTO_START_ACTIONS = new Set([
'android.intent.action.BOOT_COMPLETED',
'android.intent.action.REBOOT',
'android.intent.action.QUICKBOOT_POWERON',
'com.htc.intent.action.QUICKBOOT_POWERON',
]);
function removeAutoStartActionsFromManifest(androidManifest) {
const app = androidManifest.manifest.application?.[0];
if (!app) return androidManifest;
// 处理 <receiver> 标签
const receivers = app.receiver || [];
for (const receiver of receivers) {
if (!receiver['intent-filter']) continue;
receiver['intent-filter'] = receiver['intent-filter'].map((filter) => {
if (!filter.action) return filter;
const originalCount = filter.action.length;
filter.action = filter.action.filter(
(action) => !AUTO_START_ACTIONS.has(action.$?.['android:name'])
);
if (filter.action.length !== originalCount) {
const removed = originalCount - filter.action.length;
console.log(
`[withRemoveAutoStart] 移除了 ${removed} 个自启动 action (receiver)`
);
}
return filter;
});
// 如果 intent-filter 中没有 action 了,移除整个 intent-filter
receiver['intent-filter'] = receiver['intent-filter'].filter(
(filter) => filter.action && filter.action.length > 0
);
}
// 移除 RECEIVE_BOOT_COMPLETED 权限声明
if (androidManifest.manifest['uses-permission']) {
const originalPerms = androidManifest.manifest['uses-permission'].length;
androidManifest.manifest['uses-permission'] = androidManifest.manifest[
'uses-permission'
].filter((perm) => {
const name = perm.$?.['android:name'];
return name !== 'android.permission.RECEIVE_BOOT_COMPLETED';
});
const removedPerms = originalPerms - androidManifest.manifest['uses-permission'].length;
if (removedPerms > 0) {
console.log(
`[withRemoveAutoStart] 移除了 RECEIVE_BOOT_COMPLETED 权限声明 (${removedPerms} 处)`
);
}
}
return androidManifest;
}
function withRemoveAutoStart(config) {
return withAndroidManifest(config, (config) => {
config.modResults = removeAutoStartActionsFromManifest(config.modResults);
return config;
});
}
module.exports = withRemoveAutoStart;