Swift 6+iOS18调度后台刷新任务时应用崩溃求助
Swift 6 + iOS 18 下 BGTaskScheduler.getPendingTaskRequests 崩溃解决建议
问题重现
在Swift 6和iOS 18环境中,调用BGTaskScheduler.shared.getPendingTaskRequests时应用崩溃,触发崩溃的核心调用为:
BGTaskScheduler.shared.getPendingTaskRequests
可能原因及解决方案
1. 避免在App初始化阶段调用异步后台任务API
App的init方法是同步执行的,此时App生命周期尚未完全就绪,iOS 18对后台任务的调用时机限制更严格,异步回调可能导致线程或状态异常。
修改方案:
移除init中的scheduleAppRefresh()调用,将任务调度逻辑移到App激活阶段(通过监听ScenePhase):
@main struct YourApp: App { let backgroundAppRefreshTask = "com.example.app.refreshTask" @Environment(\.scenePhase) private var scenePhase init() { registerBackgroundTasks() // 移除这里的scheduleAppRefresh() } var body: some Scene { WindowGroup { ContentView() } .onChange(of: scenePhase) { _, newPhase in if newPhase == .active { scheduleAppRefresh() } } } // 其余方法保持不变... }
2. 确保后台任务权限配置完整
iOS 18要求必须在Info.plist中声明允许的后台任务标识符,否则调用BGTaskScheduler相关API可能崩溃。
添加配置:
在Info.plist中添加以下键值对:
<key>BGTaskSchedulerPermittedIdentifiers</key> <array> <string>com.example.app.refreshTask</string> </array> <key>UIBackgroundModes</key> <array> <string>fetch</string> </array>
3. 修复不安全的强制类型转换
原代码中使用as! BGAppRefreshTask进行强制类型转换,若iOS 18对任务类型的返回逻辑有变更,会直接触发崩溃。
修改方案:
改用可选绑定安全转换:
func registerBackgroundTasks() { BGTaskScheduler.shared.register(forTaskWithIdentifier: backgroundAppRefreshTask, using: nil) { task in guard let refreshTask = task as? BGAppRefreshTask else { task.setTaskCompleted(success: false) return } handleAppRefresh(task: refreshTask) } }
4. 确保在主队列调用BGTaskScheduler API
iOS 18可能要求BGTaskScheduler的相关调用必须在主队列执行,异步回调的线程问题也可能导致崩溃。
修改方案:
将getPendingTaskRequests的调用包裹在主队列中:
func scheduleAppRefresh() { DispatchQueue.main.async { BGTaskScheduler.shared.getPendingTaskRequests { [weak self] taskRequests in guard let self = self else { return } if taskRequests.contains(where: { $0.identifier == self.backgroundAppRefreshTask }) { print("⚠️ Task Pending: '\(self.backgroundAppRefreshTask)' is already pending.") return } let request = BGAppRefreshTaskRequest(identifier: self.backgroundAppRefreshTask) if let nextHour = Calendar.current.nextDate(after: Date(), matching: DateComponents(minute: 0), matchingPolicy: .nextTime) { request.earliestBeginDate = nextHour } do { try BGTaskScheduler.shared.submit(request) print("✅ App refresh task '\(self.backgroundAppRefreshTask)' successfully scheduled.") } catch { print("❌ Failed to schedule app refresh task.") } } } }
崩溃截图

内容的提问来源于stack exchange,提问作者David
相关产品推荐
相关产品推荐

