import { store } from '@/store'; import { StandReminderHelpers, WaterNotificationHelpers } from '@/utils/notificationHelpers'; import AsyncStorage from '@react-native-async-storage/async-storage'; import BackgroundFetch from 'react-native-background-fetch'; /** * 后台任务标识符 */ export const BACKGROUND_TASK_IDS = { WATER_REMINDER: 'water-reminder-task', STAND_REMINDER: 'stand-reminder-task', } as const; /** * 后台任务管理器 * 负责配置和管理 iOS 应用的后台任务执行 */ export class BackgroundTaskManager { private static instance: BackgroundTaskManager; private isInitialized = false; static getInstance(): BackgroundTaskManager { if (!BackgroundTaskManager.instance) { BackgroundTaskManager.instance = new BackgroundTaskManager(); } return BackgroundTaskManager.instance; } /** * 初始化后台任务管理器 */ async initialize(): Promise { if (this.isInitialized) { console.log('后台任务管理器已初始化'); return; } try { // 配置后台获取 const status = await BackgroundFetch.configure({ minimumFetchInterval: 15, // 最小间隔15分钟(单位:秒) }, async (taskId) => { console.log('[BackgroundFetch] 后台任务执行:', taskId); await this.executeBackgroundTasks(); // 完成任务 BackgroundFetch.finish(taskId); }, (error) => { console.error('[BackgroundFetch] 配置失败:', error); }); console.log('[BackgroundFetch] 配置状态:', status); this.isInitialized = true; console.log('后台任务管理器初始化完成'); // 初始化完成后自动启动后台任务 await this.start(); console.log('后台任务已自动启动'); } catch (error) { console.error('初始化后台任务管理器失败:', error); throw error; } } /** * 执行后台任务 */ private async executeBackgroundTasks(): Promise { console.log('开始执行后台任务...'); try { // 检查应用权限和用户设置 const hasPermission = await this.checkNotificationPermissions(); if (!hasPermission) { console.log('没有通知权限,跳过后台任务'); return; } // 获取用户名 const state = store.getState(); const userName = state.user.profile?.name || '朋友'; // 发送测试通知 const Notifications = await import('expo-notifications'); await Notifications.scheduleNotificationAsync({ content: { title: '测试通知', body: `你好 ${userName}!这是一条测试消息,用于验证通知功能是否正常工作。`, data: { type: 'test_notification', timestamp: Date.now() }, sound: true, priority: Notifications.AndroidNotificationPriority.HIGH, }, trigger: null, // 立即发送 }); // 执行喝水提醒检查任务 await this.executeWaterReminderTask(); // 执行站立提醒检查任务 await this.executeStandReminderTask(); console.log('后台任务执行完成'); } catch (error) { console.error('执行后台任务失败:', error); } } /** * 执行喝水提醒后台任务 */ private async executeWaterReminderTask(): Promise { try { console.log('执行喝水提醒后台任务...'); // 获取当前状态 const state = store.getState(); const waterStats = state.water.todayStats; const userProfile = state.user.profile; // 检查是否有喝水目标设置 if (!waterStats || !waterStats.dailyGoal || waterStats.dailyGoal <= 0) { console.log('没有设置喝水目标,跳过喝水提醒'); return; } // 检查时间限制(避免深夜打扰) const currentHour = new Date().getHours(); if (currentHour < 9 || currentHour >= 21) { console.log(`当前时间${currentHour}点,不在提醒时间范围内,跳过喝水提醒`); return; } // 获取用户名 const userName = userProfile?.name || '朋友'; // 构造今日统计数据 const todayWaterStats = { totalAmount: waterStats.totalAmount || 0, dailyGoal: waterStats.dailyGoal, completionRate: waterStats.completionRate || 0 }; // 调用喝水通知检查函数 const notificationSent = await WaterNotificationHelpers.checkWaterGoalAndNotify( userName, todayWaterStats, currentHour ); if (notificationSent) { console.log('后台喝水提醒通知已发送'); // 记录后台任务执行时间 await AsyncStorage.setItem('@last_background_water_check', Date.now().toString()); } else { console.log('无需发送后台喝水提醒通知'); } } catch (error) { console.error('执行喝水提醒后台任务失败:', error); } } /** * 执行站立提醒后台任务 */ private async executeStandReminderTask(): Promise { try { console.log('执行站立提醒后台任务...'); // 获取当前状态 const state = store.getState(); const userProfile = state.user.profile; // 检查时间限制(工作时间内提醒,避免深夜或清晨打扰) const currentHour = new Date().getHours(); if (currentHour < 9 || currentHour >= 21) { console.log(`当前时间${currentHour}点,不在站立提醒时间范围内,跳过站立提醒`); return; } // 获取用户名 const userName = userProfile?.name || '朋友'; // 调用站立提醒检查函数 const notificationSent = await StandReminderHelpers.checkStandStatusAndNotify(userName); if (notificationSent) { console.log('后台站立提醒通知已发送'); // 记录后台任务执行时间 await AsyncStorage.setItem('@last_background_stand_check', Date.now().toString()); } else { console.log('无需发送后台站立提醒通知'); } } catch (error) { console.error('执行站立提醒后台任务失败:', error); } } /** * 检查通知权限 */ private async checkNotificationPermissions(): Promise { try { const Notifications = await import('expo-notifications'); const { status } = await Notifications.getPermissionsAsync(); return status === 'granted'; } catch (error) { console.error('检查通知权限失败:', error); return false; } } /** * 启动后台任务 */ async start(): Promise { try { BackgroundFetch.scheduleTask({ taskId: 'com.anonymous.digitalpilates.backgroundfetch', delay: 15 * 60 * 1000 }); await BackgroundFetch.start(); console.log('后台任务已启动'); } catch (error) { console.error('启动后台任务失败:', error); } } /** * 停止后台任务 */ async stop(): Promise { try { await BackgroundFetch.stop(); console.log('后台任务已停止'); } catch (error) { console.error('停止后台任务失败:', error); } } /** * 获取后台任务状态 */ async getStatus(): Promise { try { return await BackgroundFetch.status(); } catch (error) { console.error('获取后台任务状态失败:', error); return BackgroundFetch.STATUS_DENIED; } } /** * 检查后台任务状态 */ async checkStatus(): Promise { const status = await this.getStatus(); switch (status) { case BackgroundFetch.STATUS_AVAILABLE: return '可用'; case BackgroundFetch.STATUS_DENIED: return '被拒绝'; case BackgroundFetch.STATUS_RESTRICTED: return '受限制'; default: return '未知'; } } /** * 测试后台任务 */ async testBackgroundTask(): Promise { console.log('开始测试后台任务...'); try { // 手动触发后台任务执行 await this.executeBackgroundTasks(); console.log('后台任务测试完成'); } catch (error) { console.error('后台任务测试失败:', error); } } /** * 注册喝水提醒后台任务 */ async registerWaterReminderTask(): Promise { console.log('注册喝水提醒后台任务...'); try { // 检查是否已经初始化 if (!this.isInitialized) { await this.initialize(); } // 启动后台任务 await this.start(); console.log('喝水提醒后台任务注册成功'); } catch (error) { console.error('注册喝水提醒后台任务失败:', error); throw error; } } /** * 取消喝水提醒后台任务 */ async unregisterWaterReminderTask(): Promise { console.log('取消喝水提醒后台任务...'); try { await this.stop(); console.log('喝水提醒后台任务已取消'); } catch (error) { console.error('取消喝水提醒后台任务失败:', error); throw error; } } /** * 获取最后一次后台检查时间 */ async getLastBackgroundCheckTime(): Promise { try { const lastCheck = await AsyncStorage.getItem('@last_background_water_check'); return lastCheck ? parseInt(lastCheck) : null; } catch (error) { console.error('获取最后后台检查时间失败:', error); return null; } } /** * 注册站立提醒后台任务 */ async registerStandReminderTask(): Promise { console.log('注册站立提醒后台任务...'); try { // 检查是否已经初始化 if (!this.isInitialized) { await this.initialize(); } // 启动后台任务 await this.start(); console.log('站立提醒后台任务注册成功'); } catch (error) { console.error('注册站立提醒后台任务失败:', error); throw error; } } /** * 取消站立提醒后台任务 */ async unregisterStandReminderTask(): Promise { console.log('取消站立提醒后台任务...'); try { // 取消所有相关通知 await StandReminderHelpers.cancelStandReminders(); console.log('站立提醒后台任务已取消'); } catch (error) { console.error('取消站立提醒后台任务失败:', error); throw error; } } /** * 获取最后一次站立检查时间 */ async getLastStandCheckTime(): Promise { try { const lastCheck = await AsyncStorage.getItem('@last_background_stand_check'); return lastCheck ? parseInt(lastCheck) : null; } catch (error) { console.error('获取最后站立检查时间失败:', error); return null; } } /** * 测试站立提醒任务 */ async testStandReminderTask(): Promise { console.log('开始测试站立提醒后台任务...'); try { // 手动触发站立提醒任务执行 await this.executeStandReminderTask(); console.log('站立提醒后台任务测试完成'); } catch (error) { console.error('站立提醒后台任务测试失败:', error); } } } /** * 后台任务管理器单例实例 */ export const backgroundTaskManager = BackgroundTaskManager.getInstance(); /** * 后台任务事件类型 */ export interface BackgroundTaskEvent { taskId: string; timestamp: number; success: boolean; error?: string; }