diff --git a/ios/OutLive/BackgroundTaskBridge.m b/ios/OutLive/BackgroundTaskBridge.m index 5341530..cb0e11f 100644 --- a/ios/OutLive/BackgroundTaskBridge.m +++ b/ios/OutLive/BackgroundTaskBridge.m @@ -28,4 +28,7 @@ RCT_EXTERN_METHOD(backgroundRefreshStatus:(RCTPromiseResolveBlock)resolver RCT_EXTERN_METHOD(simulateLaunch:(RCTPromiseResolveBlock)resolver rejecter:(RCTPromiseRejectBlock)rejecter) +RCT_EXTERN_METHOD(markJSReady:(RCTPromiseResolveBlock)resolver + rejecter:(RCTPromiseRejectBlock)rejecter) + @end diff --git a/ios/OutLive/BackgroundTaskBridge.swift b/ios/OutLive/BackgroundTaskBridge.swift index eaee58b..906083c 100644 --- a/ios/OutLive/BackgroundTaskBridge.swift +++ b/ios/OutLive/BackgroundTaskBridge.swift @@ -27,6 +27,10 @@ class BackgroundTaskBridge: RCTEventEmitter { private var requiresExternalPower = false private var defaultDelay: TimeInterval = 60 * 30 // 30 minutes private var currentTask: BGTask? + private let pendingTaskWaitTimeout: TimeInterval = 20 + private var waitingForJSListeners = false + private var pendingTaskPayload: [String: Any]? + private var pendingTaskTimeoutWorkItem: DispatchWorkItem? override init() { super.init() @@ -49,6 +53,9 @@ class BackgroundTaskBridge: RCTEventEmitter { override func startObserving() { hasListeners = true + queue.async { [weak self] in + self?.emitPendingTaskIfPossible() + } } override func stopObserving() { @@ -345,6 +352,22 @@ class BackgroundTaskBridge: RCTEventEmitter { #endif } + @objc + func markJSReady( + _ resolver: @escaping RCTPromiseResolveBlock, + rejecter: @escaping RCTPromiseRejectBlock + ) { + queue.async { [weak self] in + guard let self else { return } + + let hadPendingTask = self.waitingForJSListeners && self.pendingTaskPayload != nil + self.emitPendingTaskIfPossible() + resolver([ + "pendingTaskFlushed": hadPendingTask + ]) + } + } + // MARK: - Private helpers @available(iOS 13.0, *) @@ -408,6 +431,11 @@ class BackgroundTaskBridge: RCTEventEmitter { self.currentTask = task NSLog("[BackgroundTaskBridge] 开始处理后台任务: \(task.identifier)") + if self.identifier == nil { + self.identifier = task.identifier + NSLog("[BackgroundTaskBridge] 使用任务标识符初始化 identifier: \(task.identifier)") + } + // 设置任务过期处理器 task.expirationHandler = { [weak self] in guard let self else { return } @@ -435,28 +463,29 @@ class BackgroundTaskBridge: RCTEventEmitter { } } + let payload: [String: Any] = [ + "identifier": self.identifier ?? task.identifier, + "timestamp": Date().timeIntervalSince1970 * 1000 + ] + guard self.hasListeners else { - NSLog("[BackgroundTaskBridge] 没有JS监听器,执行默认处理并重新调度") - // 即使没有JS监听器,也要执行基本的任务处理 - self.executeDefaultTaskAndReschedule() + NSLog("[BackgroundTaskBridge] 暂无 JS 监听器,等待 JS 初始化 (最多 \(Int(self.pendingTaskWaitTimeout)) 秒)") + self.cacheTaskForLater(payload: payload) return } NSLog("[BackgroundTaskBridge] 发送后台任务执行事件到JS") - DispatchQueue.main.async { - self.sendEvent( - withName: "BackgroundTaskBridge.execute", - body: [ - "identifier": self.identifier ?? "", - "timestamp": Date().timeIntervalSince1970 * 1000 - ] - ) - } + self.emitTaskToJS(payload: payload) } } @available(iOS 13.0, *) private func executeDefaultTaskAndReschedule() { + waitingForJSListeners = false + pendingTaskPayload = nil + pendingTaskTimeoutWorkItem?.cancel() + pendingTaskTimeoutWorkItem = nil + // 执行默认的后台任务逻辑(当没有JS监听器时) NSLog("[BackgroundTaskBridge] 执行默认后台任务逻辑") @@ -506,4 +535,48 @@ class BackgroundTaskBridge: RCTEventEmitter { } } } + + private func cacheTaskForLater(payload: [String: Any]) { + waitingForJSListeners = true + pendingTaskPayload = payload + + pendingTaskTimeoutWorkItem?.cancel() + + let timeoutItem = DispatchWorkItem { [weak self] in + guard let self else { return } + guard self.waitingForJSListeners else { return } + + NSLog("[BackgroundTaskBridge] 等待 JS 监听器超时,执行默认处理") + self.waitingForJSListeners = false + self.pendingTaskPayload = nil + self.pendingTaskTimeoutWorkItem = nil + self.executeDefaultTaskAndReschedule() + } + + pendingTaskTimeoutWorkItem = timeoutItem + queue.asyncAfter(deadline: .now() + pendingTaskWaitTimeout, execute: timeoutItem) + } + + private func emitPendingTaskIfPossible() { + guard hasListeners else { return } + guard waitingForJSListeners, let payload = pendingTaskPayload else { return } + + pendingTaskTimeoutWorkItem?.cancel() + pendingTaskTimeoutWorkItem = nil + waitingForJSListeners = false + pendingTaskPayload = nil + + NSLog("[BackgroundTaskBridge] JS 监听器已就绪,发送缓存的后台任务事件") + emitTaskToJS(payload: payload) + } + + private func emitTaskToJS(payload: [String: Any]) { + DispatchQueue.main.async { [weak self] in + guard let self else { return } + self.sendEvent( + withName: "BackgroundTaskBridge.execute", + body: payload + ) + } + } } diff --git a/services/backgroundTaskManagerV2.ts b/services/backgroundTaskManagerV2.ts index 4789b84..062b78a 100644 --- a/services/backgroundTaskManagerV2.ts +++ b/services/backgroundTaskManagerV2.ts @@ -363,6 +363,15 @@ export class BackgroundTaskManagerV2 { this.handleTaskExpiration(); }); + if (typeof NativeBackgroundModule.markJSReady === 'function') { + try { + await NativeBackgroundModule.markJSReady(); + logger.info('[BackgroundTaskManagerV2] 已通知原生层 JS 监听器就绪'); + } catch (readyError) { + logger.warn('[BackgroundTaskManagerV2] 通知原生层 JS 准备状态失败', readyError); + } + } + logger.info('[BackgroundTaskManagerV2] 事件监听器注册完成'); try {