- 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.
314 lines
9.1 KiB
TypeScript
314 lines
9.1 KiB
TypeScript
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 };
|