It's true that the typical BG update involves a URL session to get web data, but it doesn't have to.
In the App Delegate, you need to set up your app. Here is the code I have in my didFinishLaunchingWithOptions in my app delegate:
(Note that self.logSB is my logging, similar to a Print command.)
				switch UIApplication.shared.backgroundRefreshStatus {
case .available:
self.logSB.debug("backgroundRefreshStatus is AVAILABLE")
case .denied:
self.logSB.debug("backgroundRefreshStatus is DENIED")
case .restricted:
self.logSB.debug("backgroundRefreshStatus is RESTRICTED")
default:
self.logSB.debug("backgroundRefreshStatus is unknown")
}
if #available(iOS 13.0, *) {
self.logSB.verbose("iOS 13 Registering for Background duty")
BGTaskScheduler.shared.register(forTaskWithIdentifier: "com.WH.myApp.myIdentifier", using: nil) { task in
self.handleAppRefresh(task: task as! BGAppRefreshTask)
self.logSB.verbose("iOS 13 Refresh requested")
}
} else {
self.logSB.verbose("iOS < 13 Registering for Background duty")
UIApplication.shared.setMinimumBackgroundFetchInterval(UIApplication.backgroundFetchIntervalMinimum)
// UIApplication.shared.setMinimumBackgroundFetchInterval(200)
}
You can also see that I support the older background session method. That's what my app started with before iOS 13 came along. You could probably drop that.
Up at the AppDelegate class level:
				 var backgroundSessionCompletionHandler: (() -> Void)?
		 var backgroundSynchTask: UIBackgroundTaskIdentifier = .invalid
The pre-iOS 13 fetch:
func application(_ application: UIApplication, performFetchWithCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
let dateFormatter = DateFormatter()
dateFormatter.dateStyle = DateFormatter.Style.medium
dateFormatter.timeStyle = DateFormatter.Style.long
var convertedDate = dateFormatter.string(from: Date())
if #available(iOS 13.0, *) {
self.logSB.info("iOS 13 Ignoring Background Fetch called at \(convertedDate)")
completionHandler(.newData)
} else {
self.logSB.info("Background Fetch called at \(convertedDate)")
let myState = UIApplication.shared.applicationState
switch myState {
case .background :
self.logSB.info("The app state was found to be Background at \(convertedDate)")
case .inactive:
self.logSB.info("The app state was found to be Inactive at \(convertedDate)")
case .active:
self.logSB.info("The app state was found to be Active at \(convertedDate)")
default:
self.logSB.info("The app state was found to be Unknown at \(convertedDate)")
}
Central().fetch {
convertedDate = dateFormatter.string(from: Date())
self.logSB.info("Calling the Fetch completion handler at \(convertedDate)\n\n")
completionHandler(.newData)
}
				}
}
The Central().fetch function is what goes and gets current web data, but it doesn't have to. It could be anything.
And finally:
func applicationDidEnterBackground(_ application: UIApplication) {
	 let dateFormatter = DateFormatter()
dateFormatter.dateStyle = DateFormatter.Style.medium
dateFormatter.timeStyle = DateFormatter.Style.long
let convertedDate = dateFormatter.string(from: Date())
self.logSB.info("The app entered the background at \(convertedDate)")
if #available(iOS 13.0, *) {
scheduleAppRefresh()
}
}
@available(iOS 13.0, *)
func scheduleAppRefresh() {
logSB.info("Scheduling the AppRefresh in iOS 13 !!")
let request = BGAppRefreshTaskRequest(identifier: "com.WH.myApp.myIdentifier")
request.earliestBeginDate = Date(timeIntervalSinceNow: 2 * 60)
do {
try BGTaskScheduler.shared.submit(request)
} catch {
logSB.error("Could not schedule app refresh: \(error)")
}
}
@available(iOS 13.0, *)
func handleAppRefresh(task: BGAppRefreshTask) {
logSB.info("Handling the AppRefresh in iOS 13")
scheduleAppRefresh()
let queue = OperationQueue()
queue.maxConcurrentOperationCount = 1
let appRefreshOperation = Central().fetch2
queue.addOperation(appRefreshOperation)
let lastOperation = queue.operations.last
lastOperation?.completionBlock = {
task.setTaskCompleted(success: !(lastOperation?.isCancelled ?? false))
}
task.expirationHandler = {
queue.cancelAllOperations()
}
	 let dateFormatter = DateFormatter()
dateFormatter.dateStyle = DateFormatter.Style.medium
dateFormatter.timeStyle = DateFormatter.Style.long
let convertedDate = dateFormatter.string(from: Date())
self.logSB.info("Completed the iOS 13 App Refresh at \(convertedDate)")
}