1

I am trying to upload large files from iOS to a server using URLSessionConfiguration.background object and uploadTask function. Things are looking good til now, but I wonder what actually happens behind the scene when the app goes into background state. I looked up the documents but it only roughly says "the session hands the transfers over to the system".

What I've done is just to initialize a singleton UploadManager again in application(_ application: UIApplication, handleEventsForBackgroundURLSession identifier: String, completionHandler: @escaping () -> Void) after the tasks were done while in background. The manager instance creates a new URLSession with the same identifier inside of it.

I thought I am just apparently creating "another" URLSession instance again, but how does it know about the previous tasks and their states to call the appropriate delegate methods? Does it receive the information back from process running by the system?

class UploadManager {
    static let shared = UploadManager()
    
    private var urlSession: URLSession!

    private init() {
        let sessionConfig = URLSessionConfiguration.background(withIdentifier: Bundle.main.bundleIdentifier! + ".upload")
        sessionConfig.networkServiceType = .video
        urlSession = URLSession(configuration: sessionConfig, delegate: self, delegateQueue: nil)
    }
    ...
}

extension UploadManager {
    func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
        // do post-upload process for completed jobs
    }
}

class AppDelegate: ... {
    ...
    func application(_ application: UIApplication, handleEventsForBackgroundURLSession identifier: String, completionHandler: @escaping () -> Void) {
        NSLog(" backgroundURLSession is done \(identifier)")

        // just by instantiating, the appropriate completion delegate is called
        let manager = VideoUploadManager.shared
    }

}
hjh5696
  • 53
  • 1
  • 7
  • Thanks for pointing out! For the case user relaunches the app before the upload is done, the `UploadManager` instance is also created to handle the scenario. – hjh5696 Apr 29 '23 at 22:29
  • However, I don't get the point of the completionHandler passed in `handleEventsForBackgroundURLSession` from the doc. It says `Calling this completion handler lets the system know that your app’s user interface is updated and a new snapshot can be taken.` What do they mean for "a new snapshot" here? For what do I need to let the system know that the tasks are all done? – hjh5696 Apr 29 '23 at 22:30
  • *I’m done; you can suspend me again.* That makes total sense! Thank you. Now I got the point. Actually I was relying on `handleEventsForBackgroundURLSession` for a moment the background uploads are done, is it safe to do it with `urlSessionDidFinishEvents` of the delegate? The doc says the former is called not only when the tasks are done but for other cases too such as it needs a credential or so – hjh5696 Apr 30 '23 at 13:48
  • I’ve moved my unrelated observations to [chat](https://chat.stackoverflow.com/rooms/253401/discussion-between-rob-and-hjh5696). – Rob Apr 30 '23 at 16:30

1 Answers1

1

You asked:

… how does it know about the previous tasks and their states to call the appropriate delegate methods?

It associates the background URLSession tasks with the identifier string. So, assuming the app was not merely suspended, but needed to be relaunched from scratch, when it restarts, you create a background URLSession with the particular identifier and now your delegate methods will be called. This all works because you use the same identifier string both when the tasks were first created as well as when the app is relaunched.

As Downloading Files in the Background: Recreate the Session If the App Was Terminated says:

If the system terminated the app while it was suspended, the system relaunches the app in the background. As part of your launch time setup, recreate the background session … using the same session identifier as before, to allow the system to reassociate the background download task with your session. You do this so your background session is ready to go whether the app was launched by the user or by the system. Once the app relaunches, the series of events is the same as if the app had been suspended and resumed, as discussed earlier in Handle App Suspension.

While that document focuses on background downloads, all of the general observations regarding background sessions are equally applicable to uploads.

Rob
  • 415,655
  • 72
  • 787
  • 1,044
  • Thank you so much Rob! So basically what I thought was tasks are belonging to URLSession, which seems not true. So does it mean that background tasks are basically maintained by the system and URLSession is just connected or detached from them? – hjh5696 Apr 29 '23 at 22:19
  • I don’t want to vouch for the specific implementation details, but functionally, yes. You use your original background `URLSession` to create the upload `URLSessionTask`, the out-of-process daemon manages the request while your app is no longer active, and when your app is later relaunched and you create a new `URLSession` with the same background identifier, its delegates will be called with the progress/results of the `URLSessionTask` instances that you created earlier. (This is part of the reason why you have to use the delegate-based `URLSession` task methods for background sessions.) – Rob Apr 29 '23 at 23:02
  • Thank you for your detailed answer. All your comments and answer helped me a lot! – hjh5696 Apr 30 '23 at 13:52