# 分析方案
## 变更内容总结 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:
@@ -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)")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user