SwiftUI 上的BackgroundTasks 和 BGTaskScheduler 未触发

问题描述 投票:0回答:1

我正在尝试设置一些

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:)
  • 使用标识符安排任务请求,提前 60 秒,提交给调度程序(
    schedule()
    仅在应用程序进入后台时被调用,而不是当
    handleSchedule(task:)
    应该触发时永远不会被调用)
  • 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)
    }
}

控制台日志:显示函数调用的打印语句

  • 第 1 行:应用程序启动
  • 第 2 行:
    BGTaskScheduler
    使用标识符“注册”(据说)任务
  • 第 3 行:待处理任务数组
  • 第 4 行:应用程序进入后台(并且
    schedule()
    被调用)
  • 第 5 行:待处理任务数组
LAUNCHED
true
Pending Tasks Requests []
Entered Background
Pending Tasks Requests [<BGAppRefreshTaskRequest: INDENTIFIER, earliestBeginDate: 2022-02-28 02:57:50 +0000>]
ios swift swiftui background-task
1个回答
0
投票

我会首先通过强制后台任务在设备上运行来调试它,以便您知道它是否成功:

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

但是,我的预感是,当您离开范围时,您的操作队列只是被释放,因为它没有连接到任何东西。可能您需要

waitUntilAllOperationsAreFinished()
以确保此代码不会通过队列操作退出作用域。

© www.soinside.com 2019 - 2024. All rights reserved.