I am trying to use the BackgroundTask framework to run a block of code periodically when the user closes the app. Preferably, I would want the code to run once every hour. In the project file below, I have the code change a value stored in UserDefaults, but no matter how long I wait it never runs the code in the task.
AppDelegate.swift
import UIKit
import BackgroundTasks
import OSLog
@main
class AppDelegate: UIResponder, UIApplicationDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
BGTaskScheduler.shared.register(forTaskWithIdentifier: "com.example.refresh", using: nil) { task in
Logger().info("[BGTASK] Preform bg fetch \("com.example.refresh")")
task.setTaskCompleted(success: true)
self.scheduleAppRefresh()
}
BGTaskScheduler.shared.register(forTaskWithIdentifier: "com.example.restock", using: nil) { task in
Logger().info("[BGTASK] Preform bg fetch \("com.example.restock")")
AppUserDefaults.newString = "New String" // <-- The string is changed here
task.setTaskCompleted(success: true)
self.scheduleBackgroundProcessing()
}
return true
}
func scheduleAppRefresh() {
let request = BGAppRefreshTaskRequest(identifier: "com.example.refresh")
request.earliestBeginDate = Date(timeIntervalSinceNow: 60)
do {
try BGTaskScheduler.shared.submit(request)
} catch {
print("Could not schedule app refresh task \(error.localizedDescription)")
}
}
func scheduleBackgroundProcessing() {
let request = BGProcessingTaskRequest(identifier: "com.example.restock")
request.requiresNetworkConnectivity = true
request.requiresExternalPower = false
request.earliestBeginDate = Date(timeIntervalSinceNow: 1 * 60)
do {
try BGTaskScheduler.shared.submit(request)
} catch {
print("Could not schedule image fetch: (error)")
}
}
// MARK: UISceneSession Lifecycle
func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
// Called when a new scene session is being created.
// Use this method to select a configuration to create the new scene with.
return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
}
func applicationDidEnterBackground(_ application: UIApplication) {
Logger().info("App did enter background")
self.scheduleAppRefresh()
self.scheduleBackgroundProcessing()
}
}
When the app loads, I show newString in the ContentView:
ContentView.swift
import SwiftUI
import UserNotifications
struct ContentView: View {
var body: some View {
Text("New String: \(AppUserDefaults.newString)")
}
}