import BackgroundTasks
import CocoaLumberjackSwift
import Foundation
import ThreemaFramework
/// Manages everything related to BGTasks. Always use the shared instance.
///
/// New task need to adapt `ThreemaBackgroundTask` and be added to the `tasks` array below.
final class ThreemaBGTaskManager {
public static let shared = ThreemaBGTaskManager()
// MARK: - Tasks
// Add new tasks here
private let tasks: [ThreemaBackgroundTask] = [
MessagesRetentionBackgroundTask(),
]
// MARK: - Registration
/// Do not override or add other initializers
private init() {
// no-op
}
/// This must be called in `didFinishLaunchingWithOptions` otherwise the app will crash
/// during scheduling of the tasks.
func registerTasks() {
for task in tasks {
BGTaskScheduler.shared.register(
forTaskWithIdentifier: task.identifier,
using: nil,
launchHandler: newBGTask(for: task)
)
}
}
private func newBGTask(for task: ThreemaBackgroundTask) -> (BGTask) -> Void {
{ [weak self] bgTask in
DDLogNotice("\(task.identifier) started")
// Directly schedule the task again, if requested
if task.shouldReschedule {
self?.scheduleBGTask(for: task)
}
let newTask = Task {
do {
try await task.run()
DDLogNotice("\(task.identifier) completed success=\(!Task.isCancelled)")
bgTask.setTaskCompleted(success: !Task.isCancelled)
}
catch {
DDLogNotice("\(task.identifier) failed: \(error)")
bgTask.setTaskCompleted(success: false)
}
}
bgTask.expirationHandler = {
DDLogNotice("\(task.identifier) expired")
newTask.cancel()
}
}
}
// MARK: Scheduling
/// Schedules BGTasks
public func scheduleTasks() {
for task in tasks {
scheduleBGTask(for: task)
}
}
private func scheduleBGTask(for task: ThreemaBackgroundTask) {
guard task.shouldSchedule else {
BGTaskScheduler.shared.cancel(taskRequestWithIdentifier: task.identifier)
DDLogNotice("\(task.identifier) not scheduled")
return
}
let earliestBeginDate = Date.now.addingTimeInterval(task.minimalInterval)
let request = BGProcessingTaskRequest(identifier: task.identifier)
request.earliestBeginDate = earliestBeginDate
do {
// Submitting a task request with the same identifier as an existing request will replace that request. Like
// this we indirectly refresh the earliest execution date of the task.
try BGTaskScheduler.shared.submit(request)
DDLogNotice(
"\(task.identifier) scheduled with earliest date: \(DateFormatter.shortStyleDateTimeSeconds(earliestBeginDate))"
)
}
catch {
DDLogNotice("\(task.identifier) scheduling failed: \(error)")
}
}
}
¤ Dauer der Verarbeitung: 0.6 Sekunden
¤
*© Formatika GbR, Deutschland