Posts

Post not yet marked as solved
5 Replies
1.4k Views
Hello everyone! I need to run a function every X time, and after searching all over the web, I realized that the best way for that is using the Background Tasks framework. Problem is, although I manage to successfully register and submit a Task, it never happens. About the code, I register the tasks when the app is launched: @main struct PersonalEnciclopediaApp: App {      init() {    NotificationManager.shared.requestAuthorization()    BackgroundTaskManager.shared.register()   }      var body: some Scene {     WindowGroup {       BackgroundTasks()     }   } } The above code requests notification authorization (which is working fine), and fires the register function: func register() {    BGTaskScheduler.shared.register(forTaskWithIdentifier: identifier, using: .main) { task in      self.handleTask(task)    }    scheduleAppRefresh()   } The code above registers my task, schedules a new Task with the method scheduleAppRefresh() and, for what I understood, tells the system that the functions that needs to be called when the task starts is handleTask(), which is: func handleTask(_ task: BGTask) {    scheduleAppRefresh()    show(message: "handleTask: \(task.identifier)")    let request = performRequest { error in      task.setTaskCompleted(success: error == nil)    }    task.expirationHandler = {      task.setTaskCompleted(success: false)      request.cancel()    }   } Again, for what I understood, the handleTask method calls the method performRequest, which is: func performRequest(completion: @escaping (Error?) -> Void) -> URLSessionTask {    show(message: "starting performRequest")    let url = URL(string: "https://httpbin.org/get")!    let task = URLSession.shared.dataTask(with: url) { _, _, error in      print("finished request")      completion(error)    }    task.resume()    return task   } And just so that this post is complete, the show method's responsability is just showing a notification: func show(message: String) {    let content = UNMutableNotificationContent()    content.title = "AppRefresh task"    content.body = message    let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 60, repeats: false)    let request = UNNotificationRequest(identifier: UUID().uuidString, content: content, trigger: trigger)    UNUserNotificationCenter.current().add(request) { error in      if let error {        print("error \(error.localizedDescription)")      }    }   } Here is the complete class (just in case its needed): import Foundation import BackgroundTasks import UserNotifications extension BackgroundTaskManager {      static let shared = BackgroundTaskManager()   private init() { }      let identifier = "com.hsilvgar.notifications"      func register() {    BGTaskScheduler.shared.register(forTaskWithIdentifier: identifier, using: .main, launchHandler: handleTask(_:))    scheduleAppRefresh()   }      func handleTask(_ task: BGTask) {    scheduleAppRefresh()    show(message: "handleTask: \(task.identifier)")    let request = performRequest { error in      task.setTaskCompleted(success: error == nil)    }    task.expirationHandler = {      task.setTaskCompleted(success: false)      request.cancel()    }   }      func scheduleAppRefresh() {    let request = BGAppRefreshTaskRequest(identifier: self.identifier)    var message = "Scheduled"    do {      try BGTaskScheduler.shared.submit(request)    } catch BGTaskScheduler.Error.notPermitted {      message = "BGTaskScheduler.shared.submit notPermitted"    } catch BGTaskScheduler.Error.tooManyPendingTaskRequests {      message = "BGTaskScheduler.shared.submit tooManyPendingTaskRequests"    } catch BGTaskScheduler.Error.unavailable {      message = "BGTaskScheduler.shared.submit unavailable"    } catch {      message = "BGTaskScheduler.shared.submit \(error.localizedDescription)"    }    show(message: "scheduleAppRefresh: \(message)")   }      func show(message: String) {    let content = UNMutableNotificationContent()    content.title = "AppRefresh task"    content.body = message    let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 60, repeats: false)    let request = UNNotificationRequest(identifier: UUID().uuidString, content: content, trigger: trigger)    UNUserNotificationCenter.current().add(request) { error in      if let error {        print("error \(error.localizedDescription)")      }    }   }      func performRequest(completion: @escaping (Error?) -> Void) -> URLSessionTask {    show(message: "starting performRequest")    let url = URL(string: "https://httpbin.org/get")!    let task = URLSession.shared.dataTask(with: url) { _, _, error in      print("finished request")      completion(error)    }    task.resume()    return task   } } So the problem is, I get the "Scheduled" notification, but I never get the notification from within performRequest(), which would tell me the task was processed. PS: 1- I have already registered "Background Modes" with "Background fetch" and "Background processing" on my App's Signing & Capabilities 2- I have already registered the Identifier on Info.plist (in BGTaskSchedulerPermittedIdentifiers) Here is my info.plist (if needed) <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>BGTaskSchedulerPermittedIdentifiers</key> <array> <string>com.hsilvgar.notifications</string> </array>    <key>UIApplicationExitsOnSuspend</key> <false/>    <key>UIBackgroundModes</key> <array> <string>fetch</string> <string>processing</string> </array> </dict> </plist> Does anyone know what am I missing, or what is wrong?
Posted Last updated
.