后台应用刷新关闭时未抛出BGTaskSchedulerErrorCodeUnavailable异常
iOS BGAppRefreshTask 无法捕获后台刷新关闭时的异常问题
问题描述
我们在iOS Swift项目中实现了BGAppRefreshTask,当设备的后台应用刷新功能关闭时,执行try BGTaskScheduler.shared.submit(request)代码并未抛出预期的BGTaskSchedulerErrorCodeUnavailable异常,但该功能在后台应用刷新开启时可正常工作。测试环境为实体设备iPhone 14(iOS 18.1),需要捕获该错误用于日志记录。
示例代码
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { BGTaskScheduler.shared.register(forTaskWithIdentifier: "com.example.bgTaskIdentifier", using: nil) { task in self.handleAppRefresh(task: task as! BGAppRefreshTask) } } func sceneDidEnterBackground(_ scene: UIScene) { scheduleAppRefresh() print("Entered Background") // Prints "Entered Background" } func scheduleAppRefresh() { let request = BGAppRefreshTaskRequest(identifier: "com.example.bgTaskIdentifier") request.earliestBeginDate = Date(timeIntervalSinceNow: 5 * 60) do { try BGTaskScheduler.shared.submit(request) } catch { // This catch block is not executed even when background app refresh is disabled in settings. print("Could not schedule app refresh: \(error)") } }
解决方案
1. 主动检查后台刷新状态
BGTaskScheduler.submit()在单应用关闭后台刷新时不会主动抛出异常,需要手动检查当前应用的后台刷新权限状态:
func scheduleAppRefresh() { // 先检查后台应用刷新是否可用 guard UIApplication.shared.backgroundRefreshStatus == .available else { let error = NSError(domain: BGTaskSchedulerErrorDomain, code: BGTaskSchedulerErrorCode.unavailable.rawValue, userInfo: [NSLocalizedDescriptionKey: "Background app refresh is disabled"]) print("Could not schedule app refresh: \(error)") return } let request = BGAppRefreshTaskRequest(identifier: "com.example.bgTaskIdentifier") request.earliestBeginDate = Date(timeIntervalSinceNow: 5 * 60) do { try BGTaskScheduler.shared.submit(request) } catch { print("Could not schedule app refresh: \(error)") } }
2. 理解系统行为差异
iOS 13+之后,BGTaskScheduler.submit()的错误抛出逻辑有明确区分:
- 仅当系统层面完全禁止所有应用的后台任务调度时,才会抛出
BGTaskSchedulerErrorCodeUnavailable - 单应用关闭后台刷新时,submit操作会返回成功,但系统不会触发后续的任务执行
3. 监听权限变化
如果需要实时感知后台刷新权限的变更,可以注册通知:
func setupBackgroundRefreshObserver() { NotificationCenter.default.addObserver(self, selector: #selector(handleBackgroundRefreshStatusChanged), name: UIApplication.backgroundRefreshStatusDidChangeNotification, object: nil) } @objc func handleBackgroundRefreshStatusChanged() { let status = UIApplication.shared.backgroundRefreshStatus switch status { case .available: print("Background refresh enabled, rescheduling tasks") scheduleAppRefresh() case .denied, .restricted: print("Background refresh disabled, canceling scheduled tasks") BGTaskScheduler.shared.cancelAllTaskRequests() @unknown default: break } }
验证注意事项
- 必须在实体设备上测试,模拟器的后台刷新行为可能与真机不一致
- 测试时需确保应用已退出前台,后台刷新状态变更后需重新进入后台触发调度逻辑
内容的提问来源于stack exchange,提问作者Navin Samuel
相关产品推荐
相关产品推荐

