我正在尝试设置一些
BackgroundTasks
,以便在应用程序关闭时定期运行一些代码(比如每天一次)。我相信 swift 上的 BackgroundTasks
API 就是为了这个? (如果我弄错了,请告诉我)。我按照Apple文档上的文章here来实现它,并调整它以适应SwiftUI。
问题:后台任务永远不会触发,但处于“待处理”状态(如图所示)
免责声明:我确实添加了
Background Modes
功能并检查了 Background fetch
和 Background processing
,并将标识符添加到 Info.plist
代码:
Main
- 设置应用程序委托,获取场景,设置 UserDefaults 计数器,获取所有待处理任务的按钮,显示 UserDefault 计数器的文本,添加到 UserDefault 计数器的按钮,当应用程序进入后台时调用 schedule()
任务
import SwiftUI
import BackgroundTasks
@main
struct GyfterApp: App {
@UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
@Environment(\.scenePhase) var scene
@AppStorage("test") var test = 1
var body: some Scene {
WindowGroup {
VStack {
Button("Test") {
BGTaskScheduler.shared.getPendingTaskRequests { all in
print("Pending Tasks Requests", all)
}
}
Text("\(test)")
Button("ADD") {
test = test + 1
}
}
.onChange(of: scene) { newValue in
switch newValue {
case .background:
print("Entered Background")
appDelegate.schedule()
default:
break
}
}
}
}
}
Operation
- BackgroundTasks
的操作,它会打印一条消息并向 UserDefaults 计数器加 1
class OP: Operation {
@AppStorage("test") var test = 1
override func main() {
print("OPERATION RAN")
test = test + 1
}
}
AppDelegate
-
handleSchedule(task:)
)schedule()
仅在应用程序进入后台时被调用,而不是当 handleSchedule(task:)
应该触发时永远不会被调用)schedule()
,创建OperationQueue
,创建Operation
,设置expirationHandler
和setTaskCompleted
,添加操作到队列class AppDelegate: NSObject, UIApplicationDelegate {
@AppStorage("test") var test = 1
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
print("LAUNCHED")
let a = BGTaskScheduler.shared.register(forTaskWithIdentifier: "IDENTIFIER", using: nil) { task in
print("REGISTERED")
self.test = self.test + 1
self.handleSchedule(task: task as! BGAppRefreshTask)
}
print(a)
return true
}
func schedule() {
let request = BGAppRefreshTaskRequest(identifier: "IDENTIFIER")
request.earliestBeginDate = Date(timeIntervalSinceNow: 60)
do {
try BGTaskScheduler.shared.submit(request)
} catch {
print("Could not schedule app refresh: \(error)")
}
}
func handleSchedule(task: BGAppRefreshTask) {
print("HANDLING SCHEDULE")
schedule()
let queue = OperationQueue()
queue.maxConcurrentOperationCount = 1
let operation = OP()
task.expirationHandler = {
print("BG Task Expired")
queue.cancelAllOperations()
}
operation.completionBlock = {
print("OPERATION COMPLETED")
task.setTaskCompleted(success: !operation.isCancelled)
}
queue.addOperation(operation)
}
}
控制台日志:显示函数调用的打印语句
BGTaskScheduler
使用标识符“注册”(据说)任务schedule()
被调用)LAUNCHED
true
Pending Tasks Requests []
Entered Background
Pending Tasks Requests [<BGAppRefreshTaskRequest: INDENTIFIER, earliestBeginDate: 2022-02-28 02:57:50 +0000>]
我会首先通过强制后台任务在设备上运行来调试它,以便您知道它是否成功:
e -l objc -- (void)[[BGTaskScheduler sharedScheduler] _simulateLaunchForTaskWithIdentifier:@"IDENTIFIER"]
但是,我的预感是,当您离开范围时,您的操作队列只是被释放,因为它没有连接到任何东西。可能您需要
waitUntilAllOperationsAreFinished()
以确保此代码不会通过队列操作退出作用域。