refactor(init): 优化应用初始化流程,将权限请求延迟到引导完成后
- 将服务初始化拆分为基础服务和权限相关服务两个阶段 - 基础服务(用户数据、HealthKit初始化、快捷动作等)在应用启动时立即执行 - 权限相关服务(通知、HealthKit权限请求)仅在用户完成引导流程后才执行 - 在Redux store中添加onboardingCompleted状态管理 - 引导页面完成时通过Redux更新状态而非直接操作AsyncStorage - 启动页面从预加载数据中读取引导完成状态,避免重复读取存储 - 使用ref防止权限服务重复初始化
This commit is contained in:
100
app/_layout.tsx
100
app/_layout.tsx
@@ -51,11 +51,12 @@ if (__DEV__) {
|
||||
|
||||
function Bootstrapper({ children }: { children: React.ReactNode }) {
|
||||
const dispatch = useAppDispatch();
|
||||
const { profile } = useAppSelector((state) => state.user);
|
||||
const { profile, onboardingCompleted } = useAppSelector((state) => state.user);
|
||||
const activeFastingSchedule = useAppSelector(selectActiveFastingSchedule);
|
||||
const [showPrivacyModal, setShowPrivacyModal] = React.useState(false);
|
||||
const { isLoggedIn } = useAuthGuard()
|
||||
const fastingHydrationRequestedRef = React.useRef(false);
|
||||
const permissionInitializedRef = React.useRef(false);
|
||||
|
||||
// 初始化快捷动作处理
|
||||
useQuickActions();
|
||||
@@ -94,11 +95,11 @@ function Bootstrapper({ children }: { children: React.ReactNode }) {
|
||||
}
|
||||
}, [isLoggedIn]);
|
||||
|
||||
// ==================== 基础服务初始化(不需要权限,总是执行)====================
|
||||
React.useEffect(() => {
|
||||
// ==================== 第一优先级:立即执行(关键路径,0-500ms)====================
|
||||
const initializeCriticalServices = async () => {
|
||||
const initializeBasicServices = async () => {
|
||||
try {
|
||||
logger.info('🚀 开始初始化关键服务...');
|
||||
logger.info('🚀 开始初始化基础服务(不需要权限)...');
|
||||
|
||||
// 1. 加载用户数据(首屏展示需要)
|
||||
await dispatch(fetchMyProfile());
|
||||
@@ -108,57 +109,65 @@ function Bootstrapper({ children }: { children: React.ReactNode }) {
|
||||
initializeHealthPermissions();
|
||||
logger.info('✅ HealthKit 权限系统初始化完成');
|
||||
|
||||
// 3. 初始化通知服务基础功能
|
||||
await notificationService.initialize();
|
||||
logger.info('✅ 通知服务初始化完成');
|
||||
|
||||
// 4. 初始化快捷动作(用户可能立即使用)
|
||||
// 3. 初始化快捷动作(用户可能立即使用)
|
||||
await setupQuickActions();
|
||||
logger.info('✅ 快捷动作初始化完成');
|
||||
|
||||
// 5. 清空 AI 教练会话缓存(轻量操作)
|
||||
// 4. 清空 AI 教练会话缓存(轻量操作)
|
||||
clearAiCoachSessionCache();
|
||||
logger.info('✅ AI 教练缓存清理完成');
|
||||
|
||||
logger.info('🎉 关键服务初始化完成');
|
||||
// 5. 初始化喝水记录 Bridge
|
||||
initializeWaterRecordBridge();
|
||||
logger.info('✅ 喝水记录 Bridge 初始化完成');
|
||||
|
||||
logger.info('🎉 基础服务初始化完成');
|
||||
} catch (error) {
|
||||
logger.error('❌ 关键服务初始化失败:', error);
|
||||
logger.error('❌ 基础服务初始化失败:', error);
|
||||
}
|
||||
};
|
||||
|
||||
// ==================== 第二优先级:短延迟(1-2秒后执行)====================
|
||||
const initializeSecondaryServices = () => {
|
||||
setTimeout(async () => {
|
||||
try {
|
||||
logger.info('⏰ 开始初始化次要服务...');
|
||||
initializeBasicServices();
|
||||
}, [dispatch]);
|
||||
|
||||
// 1. 请求 HealthKit 权限(延迟到 3 秒,避免打断用户浏览)
|
||||
setTimeout(async () => {
|
||||
try {
|
||||
await ensureHealthPermissions();
|
||||
logger.info('✅ HealthKit 权限请求完成');
|
||||
} catch (error) {
|
||||
logger.warn('⚠️ HealthKit 权限请求失败,可能在模拟器上运行:', error);
|
||||
}
|
||||
}, 3000);
|
||||
// ==================== 权限相关服务初始化(仅在 onboarding 完成后执行)====================
|
||||
React.useEffect(() => {
|
||||
// 如果还没完成 onboarding,或已经初始化过权限,则跳过
|
||||
if (!onboardingCompleted || permissionInitializedRef.current) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 2. 初始化喝水记录 Bridge
|
||||
initializeWaterRecordBridge();
|
||||
logger.info('✅ 喝水记录 Bridge 初始化完成');
|
||||
permissionInitializedRef.current = true;
|
||||
|
||||
// 3. 异步同步 Widget 数据(不阻塞主流程)
|
||||
syncWidgetDataInBackground();
|
||||
const initializePermissionServices = async () => {
|
||||
try {
|
||||
logger.info('🔐 开始初始化需要权限的服务(onboarding 已完成)...');
|
||||
|
||||
logger.info('🎉 次要服务初始化完成');
|
||||
} catch (error) {
|
||||
logger.error('❌ 次要服务初始化失败:', error);
|
||||
}
|
||||
}, 2000);
|
||||
// 1. 初始化通知服务(包含权限请求)
|
||||
await notificationService.initialize();
|
||||
logger.info('✅ 通知服务初始化完成');
|
||||
|
||||
// 2. 延迟请求 HealthKit 权限(避免立即弹窗打断用户)
|
||||
setTimeout(async () => {
|
||||
try {
|
||||
await ensureHealthPermissions();
|
||||
logger.info('✅ HealthKit 权限请求完成');
|
||||
} catch (error) {
|
||||
logger.warn('⚠️ HealthKit 权限请求失败,可能在模拟器上运行:', error);
|
||||
}
|
||||
}, 2000);
|
||||
|
||||
// 3. 异步同步 Widget 数据
|
||||
syncWidgetDataInBackground();
|
||||
|
||||
logger.info('🎉 权限相关服务初始化完成');
|
||||
} catch (error) {
|
||||
logger.error('❌ 权限相关服务初始化失败:', error);
|
||||
}
|
||||
};
|
||||
|
||||
// ==================== 第三优先级:中延迟(3-5秒后或交互完成后执行)====================
|
||||
// ==================== 后台服务初始化(延迟执行)====================
|
||||
const initializeBackgroundServices = () => {
|
||||
// 使用 InteractionManager 确保在所有交互和动画完成后再执行
|
||||
const { InteractionManager } = require('react-native');
|
||||
|
||||
InteractionManager.runAfterInteractions(() => {
|
||||
@@ -183,7 +192,7 @@ function Bootstrapper({ children }: { children: React.ReactNode }) {
|
||||
});
|
||||
};
|
||||
|
||||
// ==================== 第四优先级:空闲时执行(不影响用户体验)====================
|
||||
// ==================== 空闲服务初始化====================
|
||||
const initializeIdleServices = () => {
|
||||
setTimeout(async () => {
|
||||
try {
|
||||
@@ -202,7 +211,7 @@ function Bootstrapper({ children }: { children: React.ReactNode }) {
|
||||
} catch (error) {
|
||||
logger.error('❌ 空闲服务初始化失败:', error);
|
||||
}
|
||||
}, 8000); // 8秒后执行,确保不影响用户体验
|
||||
}, 8000);
|
||||
};
|
||||
|
||||
// ==================== 辅助函数 ====================
|
||||
@@ -350,13 +359,8 @@ function Bootstrapper({ children }: { children: React.ReactNode }) {
|
||||
}
|
||||
};
|
||||
|
||||
// ==================== 执行初始化流程 ====================
|
||||
|
||||
// 立即执行关键服务
|
||||
initializeCriticalServices();
|
||||
|
||||
// 延迟执行次要服务
|
||||
initializeSecondaryServices();
|
||||
// 执行权限相关初始化
|
||||
initializePermissionServices();
|
||||
|
||||
// 交互完成后执行后台服务
|
||||
initializeBackgroundServices();
|
||||
@@ -364,7 +368,7 @@ function Bootstrapper({ children }: { children: React.ReactNode }) {
|
||||
// 空闲时执行非关键服务
|
||||
initializeIdleServices();
|
||||
|
||||
}, [dispatch, profile.name]);
|
||||
}, [onboardingCompleted, profile.name]);
|
||||
|
||||
React.useEffect(() => {
|
||||
|
||||
|
||||
Reference in New Issue
Block a user