feat(background-task): 完善iOS后台任务系统并优化断食通知和UI体验
- 修复iOS后台任务注册时机问题,确保任务能正常触发 - 添加后台任务调试辅助工具和完整测试指南 - 优化断食通知系统,增加防抖机制避免频繁重调度 - 改进断食自动续订逻辑,使用固定时间而非相对时间计算 - 优化统计页面布局,添加身体指标section标题 - 增强饮水详情页面视觉效果,改进卡片样式和配色 - 添加用户反馈入口到个人设置页面 - 完善锻炼摘要卡片条件渲染逻辑 - 增强日志记录和错误处理机制 这些改进显著提升了应用的稳定性、性能和用户体验,特别是在iOS后台任务执行和断食功能方面。
This commit is contained in:
327
docs/background-task-testing-guide.md
Normal file
327
docs/background-task-testing-guide.md
Normal file
@@ -0,0 +1,327 @@
|
||||
# iOS 后台任务测试指南
|
||||
|
||||
## 问题诊断与修复
|
||||
|
||||
### 已识别的问题
|
||||
|
||||
1. **AppDelegate 注册时机错误** ✅ 已修复
|
||||
|
||||
- 问题:后台任务处理器在 `super.application()` 之后注册
|
||||
- 修复:移至 `super.application()` 之前注册
|
||||
- 影响:这是导致任务从未执行的主要原因
|
||||
|
||||
2. **缺少详细日志** ✅ 已修复
|
||||
|
||||
- 添加了全面的日志记录
|
||||
- 改进了错误处理和报告
|
||||
|
||||
3. **测试机制不完善** ✅ 已修复
|
||||
- 添加了调试辅助工具
|
||||
- 提供了诊断命令
|
||||
|
||||
## 在真机上测试后台任务
|
||||
|
||||
### 前置条件
|
||||
|
||||
1. **设备要求**
|
||||
|
||||
- iOS 13.0 或更高版本
|
||||
- 真机(模拟器不支持 BGTaskScheduler)
|
||||
|
||||
2. **系统设置**
|
||||
|
||||
```
|
||||
设置 > Out Live > 后台App刷新 > 开启
|
||||
```
|
||||
|
||||
3. **开发者设置**
|
||||
```
|
||||
设置 > 开发者 > Background Fetch > 频繁
|
||||
```
|
||||
|
||||
### 方法 1: 使用 Xcode 模拟后台任务(推荐)
|
||||
|
||||
1. **在 Xcode 中打开项目**
|
||||
|
||||
```bash
|
||||
open ios/OutLive.xcworkspace
|
||||
```
|
||||
|
||||
2. **运行应用到真机**
|
||||
|
||||
- 选择真机设备
|
||||
- 点击 Run (⌘R)
|
||||
|
||||
3. **暂停应用执行**
|
||||
|
||||
- 点击 Pause 按钮(或 ⌘⌃Y)
|
||||
|
||||
4. **在 LLDB 控制台中执行命令**
|
||||
|
||||
```lldb
|
||||
e -l objc -- (void)[[BGTaskScheduler sharedScheduler] _simulateLaunchForTaskWithIdentifier:@"com.anonymous.digitalpilates.task"]
|
||||
```
|
||||
|
||||
5. **恢复应用执行**
|
||||
|
||||
- 点击 Continue 按钮(或 ⌘⌃Y)
|
||||
|
||||
6. **查看日志**
|
||||
- 在 Xcode Console 中查看后台任务执行日志
|
||||
- 应该看到 `[AppDelegate] ====== 后台任务被触发 ======`
|
||||
|
||||
### 方法 2: 使用应用内调试功能
|
||||
|
||||
1. **在应用中调用诊断工具**
|
||||
|
||||
```typescript
|
||||
import { BackgroundTaskDebugHelper } from "@/services/backgroundTaskDebugHelper";
|
||||
|
||||
// 运行完整诊断
|
||||
const helper = BackgroundTaskDebugHelper.getInstance();
|
||||
const report = await helper.runFullDiagnostics();
|
||||
console.log(helper.generateReadableReport(report));
|
||||
|
||||
// 手动触发测试任务
|
||||
await helper.triggerTestTask();
|
||||
```
|
||||
|
||||
2. **在开发者页面添加测试按钮**
|
||||
|
||||
```typescript
|
||||
// 在 app/developer.tsx 中
|
||||
import { BackgroundTaskManager } from "@/services/backgroundTaskManagerV2";
|
||||
import { BackgroundTaskDebugHelper } from "@/services/backgroundTaskDebugHelper";
|
||||
|
||||
const handleRunDiagnostics = async () => {
|
||||
const helper = BackgroundTaskDebugHelper.getInstance();
|
||||
const report = await helper.runFullDiagnostics();
|
||||
Alert.alert("诊断报告", helper.generateReadableReport(report));
|
||||
};
|
||||
|
||||
const handleTriggerTask = async () => {
|
||||
try {
|
||||
await BackgroundTaskManager.getInstance().triggerTaskForTesting();
|
||||
Alert.alert("成功", "测试任务已触发");
|
||||
} catch (error) {
|
||||
Alert.alert("错误", error.message);
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
### 方法 3: 自然触发(等待系统调度)
|
||||
|
||||
1. **启动应用并确保后台任务已初始化**
|
||||
|
||||
- 查看启动日志确认初始化成功
|
||||
- 确认有待处理的任务请求
|
||||
|
||||
2. **将应用切换到后台**
|
||||
|
||||
- 按 Home 键或使用手势切换
|
||||
|
||||
3. **等待系统触发**
|
||||
|
||||
- iOS 系统会在合适的时机触发后台任务
|
||||
- 通常在以下情况下:
|
||||
- 设备空闲
|
||||
- 网络连接良好
|
||||
- 电量充足
|
||||
- 距离上次执行已过最小间隔
|
||||
|
||||
4. **查看执行记录**
|
||||
```typescript
|
||||
const manager = BackgroundTaskManager.getInstance();
|
||||
const lastExecution = await manager.getLastBackgroundCheckTime();
|
||||
console.log(
|
||||
"上次执行:",
|
||||
lastExecution ? new Date(lastExecution) : "从未执行"
|
||||
);
|
||||
```
|
||||
|
||||
## 验证后台任务执行
|
||||
|
||||
### 检查点 1: 应用启动日志
|
||||
|
||||
期望看到:
|
||||
|
||||
```
|
||||
[BackgroundTaskManagerV2] ====== 开始初始化后台任务管理器 ======
|
||||
[BackgroundTaskManagerV2] 原生模块可用,开始注册事件监听器
|
||||
[BackgroundTaskManagerV2] 事件监听器注册完成
|
||||
[BackgroundTaskManagerV2] 后台刷新状态: available
|
||||
[BackgroundTaskManagerV2] ✅ 后台任务配置成功
|
||||
[BackgroundTaskManagerV2] 当前待处理的任务请求数量: 1
|
||||
[BackgroundTaskManagerV2] ====== 初始化完成 ======
|
||||
```
|
||||
|
||||
### 检查点 2: 后台任务触发日志
|
||||
|
||||
期望看到:
|
||||
|
||||
```
|
||||
[AppDelegate] ====== 后台任务被触发 ======
|
||||
[AppDelegate] 任务标识符: com.anonymous.digitalpilates.task
|
||||
[BackgroundTaskBridge] ====== 开始处理后台任务 ======
|
||||
[BackgroundTaskBridge] ✅ 有JS监听器,发送执行事件
|
||||
[BackgroundTaskManagerV2] ✅ 收到后台任务执行事件
|
||||
[BackgroundTaskManagerV2] 开始执行后台任务
|
||||
```
|
||||
|
||||
### 检查点 3: 任务执行完成日志
|
||||
|
||||
期望看到:
|
||||
|
||||
```
|
||||
[BackgroundTaskManagerV2] 后台任务执行成功
|
||||
[BackgroundTaskManagerV2] ✅ 后台任务调度成功
|
||||
```
|
||||
|
||||
## 常见问题排查
|
||||
|
||||
### 问题 1: 任务从不执行
|
||||
|
||||
**可能原因:**
|
||||
|
||||
- 后台刷新权限未启用
|
||||
- 应用在 Info.plist 中的配置不正确
|
||||
- 任务标识符不匹配
|
||||
|
||||
**解决方案:**
|
||||
|
||||
1. 检查系统设置中的后台刷新权限
|
||||
2. 验证 Info.plist 配置:
|
||||
```xml
|
||||
<key>BGTaskSchedulerPermittedIdentifiers</key>
|
||||
<array>
|
||||
<string>com.anonymous.digitalpilates.task</string>
|
||||
</array>
|
||||
<key>UIBackgroundModes</key>
|
||||
<array>
|
||||
<string>fetch</string>
|
||||
<string>processing</string>
|
||||
</array>
|
||||
```
|
||||
3. 运行诊断工具检查配置
|
||||
|
||||
### 问题 2: 模拟器上不工作
|
||||
|
||||
**原因:**
|
||||
iOS 模拟器不完全支持 BGTaskScheduler
|
||||
|
||||
**解决方案:**
|
||||
必须在真机上测试
|
||||
|
||||
### 问题 3: 执行频率低于预期
|
||||
|
||||
**原因:**
|
||||
iOS 系统根据多个因素决定后台任务执行时机:
|
||||
|
||||
- 设备使用模式
|
||||
- 电量状态
|
||||
- 网络状况
|
||||
- 应用使用频率
|
||||
|
||||
**解决方案:**
|
||||
|
||||
- 使用 Xcode 模拟触发进行测试
|
||||
- 在生产环境中接受系统的调度策略
|
||||
- 不要期望后台任务精确按时执行
|
||||
|
||||
### 问题 4: 任务执行时间过短
|
||||
|
||||
**原因:**
|
||||
iOS 通常只给后台任务 30 秒执行时间
|
||||
|
||||
**解决方案:**
|
||||
|
||||
- 优化后台任务逻辑,确保快速完成
|
||||
- 使用异步操作和超时机制
|
||||
- 在任务过期前完成关键操作
|
||||
|
||||
## 生产环境监控
|
||||
|
||||
### 添加远程日志记录
|
||||
|
||||
```typescript
|
||||
import { BackgroundTaskManager } from "@/services/backgroundTaskManagerV2";
|
||||
import AsyncStorage from "@/utils/kvStore";
|
||||
|
||||
// 记录后台任务执行历史
|
||||
async function logBackgroundExecution(success: boolean, duration: number) {
|
||||
const history = JSON.parse(
|
||||
(await AsyncStorage.getItem("@bg_task_history")) || "[]"
|
||||
);
|
||||
history.push({
|
||||
timestamp: Date.now(),
|
||||
success,
|
||||
duration,
|
||||
});
|
||||
|
||||
// 只保留最近 50 条记录
|
||||
if (history.length > 50) {
|
||||
history.shift();
|
||||
}
|
||||
|
||||
await AsyncStorage.setItem("@bg_task_history", JSON.stringify(history));
|
||||
}
|
||||
```
|
||||
|
||||
### 添加性能监控
|
||||
|
||||
```typescript
|
||||
// 在 backgroundTaskManagerV2.ts 中
|
||||
private async handleBackgroundExecution(): Promise<void> {
|
||||
const startTime = Date.now();
|
||||
|
||||
try {
|
||||
await executeBackgroundTasks();
|
||||
const duration = Date.now() - startTime;
|
||||
logger.info(`后台任务执行成功,耗时: ${duration}ms`);
|
||||
|
||||
// 记录到本地存储或远程服务
|
||||
await logBackgroundExecution(true, duration);
|
||||
} catch (error) {
|
||||
const duration = Date.now() - startTime;
|
||||
logger.error(`后台任务执行失败,耗时: ${duration}ms`, error);
|
||||
await logBackgroundExecution(false, duration);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 最佳实践
|
||||
|
||||
1. **快速执行**
|
||||
|
||||
- 后台任务应在 30 秒内完成
|
||||
- 优先处理关键逻辑
|
||||
- 使用异步操作避免阻塞
|
||||
|
||||
2. **错误处理**
|
||||
|
||||
- 捕获所有可能的错误
|
||||
- 确保任务始终标记为完成
|
||||
- 在错误情况下也要重新调度
|
||||
|
||||
3. **电池友好**
|
||||
|
||||
- 避免密集计算
|
||||
- 限制网络请求数量
|
||||
- 使用批处理减少唤醒次数
|
||||
|
||||
4. **用户体验**
|
||||
|
||||
- 不要过度依赖后台任务
|
||||
- 在应用前台时优先更新数据
|
||||
- 提供手动刷新选项
|
||||
|
||||
5. **测试覆盖**
|
||||
- 在真机上充分测试
|
||||
- 模拟各种系统状态(低电量、无网络等)
|
||||
- 验证长时间运行的稳定性
|
||||
|
||||
## 参考资源
|
||||
|
||||
- [Apple BGTaskScheduler 文档](https://developer.apple.com/documentation/backgroundtasks/bgtaskscheduler)
|
||||
- [WWDC 2019: Advances in App Background Execution](https://developer.apple.com/videos/play/wwdc2019/707/)
|
||||
- [iOS 后台执行最佳实践](https://developer.apple.com/documentation/backgroundtasks/starting_and_terminating_tasks_during_development)
|
||||
Reference in New Issue
Block a user