So I created a background service, it seems to get scheduled but not executed.
I added "Background fetch" and "Background processing" to the app and added the required background modes and permitted background task scheduler identifier 
When closing the App the background process is getting scheduled but never executed (it seems like).
When "Simulating background fetch" with Xcode, nothing happens or I get this error:
nw_read_request_report [C2] Receive failed with error "Software caused connection abort"
Here is my AppDelegate.swift :
@main
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
print("reguster")
BGTaskScheduler.shared.register(forTaskWithIdentifier: "id.myRefreshName", using: nil) { (task) in
guard let bgTask = task as? BGProcessingTask else {
return
}
self.handleAppRefreshTask(task: bgTask)
}
return true
}
func handleAppRefreshTask(task: BGProcessingTask) {
let taskCompletionHandler: (Bool) -> Void = { success in
// Call the completion handler provided by the system
task.setTaskCompleted(success: success)
print("Task completed with success: \(success)")
}
task.expirationHandler = {
taskCompletionHandler(false)
print("no success")
}
NetworkManager.getData { result in
switch result {
case .success(let hasInternet):
DispatchQueue.main.async {
if hasInternet {
let time = Utils.getCurrentTime()
UserDefaults.standard.set(time, forKey: "lastUpdate")
} else {
print("No internet connection")
}
}
taskCompletionHandler(true)
case .failure(let error):
print("Data update failed: \(error.localizedDescription)")
taskCompletionHandler(false)
}
}
scheduleBackgroundFetch()
}
func scheduleBackgroundFetch() {
let fetchTask = BGProcessingTaskRequest(identifier: "id.myRefreshName")
fetchTask.earliestBeginDate = Date(timeIntervalSinceNow: 5)
do {
try BGTaskScheduler.shared.submit(fetchTask)
} catch {
print("Unable to submit task: \(error.localizedDescription)")
}
}
// 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.
UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
}
func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set<UISceneSession>) {
// Called when the user discards a scene session.
// If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.
// Use this method to release any resources that were specific to the discarded scenes, as they will not return.
}
func applicationWillTerminate(_ application: UIApplication) {
Statistics.storeEvent("closeApp")
}
func application(_ application: UIApplication, performFetchWithCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
let task = BGProcessingTaskRequest(identifier: "id.myRefreshName")
do {
try BGTaskScheduler.shared.submit(task)
completionHandler(.newData)
} catch {
completionHandler(.failed)
}
}
}
In the NetworkManager.getData function I parse a website, get its data and store it in CoreData.
Background fetch and background processing are two different things. Background fetch is the older mechanism, but confusingly the "Background fetch" capability is used to enable both the older mechanism and the new BGAppRefreshTask mechanism.
The menu you are using in the simulator triggers the older, deprecated background fetch mechanism. It will result in a call to application(_:performFetchWithCompletionHandler:) in your App Delegate, if you have implemented that function.
There is a different process to trigger a BGAppRefreshTask or a BGProcessingTask during development.
Essentially, you need to:
e -l objc -- (void)[[BGTaskScheduler sharedScheduler] _simulateLaunchForTaskWithIdentifier:@"TASK_IDENTIFIER"], substituting the appropriate task identifier. In your case this would be e -l objc -- (void)[[BGTaskScheduler sharedScheduler] _simulateLaunchForTaskWithIdentifier:@"id.myRefreshName"]I note that you are scheduling a BGProcessingTask; This probably isn't what you want. BGProcessingTask is intended for long data updates and app maintenance. This sort of task only executes when the device is idle and is cancelled if the user starts using their device.
You probably want a BGAppRefreshTask, which is intended for smaller updates but doesn't require the device to be idle.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With