Files
digital-pilates/services/backgroundTaskDebugHelper.ts
richarjiang ea22901553 feat(background-task): 完善iOS后台任务系统并优化断食通知和UI体验
- 修复iOS后台任务注册时机问题,确保任务能正常触发
- 添加后台任务调试辅助工具和完整测试指南
- 优化断食通知系统,增加防抖机制避免频繁重调度
- 改进断食自动续订逻辑,使用固定时间而非相对时间计算
- 优化统计页面布局,添加身体指标section标题
- 增强饮水详情页面视觉效果,改进卡片样式和配色
- 添加用户反馈入口到个人设置页面
- 完善锻炼摘要卡片条件渲染逻辑
- 增强日志记录和错误处理机制

这些改进显著提升了应用的稳定性、性能和用户体验,特别是在iOS后台任务执行和断食功能方面。
2025-11-05 11:23:33 +08:00

308 lines
8.5 KiB
TypeScript
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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 { logger } from '@/utils/logger';
import { NativeModules, Platform } from 'react-native';
import { BackgroundTaskManager } from './backgroundTaskManagerV2';
const NativeBackgroundModule = NativeModules.BackgroundTaskBridge;
export class BackgroundTaskDebugHelper {
private static instance: BackgroundTaskDebugHelper;
static getInstance(): BackgroundTaskDebugHelper {
if (!BackgroundTaskDebugHelper.instance) {
BackgroundTaskDebugHelper.instance = new BackgroundTaskDebugHelper();
}
return BackgroundTaskDebugHelper.instance;
}
/**
* 执行完整的后台任务诊断
*/
async runFullDiagnostics(): Promise<DiagnosticsReport> {
logger.info('[BackgroundTaskDebug] ====== 开始后台任务诊断 ======');
const report: DiagnosticsReport = {
platform: Platform.OS,
timestamp: new Date().toISOString(),
checks: {},
};
// 1. 检查平台支持
report.checks.platformSupport = this.checkPlatformSupport();
// 2. 检查原生模块
report.checks.nativeModule = await this.checkNativeModule();
// 3. 检查后台刷新权限
report.checks.backgroundRefresh = await this.checkBackgroundRefreshStatus();
// 4. 检查待处理任务
report.checks.pendingTasks = await this.checkPendingTasks();
// 5. 检查配置
report.checks.configuration = this.checkConfiguration();
// 6. 检查最后执行时间
report.checks.lastExecution = await this.checkLastExecution();
logger.info('[BackgroundTaskDebug] ====== 诊断完成 ======');
logger.info('[BackgroundTaskDebug] 报告:', JSON.stringify(report, null, 2));
return report;
}
/**
* 检查平台支持
*/
private checkPlatformSupport(): CheckResult {
const isIOS = Platform.OS === 'ios';
return {
status: isIOS ? 'success' : 'error',
message: isIOS
? 'iOS 平台支持后台任务'
: `当前平台 (${Platform.OS}) 不支持后台任务`,
details: {
platform: Platform.OS,
version: Platform.Version,
},
};
}
/**
* 检查原生模块
*/
private async checkNativeModule(): Promise<CheckResult> {
if (!NativeBackgroundModule) {
return {
status: 'error',
message: '原生模块 BackgroundTaskBridge 不可用',
details: {
available: false,
},
};
}
try {
// 尝试调用一个简单的方法来验证模块是否正常工作
const status = await NativeBackgroundModule.backgroundRefreshStatus();
return {
status: 'success',
message: '原生模块可用且正常工作',
details: {
available: true,
backgroundRefreshStatus: status,
},
};
} catch (error) {
return {
status: 'error',
message: '原生模块存在但调用失败',
details: {
available: true,
error: (error as Error).message,
},
};
}
}
/**
* 检查后台刷新权限状态
*/
private async checkBackgroundRefreshStatus(): Promise<CheckResult> {
try {
const manager = BackgroundTaskManager.getInstance();
const status = await manager.getStatus();
const statusText = await manager.checkStatus();
let resultStatus: 'success' | 'warning' | 'error';
let message: string;
switch (status) {
case 'available':
resultStatus = 'success';
message = '后台刷新权限已启用';
break;
case 'denied':
resultStatus = 'error';
message = '后台刷新被拒绝,请在设置中启用';
break;
case 'restricted':
resultStatus = 'error';
message = '后台刷新被限制(可能是家长控制)';
break;
default:
resultStatus = 'warning';
message = `后台刷新状态未知: ${status}`;
}
return {
status: resultStatus,
message,
details: {
status,
statusText,
},
};
} catch (error) {
return {
status: 'error',
message: '检查后台刷新状态失败',
details: {
error: (error as Error).message,
},
};
}
}
/**
* 检查待处理的任务
*/
private async checkPendingTasks(): Promise<CheckResult> {
try {
const manager = BackgroundTaskManager.getInstance();
const pendingRequests = await manager.getPendingRequests();
return {
status: pendingRequests.length > 0 ? 'success' : 'warning',
message: pendingRequests.length > 0
? `${pendingRequests.length} 个待处理任务`
: '没有待处理的任务(可能需要调度)',
details: {
count: pendingRequests.length,
tasks: pendingRequests,
},
};
} catch (error) {
return {
status: 'error',
message: '检查待处理任务失败',
details: {
error: (error as Error).message,
},
};
}
}
/**
* 检查配置
*/
private checkConfiguration(): CheckResult {
const config = {
identifier: 'com.anonymous.digitalpilates.task',
defaultDelay: 15 * 60, // 15分钟
};
return {
status: 'info',
message: '后台任务配置',
details: config,
};
}
/**
* 检查最后执行时间
*/
private async checkLastExecution(): Promise<CheckResult> {
try {
const manager = BackgroundTaskManager.getInstance();
const lastCheckTime = await manager.getLastBackgroundCheckTime();
if (!lastCheckTime) {
return {
status: 'warning',
message: '后台任务从未执行过',
details: {
lastExecution: null,
},
};
}
const timeSinceLastCheck = Date.now() - lastCheckTime;
const hoursSinceLastCheck = timeSinceLastCheck / (1000 * 60 * 60);
return {
status: hoursSinceLastCheck > 24 ? 'warning' : 'success',
message: hoursSinceLastCheck > 24
? `距离上次执行已超过24小时 (${hoursSinceLastCheck.toFixed(1)}小时)`
: `上次执行时间: ${new Date(lastCheckTime).toLocaleString()}`,
details: {
lastExecution: lastCheckTime,
timeSinceLastCheck: `${hoursSinceLastCheck.toFixed(1)} 小时`,
},
};
} catch (error) {
return {
status: 'error',
message: '检查最后执行时间失败',
details: {
error: (error as Error).message,
},
};
}
}
/**
* 生成可读的诊断报告
*/
generateReadableReport(report: DiagnosticsReport): string {
let output = '\n========== 后台任务诊断报告 ==========\n';
output += `时间: ${new Date(report.timestamp).toLocaleString()}\n`;
output += `平台: ${report.platform}\n`;
output += '\n';
Object.entries(report.checks).forEach(([key, check]) => {
const icon = check.status === 'success' ? '✅' : check.status === 'error' ? '❌' : '⚠️';
output += `${icon} ${key}: ${check.message}\n`;
if (check.details && Object.keys(check.details).length > 0) {
output += ` 详情: ${JSON.stringify(check.details, null, 2)}\n`;
}
output += '\n';
});
output += '=====================================\n';
return output;
}
/**
* 模拟触发后台任务(仅用于测试)
*/
async triggerTestTask(): Promise<void> {
logger.info('[BackgroundTaskDebug] 触发测试任务...');
try {
const manager = BackgroundTaskManager.getInstance();
await manager.triggerTaskForTesting();
logger.info('[BackgroundTaskDebug] ✅ 测试任务执行完成');
} catch (error: any) {
const errorCode = error?.code || '';
if (errorCode === 'SIMULATOR_NOT_SUPPORTED') {
logger.info('[BackgroundTaskDebug] 在模拟器上执行了后台任务逻辑');
logger.info('[BackgroundTaskDebug] 模拟器不支持完整的后台任务调度');
logger.info('[BackgroundTaskDebug] 这是正常的,请在真机上测试完整功能');
} else {
logger.error('[BackgroundTaskDebug] ❌ 测试任务执行失败', error);
throw error;
}
}
}
}
export interface DiagnosticsReport {
platform: string;
timestamp: string;
checks: {
[key: string]: CheckResult;
};
}
export interface CheckResult {
status: 'success' | 'warning' | 'error' | 'info';
message: string;
details?: Record<string, any>;
}