import '@/i18n'; import { DefaultTheme, ThemeProvider } from '@react-navigation/native'; import { useFonts } from 'expo-font'; import { Stack } from 'expo-router'; import { StatusBar } from 'expo-status-bar'; import { GestureHandlerRootView } from 'react-native-gesture-handler'; import 'react-native-reanimated'; import PrivacyConsentModal from '@/components/PrivacyConsentModal'; import { useAppDispatch, useAppSelector } from '@/hooks/redux'; import { useQuickActions } from '@/hooks/useQuickActions'; import { clearAiCoachSessionCache } from '@/services/aiCoachSession'; import { notificationService } from '@/services/notifications'; import { setupQuickActions } from '@/services/quickActions'; import { sleepMonitorService } from '@/services/sleepMonitor'; import { initializeWaterRecordBridge } from '@/services/waterRecordBridge'; import { WaterRecordSource } from '@/services/waterRecords'; import { workoutMonitorService } from '@/services/workoutMonitor'; import { store } from '@/store'; import { hydrateActiveSchedule, selectActiveFastingSchedule } from '@/store/fastingSlice'; import { fetchMyProfile, setPrivacyAgreed } from '@/store/userSlice'; import { createWaterRecordAction } from '@/store/waterSlice'; import { loadActiveFastingSchedule } from '@/utils/fasting'; import { ensureHealthPermissions, initializeHealthPermissions } from '@/utils/health'; import { MoodNotificationHelpers, NutritionNotificationHelpers, WaterNotificationHelpers } from '@/utils/notificationHelpers'; import { clearPendingWaterRecords, syncPendingWidgetChanges } from '@/utils/widgetDataSync'; import React, { useEffect } from 'react'; import { DialogProvider } from '@/components/ui/DialogProvider'; import { MembershipModalProvider } from '@/contexts/MembershipModalContext'; import { ToastProvider } from '@/contexts/ToastContext'; import { useAuthGuard } from '@/hooks/useAuthGuard'; import { STORAGE_KEYS } from '@/services/api'; import { BackgroundTaskManager } from '@/services/backgroundTaskManagerV2'; import { fetchChallenges } from '@/store/challengesSlice'; import AsyncStorage from '@/utils/kvStore'; import { logger } from '@/utils/logger'; import { Provider } from 'react-redux'; // 在开发环境中导入调试工具 let BackgroundTaskDebugger: any = null; if (__DEV__) { try { const debuggerModule = require('@/services/backgroundTaskDebugger'); BackgroundTaskDebugger = debuggerModule.BackgroundTaskDebugger; } catch (error) { logger.warn('无法导入后台任务调试工具:', error); } } function Bootstrapper({ children }: { children: React.ReactNode }) { const dispatch = useAppDispatch(); const { profile } = useAppSelector((state) => state.user); const activeFastingSchedule = useAppSelector(selectActiveFastingSchedule); const [showPrivacyModal, setShowPrivacyModal] = React.useState(false); const { isLoggedIn } = useAuthGuard() const fastingHydrationRequestedRef = React.useRef(false); // 初始化快捷动作处理 useQuickActions(); React.useEffect(() => { if (fastingHydrationRequestedRef.current) return; if (activeFastingSchedule) { fastingHydrationRequestedRef.current = true; return; } fastingHydrationRequestedRef.current = true; let cancelled = false; const hydrate = async () => { try { const stored = await loadActiveFastingSchedule(); if (cancelled || !stored) return; if (store.getState().fasting.activeSchedule) return; dispatch(hydrateActiveSchedule(stored)); } catch (error) { logger.warn('恢复断食计划失败:', error); } }; hydrate(); return () => { cancelled = true; }; }, [dispatch, activeFastingSchedule]); useEffect(() => { if (isLoggedIn) { dispatch(fetchChallenges()); } }, [isLoggedIn]); React.useEffect(() => { // ==================== 第一优先级:立即执行(关键路径,0-500ms)==================== const initializeCriticalServices = async () => { try { logger.info('🚀 开始初始化关键服务...'); // 1. 加载用户数据(首屏展示需要) await dispatch(fetchMyProfile()); logger.info('✅ 用户数据加载完成'); // 2. 初始化 HealthKit 权限系统(不请求权限,仅初始化) initializeHealthPermissions(); logger.info('✅ HealthKit 权限系统初始化完成'); // 3. 初始化通知服务基础功能 await notificationService.initialize(); logger.info('✅ 通知服务初始化完成'); // 4. 初始化快捷动作(用户可能立即使用) await setupQuickActions(); logger.info('✅ 快捷动作初始化完成'); // 5. 清空 AI 教练会话缓存(轻量操作) clearAiCoachSessionCache(); logger.info('✅ AI 教练缓存清理完成'); logger.info('🎉 关键服务初始化完成'); } catch (error) { logger.error('❌ 关键服务初始化失败:', error); } }; // ==================== 第二优先级:短延迟(1-2秒后执行)==================== const initializeSecondaryServices = () => { setTimeout(async () => { try { logger.info('⏰ 开始初始化次要服务...'); // 1. 请求 HealthKit 权限(延迟到 3 秒,避免打断用户浏览) setTimeout(async () => { try { await ensureHealthPermissions(); logger.info('✅ HealthKit 权限请求完成'); } catch (error) { logger.warn('⚠️ HealthKit 权限请求失败,可能在模拟器上运行:', error); } }, 3000); // 2. 初始化喝水记录 Bridge initializeWaterRecordBridge(); logger.info('✅ 喝水记录 Bridge 初始化完成'); // 3. 异步同步 Widget 数据(不阻塞主流程) syncWidgetDataInBackground(); logger.info('🎉 次要服务初始化完成'); } catch (error) { logger.error('❌ 次要服务初始化失败:', error); } }, 2000); }; // ==================== 第三优先级:中延迟(3-5秒后或交互完成后执行)==================== const initializeBackgroundServices = () => { // 使用 InteractionManager 确保在所有交互和动画完成后再执行 const { InteractionManager } = require('react-native'); InteractionManager.runAfterInteractions(() => { setTimeout(async () => { try { logger.info('📅 开始初始化后台服务...'); // 1. 批量注册所有通知提醒 await registerAllNotifications(); // 2. 初始化后台任务管理器 await initializeBackgroundTaskManager(); // 3. 初始化健康监听服务 await initializeHealthMonitoring(); logger.info('🎉 后台服务初始化完成'); } catch (error) { logger.error('❌ 后台服务初始化失败:', error); } }, 3000); }); }; // ==================== 第四优先级:空闲时执行(不影响用户体验)==================== const initializeIdleServices = () => { setTimeout(async () => { try { logger.info('🔄 开始初始化空闲服务...'); // 1. 后台任务详细状态检查 await checkBackgroundTaskStatus(); // 2. 开发环境调试工具 if (__DEV__ && BackgroundTaskDebugger) { BackgroundTaskDebugger.getInstance().initialize(); logger.info('✅ 后台任务调试工具已初始化(开发环境)'); } logger.info('🎉 空闲服务初始化完成'); } catch (error) { logger.error('❌ 空闲服务初始化失败:', error); } }, 8000); // 8秒后执行,确保不影响用户体验 }; // ==================== 辅助函数 ==================== // 异步同步 Widget 数据(不阻塞主流程) const syncWidgetDataInBackground = async () => { try { const widgetSync = await syncPendingWidgetChanges(); if (widgetSync.hasPendingChanges && widgetSync.pendingRecords) { logger.info(`🔄 检测到 ${widgetSync.pendingRecords.length} 条待同步的水记录`); // 异步处理每条记录 for (const record of widgetSync.pendingRecords) { try { await store.dispatch(createWaterRecordAction({ amount: record.amount, recordedAt: record.recordedAt, source: WaterRecordSource.Auto, })).unwrap(); logger.info(`✅ 成功同步水记录: ${record.amount}ml at ${record.recordedAt}`); } catch (error) { logger.error('❌ 同步水记录失败:', error); } } // 清除已同步的记录 await clearPendingWaterRecords(); logger.info('✅ 所有待同步的水记录已处理完成'); } } catch (error) { logger.error('❌ Widget 数据同步失败:', error); } }; // 批量注册所有通知提醒 const registerAllNotifications = async () => { try { logger.info('📢 开始批量注册通知提醒...'); // 并行注册所有通知,提高效率 await Promise.all([ // 营养提醒 NutritionNotificationHelpers.scheduleDailyLunchReminder(profile.name || '').then(() => logger.info('✅ 午餐提醒已注册') ), NutritionNotificationHelpers.scheduleDailyDinnerReminder(profile.name || '').then(() => logger.info('✅ 晚餐提醒已注册') ), // 心情提醒 MoodNotificationHelpers.scheduleDailyMoodReminder(profile.name || '').then(() => logger.info('✅ 心情提醒已注册') ), // 喝水提醒 WaterNotificationHelpers.scheduleRegularWaterReminders(profile.name || '用户').then(() => logger.info('✅ 喝水提醒已注册') ), ]); // 检查断食通知(如果有活跃计划) const fastingSchedule = store.getState().fasting.activeSchedule; if (fastingSchedule) { logger.info('✅ 检测到活跃的断食计划,将通过页面 hook 自动安排通知'); } logger.info('🎉 所有通知提醒注册完成'); } catch (error) { logger.error('❌ 通知提醒注册失败:', error); } }; // 初始化后台任务管理器 const initializeBackgroundTaskManager = async () => { try { logger.info('⚙️ 初始化后台任务管理器...'); await BackgroundTaskManager.getInstance().initialize(); logger.info('✅ 后台任务管理器初始化成功'); // 简单的任务调度检查 const taskManager = BackgroundTaskManager.getInstance(); const status = await taskManager.getStatus(); if (status === 'available') { const pendingRequests = await taskManager.getPendingRequests(); if (pendingRequests.length === 0) { await taskManager.scheduleNextTask(); logger.info('✅ 已调度新的后台任务'); } } } catch (error) { logger.error('❌ 后台任务管理器初始化失败:', error); } }; // 初始化健康监听服务(锻炼 + 睡眠) const initializeHealthMonitoring = async () => { try { logger.info('💪 初始化健康监听服务...'); // 并行初始化锻炼和睡眠监听 await Promise.allSettled([ workoutMonitorService.initialize().then(() => logger.info('✅ 锻炼监听服务初始化成功') ), sleepMonitorService.initialize().then(() => logger.info('✅ 睡眠监听服务初始化成功') ), ]); logger.info('🎉 健康监听服务初始化完成'); } catch (error) { logger.error('❌ 健康监听服务初始化失败:', error); } }; // 后台任务详细状态检查(空闲时执行) const checkBackgroundTaskStatus = async () => { try { logger.info('🔍 检查后台任务详细状态...'); const taskManager = BackgroundTaskManager.getInstance(); const status = await taskManager.getStatus(); const statusText = await taskManager.checkStatus(); logger.info(`📊 后台任务状态: ${status} (${statusText})`); // 检查上次执行时间 const lastCheckTime = await taskManager.getLastBackgroundCheckTime(); if (lastCheckTime) { const timeSinceLastCheck = Date.now() - lastCheckTime; const hoursSinceLastCheck = timeSinceLastCheck / (1000 * 60 * 60); logger.info(`⏱️ 上次执行: ${new Date(lastCheckTime).toLocaleString()} (${hoursSinceLastCheck.toFixed(1)}小时前)`); if (hoursSinceLastCheck > 24) { logger.warn('⚠️ 超过24小时未执行后台任务,请检查系统设置'); } } logger.info('✅ 后台任务状态检查完成'); } catch (error) { logger.error('❌ 后台任务状态检查失败:', error); } }; // ==================== 执行初始化流程 ==================== // 立即执行关键服务 initializeCriticalServices(); // 延迟执行次要服务 initializeSecondaryServices(); // 交互完成后执行后台服务 initializeBackgroundServices(); // 空闲时执行非关键服务 initializeIdleServices(); }, [dispatch, profile.name]); React.useEffect(() => { const getPrivacyAgreed = async () => { const str = await AsyncStorage.getItem(STORAGE_KEYS.privacyAgreed) setShowPrivacyModal(str !== 'true'); } getPrivacyAgreed(); }, []); const handlePrivacyAgree = () => { dispatch(setPrivacyAgreed()); setShowPrivacyModal(false); }; const handlePrivacyDisagree = () => { // RNExitApp.exitApp(); }; return ( {children} ); } export default function RootLayout() { const [loaded] = useFonts({ SpaceMono: require('../assets/fonts/SpaceMono-Regular.ttf'), }); if (!loaded) { // Async font loading only occurs in development. return null; } return ( ); }