# 分析方案

## 变更内容总结
1. **iOS后台任务系统重构** - 修复后台任务无法自动运行的问题
2. **日志系统优化** - 改进日志记录机制,添加队列和批量写入
3. **文档新增** - 添加后台任务修复总结和测试指南文档
4. **应用启动优化** - 添加后台任务状态检查和恢复逻辑
5. **版本号更新** - Info.plist版本从1.0.23升级到1.0.24

## 提交信息类型判断
- **主要类型**: `fix` - 这是一个重要的bug修复,解决了iOS后台任务无法自动运行的核心问题
- **作用域**: `ios-background` - 专注于iOS后台任务功能
- **影响**: 这个修复对iOS用户的后台功能至关重要

## 提交信息

fix(ios-background): 修复iOS后台任务无法自动运行的问题

主要修复内容:
- 修复BackgroundTaskBridge任务调度逻辑,改用BGAppRefreshTaskRequest
- 添加任务完成后自动重新调度机制,确保任务持续执行
- 优化应用生命周期管理,移除重复的后台任务调度
- 在应用启动时添加后台任务状态检查和恢复功能
- 将默认任务间隔从30分钟优化为15分钟

次要改进:
- 重构日志系统,添加内存队列和批量写入机制,提升性能
- 添加写入锁和重试机制,防止日志数据丢失
- 新增详细的修复总结文档和测试指南

技术细节:
- 使用BGAppRefreshTaskRequest替代BGProcessingTaskRequest
- 实现任务过期自动重新调度
- 添加任务执行状态监控和恢复逻辑
- 优化错误处理和日志输出

影响范围: iOS后台任务调度、通知推送、应用状态管理
This commit is contained in:
richarjiang
2025-11-04 19:14:53 +08:00
parent f80a1bae78
commit d74046498d
8 changed files with 1014 additions and 102 deletions

View File

@@ -26,7 +26,6 @@ class BackgroundTaskBridge: RCTEventEmitter {
private var requiresNetworkConnectivity = false
private var requiresExternalPower = false
private var defaultDelay: TimeInterval = 60 * 30 // 30 minutes
private var isRegistered = false
private var currentTask: BGTask?
override init() {
@@ -116,7 +115,6 @@ class BackgroundTaskBridge: RCTEventEmitter {
}
do {
try self.registerTaskIfNeeded(identifier: identifier)
try self.scheduleTask(after: self.defaultDelay)
resolver([
"identifier": identifier,
@@ -156,7 +154,6 @@ class BackgroundTaskBridge: RCTEventEmitter {
guard let self else { return }
do {
try self.registerTaskIfNeeded(identifier: identifier)
try self.scheduleTask(after: effectiveDelay)
resolver([
"identifier": identifier,
@@ -331,17 +328,6 @@ class BackgroundTaskBridge: RCTEventEmitter {
// MARK: - Private helpers
@available(iOS 13.0, *)
private func registerTaskIfNeeded(identifier: String) throws {
guard !isRegistered else { return }
// AppDelegate
// BGTaskScheduler
// AppDelegate
isRegistered = true
NSLog("[BackgroundTaskBridge] 使用 AppDelegate 中预注册的后台任务: \(identifier)")
}
@available(iOS 13.0, *)
private func scheduleTask(after delay: TimeInterval) throws {
guard let identifier else {
@@ -352,24 +338,22 @@ class BackgroundTaskBridge: RCTEventEmitter {
)
}
let request: BGTaskRequest
//
BGTaskScheduler.shared.cancel(taskRequestWithIdentifier: identifier)
switch kind {
case .processing:
let processing = BGProcessingTaskRequest(identifier: identifier)
processing.requiresNetworkConnectivity = requiresNetworkConnectivity
processing.requiresExternalPower = requiresExternalPower
processing.earliestBeginDate = Date(timeIntervalSinceNow: delay)
request = processing
case .refresh:
let refresh = BGAppRefreshTaskRequest(identifier: identifier)
refresh.earliestBeginDate = Date(timeIntervalSinceNow: delay)
request = refresh
}
// 使 BGAppRefreshTaskRequest BGProcessingTaskRequest
// BGAppRefreshTaskRequest
let request = BGAppRefreshTaskRequest(identifier: identifier)
//
//
request.earliestBeginDate = Date(timeIntervalSinceNow: delay)
do {
try BGTaskScheduler.shared.submit(request)
NSLog("[BackgroundTaskBridge] 后台任务已调度,标识符: \(identifier),延迟: \(delay)")
} catch {
NSLog("[BackgroundTaskBridge] 调度后台任务失败: \(error.localizedDescription)")
throw error
}
}
@@ -380,11 +364,20 @@ class BackgroundTaskBridge: RCTEventEmitter {
guard let self else { return }
self.currentTask = task
NSLog("[BackgroundTaskBridge] 开始处理后台任务: \(task.identifier)")
//
task.expirationHandler = { [weak self] in
guard let self else { return }
NSLog("[BackgroundTaskBridge] 后台任务即将过期")
self.queue.async {
if let currentTask = self.currentTask {
currentTask.setTaskCompleted(success: false)
}
self.currentTask = nil
// 使
self.rescheduleTask()
}
guard self.hasListeners else { return }
@@ -401,11 +394,13 @@ class BackgroundTaskBridge: RCTEventEmitter {
}
guard self.hasListeners else {
task.setTaskCompleted(success: false)
self.currentTask = nil
NSLog("[BackgroundTaskBridge] 没有JS监听器执行默认处理并重新调度")
// 使JS
self.executeDefaultTaskAndReschedule()
return
}
NSLog("[BackgroundTaskBridge] 发送后台任务执行事件到JS")
DispatchQueue.main.async {
self.sendEvent(
withName: "BackgroundTaskBridge.execute",
@@ -417,4 +412,56 @@ class BackgroundTaskBridge: RCTEventEmitter {
}
}
}
@available(iOS 13.0, *)
private func executeDefaultTaskAndReschedule() {
// JS
NSLog("[BackgroundTaskBridge] 执行默认后台任务逻辑")
//
// 1.
// 2.
// 3.
//
if let currentTask = self.currentTask {
currentTask.setTaskCompleted(success: true)
self.currentTask = nil
}
//
self.rescheduleTask()
}
@available(iOS 13.0, *)
private func rescheduleTask() {
guard let identifier = self.identifier else {
NSLog("[BackgroundTaskBridge] 无法重新调度任务:标识符为空")
return
}
//
BGTaskScheduler.shared.cancel(taskRequestWithIdentifier: identifier)
let request = BGAppRefreshTaskRequest(identifier: identifier)
request.earliestBeginDate = Date(timeIntervalSinceNow: self.defaultDelay)
do {
try BGTaskScheduler.shared.submit(request)
NSLog("[BackgroundTaskBridge] 已重新调度后台任务,标识符: \(identifier),延迟: \(self.defaultDelay)")
} catch {
NSLog("[BackgroundTaskBridge] 重新调度后台任务失败: \(error.localizedDescription)")
// 使
let retryDelay = min(self.defaultDelay * 0.5, 5 * 60) // 5
request.earliestBeginDate = Date(timeIntervalSinceNow: retryDelay)
do {
try BGTaskScheduler.shared.submit(request)
NSLog("[BackgroundTaskBridge] 使用重试延迟重新调度后台任务成功: \(retryDelay)")
} catch {
NSLog("[BackgroundTaskBridge] 重试调度后台任务也失败: \(error.localizedDescription)")
}
}
}
}