Files
digital-pilates/services/backgroundTaskManager.ts

398 lines
11 KiB
TypeScript

import { store } from '@/store';
import { StandReminderHelpers, WaterNotificationHelpers } from '@/utils/notificationHelpers';
import AsyncStorage from '@react-native-async-storage/async-storage';
import * as BackgroundTask from 'expo-background-task';
import * as TaskManager from 'expo-task-manager';
import { TaskManagerTaskBody } from 'expo-task-manager';
/**
* 后台任务标识符
*/
export const BACKGROUND_TASK_IDS = {
WATER_REMINDER: 'water-reminder-task',
STAND_REMINDER: 'stand-reminder-task',
HEALTH_REMINDERS: 'background-health-reminders',
} as const;
// 定义后台任务
TaskManager.defineTask(BACKGROUND_TASK_IDS.HEALTH_REMINDERS, async (body: TaskManagerTaskBody) => {
try {
console.log('[BackgroundTask] 后台任务执行');
await executeBackgroundTasks();
return BackgroundTask.BackgroundTaskResult.Success;
} catch (error) {
console.error('[BackgroundTask] 任务执行失败:', error);
return BackgroundTask.BackgroundTaskResult.Failed;
}
});
// 检查通知权限
async function checkNotificationPermissions(): Promise<boolean> {
try {
const Notifications = await import('expo-notifications');
const { status } = await Notifications.getPermissionsAsync();
return status === 'granted';
} catch (error) {
console.error('检查通知权限失败:', error);
return false;
}
}
// 执行喝水提醒后台任务
async function executeWaterReminderTask(): Promise<void> {
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);
}
}
// 执行站立提醒后台任务
async function executeStandReminderTask(): Promise<void> {
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);
}
}
// 后台任务执行函数
async function executeBackgroundTasks(): Promise<void> {
console.log('开始执行后台任务...');
try {
// 检查应用权限和用户设置
const hasPermission = await checkNotificationPermissions();
if (!hasPermission) {
console.log('没有通知权限,跳过后台任务');
return;
}
// 执行喝水提醒检查任务
await executeWaterReminderTask();
// 执行站立提醒检查任务
await executeStandReminderTask();
console.log('后台任务执行完成');
} catch (error) {
console.error('执行后台任务失败:', error);
}
}
/**
* 后台任务管理器
* 负责配置和管理应用的后台任务执行
*/
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<void> {
if (this.isInitialized) {
console.log('后台任务管理器已初始化');
return;
}
try {
// 注册后台任务
const status = await BackgroundTask.registerTaskAsync(BACKGROUND_TASK_IDS.HEALTH_REMINDERS, {
minimumInterval: 15, // 15分钟
});
console.log('[BackgroundTask] 配置状态:', status);
this.isInitialized = true;
console.log('后台任务管理器初始化完成');
} catch (error) {
console.error('初始化后台任务管理器失败:', error);
throw error;
}
}
/**
* 启动后台任务
*/
async start(): Promise<void> {
try {
await BackgroundTask.registerTaskAsync(BACKGROUND_TASK_IDS.HEALTH_REMINDERS, {
minimumInterval: 15,
});
console.log('后台任务已启动');
} catch (error) {
console.error('启动后台任务失败:', error);
}
}
/**
* 停止后台任务
*/
async stop(): Promise<void> {
try {
await BackgroundTask.unregisterTaskAsync(BACKGROUND_TASK_IDS.HEALTH_REMINDERS);
console.log('后台任务已停止');
} catch (error) {
console.error('停止后台任务失败:', error);
}
}
/**
* 获取后台任务状态
*/
async getStatus(): Promise<BackgroundTask.BackgroundTaskStatus> {
try {
const status = await BackgroundTask.getStatusAsync();
return status || BackgroundTask.BackgroundTaskStatus.Restricted;
} catch (error) {
console.error('获取后台任务状态失败:', error);
return BackgroundTask.BackgroundTaskStatus.Restricted;
}
}
/**
* 检查后台任务状态
*/
async checkStatus(): Promise<string> {
const status = await this.getStatus();
switch (status) {
case BackgroundTask.BackgroundTaskStatus.Available:
return '可用';
case BackgroundTask.BackgroundTaskStatus.Restricted:
return '受限制';
default:
return '未知';
}
}
/**
* 测试后台任务
*/
async testBackgroundTask(): Promise<void> {
console.log('开始测试后台任务...');
try {
// 手动触发后台任务执行
await executeBackgroundTasks();
console.log('后台任务测试完成');
} catch (error) {
console.error('后台任务测试失败:', error);
}
}
/**
* 注册喝水提醒后台任务
*/
async registerWaterReminderTask(): Promise<void> {
console.log('注册喝水提醒后台任务...');
try {
// 检查是否已经初始化
if (!this.isInitialized) {
await this.initialize();
}
// 启动后台任务
await this.start();
console.log('喝水提醒后台任务注册成功');
} catch (error) {
console.error('注册喝水提醒后台任务失败:', error);
throw error;
}
}
/**
* 取消喝水提醒后台任务
*/
async unregisterWaterReminderTask(): Promise<void> {
console.log('取消喝水提醒后台任务...');
try {
await this.stop();
console.log('喝水提醒后台任务已取消');
} catch (error) {
console.error('取消喝水提醒后台任务失败:', error);
throw error;
}
}
/**
* 获取最后一次后台检查时间
*/
async getLastBackgroundCheckTime(): Promise<number | null> {
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<void> {
console.log('注册站立提醒后台任务...');
try {
// 检查是否已经初始化
if (!this.isInitialized) {
await this.initialize();
}
// 启动后台任务
await this.start();
console.log('站立提醒后台任务注册成功');
} catch (error) {
console.error('注册站立提醒后台任务失败:', error);
throw error;
}
}
/**
* 取消站立提醒后台任务
*/
async unregisterStandReminderTask(): Promise<void> {
console.log('取消站立提醒后台任务...');
try {
// 取消所有相关通知
await StandReminderHelpers.cancelStandReminders();
console.log('站立提醒后台任务已取消');
} catch (error) {
console.error('取消站立提醒后台任务失败:', error);
throw error;
}
}
/**
* 获取最后一次站立检查时间
*/
async getLastStandCheckTime(): Promise<number | null> {
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<void> {
console.log('开始测试站立提醒后台任务...');
try {
// 手动触发站立提醒任务执行
await executeStandReminderTask();
console.log('站立提醒后台任务测试完成');
} catch (error) {
console.error('站立提醒后台任务测试失败:', error);
}
}
}
/**
* 后台任务管理器单例实例
*/
export const backgroundTaskManager = BackgroundTaskManager.getInstance();
/**
* 后台任务事件类型
*/
export interface BackgroundTaskEvent {
taskId: string;
timestamp: number;
success: boolean;
error?: string;
}