I use URLSession configured as background session to download some files. When download finishes I use:
func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL)
to move downloaded file. Everything works fine, except that when app is in the background this function is not being called. It's called right after app is restored to foreground, but I would like the system to wake my app after file is downloaded. Is there some way to do this?
There is indeed :)
You probably need to change a few things in your setup.
First the URLSessionConfiguration
you use should be of type background
like so:
URLSessionConfiguration.background(withIdentifier: "your.unique.id.here")
Then, in your AppDelegate
you need to implement this method:
func application(_ application: UIApplication, handleEventsForBackgroundURLSession identifier: String, completionHandler: @escaping () -> Void)
Where you do something like store the completionHandler
so it can be used later on.
And finally, where you normally do your "done downloading" magic... typically here:
func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL)
You need to check for the presence of a completionHandler
and if present, invoke that.
Example
The last two bits of the above may seem a bit...huh?? so here is an example.
In your AppDelegate
you can define an optional for the completionHandler
so you can store it for later on:
var backgroundSessionCompletionHandler: (() -> Void)?
and the method then looks like this:
func application(_ application: UIApplication, handleEventsForBackgroundURLSession identifier: String, completionHandler: @escaping () -> Void) {
if identifier == "your.unique.id.here" {
backgroundSessionCompletionHandler = completionHandler
}
}
And then you "just" need to call that once you are done processing the downloaded file, which you can do like this:
if let appDelegate = UIApplication.shared.delegate as? AppDelegate,
let completionHandler = appDelegate.backgroundSessionCompletionHandler {
appDelegate.backgroundSessionCompletionHandler = nil
OperationQueue.main.addOperation {
completionHandler()
}
}
Also, take a look at this tutorial for instance.
Hope that helps you.