Files
digital-pilates/services/backgroundTaskManager.ts
richarjiang 8b9689b269 Refactor components and enhance background task management
- Updated font sizes and weights in BasalMetabolismCard, MoodCard, HealthDataCard, and NutritionRadarCard for improved readability.
- Removed loading state from MoodCard to simplify the component.
- Adjusted styles in WeightHistoryCard for better layout and spacing.
- Integrated expo-background-fetch for improved background task handling.
- Updated Info.plist to include background fetch capability.
- Enhanced background task registration and execution logic in backgroundTaskManager.
- Added debug function to manually trigger background task execution for testing purposes.
2025-09-03 16:17:29 +08:00

314 lines
9.1 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import AsyncStorage from '@react-native-async-storage/async-storage';
import * as BackgroundFetch from 'expo-background-fetch';
import * as TaskManager from 'expo-task-manager';
// 任务类型定义
export interface BackgroundTask {
id: string;
name: string;
handler: (data?: any) => Promise<void>;
options?: {
minimumInterval?: number; // 最小间隔时间(分钟)
stopOnTerminate?: boolean; // 应用终止时是否停止
startOnBoot?: boolean; // 设备重启时是否启动
};
}
// 任务状态
export interface TaskStatus {
id: string;
isRegistered: boolean;
lastExecution?: Date;
nextExecution?: Date;
executionCount: number;
lastError?: string;
}
// 后台任务管理器类
class BackgroundTaskManager {
private static instance: BackgroundTaskManager;
private tasks: Map<string, BackgroundTask> = new Map();
private taskStatuses: Map<string, TaskStatus> = new Map();
private isInitialized = false;
// 单例模式
public static getInstance(): BackgroundTaskManager {
if (!BackgroundTaskManager.instance) {
BackgroundTaskManager.instance = new BackgroundTaskManager();
}
return BackgroundTaskManager.instance;
}
// 初始化后台任务管理器
public async initialize(): Promise<void> {
if (this.isInitialized) {
return;
}
try {
this.isInitialized = true;
// 注册后台任务
await this.registerBackgroundTask();
// 加载已保存的任务状态
await this.loadTaskStatuses();
console.log('后台任务管理器初始化成功');
} catch (error) {
console.error('后台任务管理器初始化失败:', error);
throw error;
}
}
// 注册后台任务
private async registerBackgroundTask(): Promise<void> {
const BACKGROUND_FETCH_TASK = 'background-fetch-task';
console.log('注册后台获取任务');
// 定义后台获取任务
TaskManager.defineTask(BACKGROUND_FETCH_TASK, async () => {
console.log('后台获取任务被系统调用');
const now = new Date();
try {
console.log(`开始执行后台任务 - ${now.toISOString()}`);
// 执行所有注册的任务
const results = await this.executeAllTasks();
console.log('后台任务执行完成:', results);
// 返回成功状态
return BackgroundFetch.BackgroundFetchResult.NewData;
} catch (error) {
console.error('后台任务执行失败:', error);
return BackgroundFetch.BackgroundFetchResult.Failed;
}
});
// 注册后台获取任务
try {
const status = await BackgroundFetch.getStatusAsync();
if (status === BackgroundFetch.BackgroundFetchStatus.Available) {
await BackgroundFetch.registerTaskAsync(BACKGROUND_FETCH_TASK, {
minimumInterval: 15 * 60, // 15分钟以秒为单位
stopOnTerminate: false,
startOnBoot: true,
});
console.log('后台获取任务注册成功');
} else {
console.warn('后台获取不可用,状态:', status);
}
} catch (error) {
console.error('注册后台获取任务失败:', error);
}
}
// 注册自定义任务
public async registerTask(task: BackgroundTask): Promise<void> {
try {
// 检查任务是否已存在
if (this.tasks.has(task.id)) {
console.warn(`任务 ${task.id} 已存在,将被覆盖`);
}
// 保存任务
this.tasks.set(task.id, task);
// 初始化任务状态
if (!this.taskStatuses.has(task.id)) {
this.taskStatuses.set(task.id, {
id: task.id,
isRegistered: true,
executionCount: 0,
});
}
// 保存任务状态
await this.saveTaskStatuses();
console.log(`任务 ${task.id} 注册成功`);
} catch (error) {
console.error(`注册任务 ${task.id} 失败:`, error);
throw error;
}
}
// 取消注册任务
public async unregisterTask(taskId: string): Promise<void> {
try {
// 移除任务
this.tasks.delete(taskId);
// 更新任务状态
const status = this.taskStatuses.get(taskId);
if (status) {
status.isRegistered = false;
await this.saveTaskStatuses();
}
console.log(`任务 ${taskId} 取消注册成功`);
} catch (error) {
console.error(`取消注册任务 ${taskId} 失败:`, error);
throw error;
}
}
// 手动执行任务
public async executeTask(taskId: string, data?: any): Promise<void> {
try {
const task = this.tasks.get(taskId);
if (!task) {
throw new Error(`任务 ${taskId} 不存在`);
}
console.log(`开始执行任务: ${taskId}`);
// 执行任务
await task.handler(data);
// 更新任务状态
const status = this.taskStatuses.get(taskId);
if (status) {
status.lastExecution = new Date();
status.executionCount += 1;
status.lastError = undefined;
await this.saveTaskStatuses();
}
console.log(`任务 ${taskId} 执行成功`);
} catch (error) {
console.error(`执行任务 ${taskId} 失败:`, error);
// 更新错误状态
const status = this.taskStatuses.get(taskId);
if (status) {
status.lastError = error instanceof Error ? error.message : String(error);
await this.saveTaskStatuses();
}
throw error;
}
}
// 执行所有任务
public async executeAllTasks(): Promise<{ [taskId: string]: 'success' | 'failed' }> {
const results: { [taskId: string]: 'success' | 'failed' } = {};
for (const [taskId, task] of this.tasks) {
try {
await this.executeTask(taskId);
results[taskId] = 'success';
} catch (error) {
console.error(`执行任务 ${taskId} 失败:`, error);
results[taskId] = 'failed';
}
}
return results;
}
// 获取任务状态
public getTaskStatus(taskId: string): TaskStatus | undefined {
return this.taskStatuses.get(taskId);
}
// 获取所有任务状态
public getAllTaskStatuses(): TaskStatus[] {
return Array.from(this.taskStatuses.values());
}
// 获取已注册的任务列表
public getRegisteredTasks(): BackgroundTask[] {
return Array.from(this.tasks.values());
}
// 检查后台任务状态
public async getBackgroundTaskStatus(): Promise<BackgroundFetch.BackgroundFetchStatus | null> {
return await BackgroundFetch.getStatusAsync();
}
// 保存任务状态到本地存储
private async saveTaskStatuses(): Promise<void> {
try {
const statuses = Array.from(this.taskStatuses.values());
await AsyncStorage.setItem('@background_task_statuses', JSON.stringify(statuses));
} catch (error) {
console.error('保存任务状态失败:', error);
}
}
// 从本地存储加载任务状态
private async loadTaskStatuses(): Promise<void> {
try {
const statusesJson = await AsyncStorage.getItem('@background_task_statuses');
if (statusesJson) {
const statuses: TaskStatus[] = JSON.parse(statusesJson);
statuses.forEach(status => {
this.taskStatuses.set(status.id, status);
});
}
} catch (error) {
console.error('加载任务状态失败:', error);
}
}
// 清理过期的任务状态
public async cleanupTaskStatuses(): Promise<void> {
const now = new Date();
const thirtyDaysAgo = new Date(now.getTime() - 30 * 24 * 60 * 60 * 1000);
for (const [taskId, status] of this.taskStatuses) {
if (status.lastExecution && status.lastExecution < thirtyDaysAgo && !status.isRegistered) {
this.taskStatuses.delete(taskId);
}
}
await this.saveTaskStatuses();
}
// 调试函数:强制触发后台任务执行
public async debugExecuteBackgroundTask(): Promise<void> {
console.log('=== 调试:手动触发后台任务执行 ===');
try {
// 获取后台任务状态
const status = await this.getBackgroundTaskStatus();
console.log('后台获取状态:', status);
// 执行所有注册的任务
console.log('当前注册的任务数量:', this.tasks.size);
this.tasks.forEach((task, id) => {
console.log(`- 任务ID: ${id}, 名称: ${task.name}`);
});
const results = await this.executeAllTasks();
console.log('任务执行结果:', results);
// 显示任务状态
const taskStatuses = this.getAllTaskStatuses();
taskStatuses.forEach(status => {
console.log(`任务 ${status.id} 状态:`, {
isRegistered: status.isRegistered,
executionCount: status.executionCount,
lastExecution: status.lastExecution?.toISOString(),
lastError: status.lastError
});
});
} catch (error) {
console.error('调试执行失败:', error);
}
console.log('=== 调试执行完成 ===');
}
}
// 导出单例实例
export const backgroundTaskManager = BackgroundTaskManager.getInstance();
// 导出类型
export type { BackgroundTask as BackgroundTaskType, TaskStatus as TaskStatusType };