BGTaskScheduler 的后台获取与调试模拟完美配合,但在实践中从未奏效

Background fetch with BGTaskScheduler works perfectly with debug simulations but never works in practice

我在 appDelegate 的 didFinishLaunchingWithOptions 中注册了后台获取任务:

BGTaskScheduler.shared.register(forTaskWithIdentifier: BackgroundScheduler.shared.backgroundTaskId, using: DispatchQueue.main) { task in

    BackgroundScheduler.shared.handleAppRefresh(task: task as! BGAppRefreshTask)
}

handleAppRefersh 函数安排另一个刷新任务并调用该操作的获取方法,并在完成获取操作后将完成处理程序传递给 运行。

func handleAppRefresh(task: BGAppRefreshTask) {
    
    os_log("handleAppRefresh exetued.")
    
    scheduleAppRefresh()
    
    task.expirationHandler = {
        os_log("backgroundFetch expiration called")
    }
    
    operation.fetch() {
        os_log("backgroundFetch fetch called")
        task.setTaskCompleted(success: true)
    }
}

scheduleAppRefresh 提交 BGAppRefreshTAskRequest 以重复后台获取执行。

func scheduleAppRefresh() {
    
    os_log("scheduleAppRefresh exetued.")
    
    let request = BGAppRefreshTaskRequest(identifier: backgroundFetchId)
    request.earliestBeginDate = Date(timeIntervalSinceNow: AppSettings.refreshInterval)

    do {
        try BGTaskScheduler.shared.submit(request)
    } catch {
        os_log("Could not schedule app refresh:", error.localizedDescription)
    }
}

刷新间隔为 10 * 60,即 10 分钟。

operation.fetch 方法检查设备的当前位置并向远程服务器发送请求。最后它发送本地通知,更新 UI 并调用以下代码:

task.setTaskCompleted(success: true)

在 Xcode 中检查了“位置更新”和“后台获取”功能,并在 info.plist 中添加了必需的设置。

当我使用以下调试命令测试后台获取功能时,一切正常,调试器中没有任何警告消息。

e -l objc -- (void)[[BGTaskScheduler sharedScheduler] _simulateLaunchForTaskWithIdentifier:@"TASK_IDENTIFIER"]

但是当我将应用程序留在后台很长时间时,iOS 永远不会调用 handleAppRefresh 函数。

Xcode: 12.2, iOS: 14.2

项目 public 回购: https://github.com/amirrezaeghtedari/CoronaVirousRegulations.git

我完全糊涂了。

WWDC 2020 后台执行揭秘

据称,有很多因素在起作用,决定了您的应用何时实际运行后台刷新。 OS 的神经引擎了解用户何时启动应用程序,以便可以在之前执行更新。他们在 2019 年 session.

中首次提到了这一点

我将后台获取间隔设置为 10 分钟,在等待大约 4 小时或更长时间后,iOS 运行 我的应用程序在后台运行。之后,我的应用程序在后台不定期地被调用,间隔时间从不到一小时到几个小时不等。很明显,我的实现没有问题,这些执行间隔取决于 iOS 策略。