Alamofire learning (I) Network foundation

Alamofire (2) URLSession

Alamofire (3) Background download principle

@TOC

  • The previous two blogs, Alamofire (I) Network Basics and Alamofire (II) URLSession, respectively explain some essential network basics and iOS network framework apis required for the implementation of alamofire framework. After this knowledge, we can explore the design idea and underlying implementation of alamofire framework. This blog focuses on the implementation principle of “background download”, an important feature of Alamofire.
  • Let’s review an Easter egg from this blog post by Alamofire:

URLSession Background download

  • In the last blog alamofire(2) URLSession has been roughly explained some URLSession background download process and implementation code. Here again to review the summary, is conducive to a better understanding of the principle of Alamofire framework background download.

URLSession Background process

The steps of URLSession to realize background download are as follows:

  • Steps 1 to 3 above can be combined because the code is relatively simple, specifically: first initialize onebackgroundThe pattern ofconfiguration. Configuration supports three modes. Only the Background mode can be downloaded in the background. The network download session is then initialized using configurationsession, set up the related proxy, and call back the data signal response. Finally, the session is createddownloadTaskTask –resumeSuspend starts (default state: suspend) as follows:
// 1: initializes a background mode configuration
let configuration = URLSessionConfiguration.background(withIdentifier: self.createID())
// 2: Initializes the network download session through configuration
let session = URLSession.init(configuration: configuration, delegate: self, delegateQueue: OperationQueue.main)
// 3: session creates a downloadTask. - Resume Starts
let url = URL(string: "https://dldir1.qq.com/qqfile/QQforMac/QQ_V6.5.5.dmg")!
session.downloadTask(with: url).resume()
Copy the code
  • Next comes step 4, setting up the proxy. Rely on the Apple-wrapped network handling API, initiate a connection, send a request, and callback proxy response. Only two callbacks are required
//MARK: -session proxy
extension ViewController:URLSessionDownloadDelegate{
// Download complete callback
    func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL) {
        // Download complete - Start sandbox migration
        print("Download complete -\(location)")
        let locationPath = location.path
        // Copy to user directory (filename named after timestamp)
        let documnets = NSHomeDirectory() + "/Documents/" + self.lgCurrentDataTurnString() + ".mp4"
        print("Mobile address:\(documnets)")
        // Create file manager
        let fileManager = FileManager.default
        try! fileManager.moveItem(atPath: locationPath, toPath: documnets)
    }
    // Download progress callback
    func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didWriteData bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64) {
        print(" bytesWritten \(bytesWritten)\n totalBytesWritten \(totalBytesWritten)\n totalBytesExpectedToWrite \(totalBytesExpectedToWrite)")
        print("Download progress:\(Double(totalBytesWritten)/Double(totalBytesExpectedToWrite))\n")}}Copy the code
  • Then the need to deal with backgroundSessionCompletionHandler callback in step 5. Define a global variable to hold the completionHandler for the background download
class AppDelegate: UIResponder.UIApplicationDelegate {
    var window: UIWindow?
    // Used to save the completionHandler for the background download
    var backgroundSessionCompletionHandler: (() -> Void)?
    func application(_ application: UIApplication, handleEventsForBackgroundURLSession identifier: String, completionHandler: @escaping (a) -> Void) {
        self.backgroundSessionCompletionHandler = completionHandler
    }
}
Copy the code

Note: we through handleEventsForBackgroundURLSession save corresponding callback, it is very necessary! Tell the system background download back to refresh the screen in time

  • The last step 6: agent in urlSessionDidFinishEvents implementation calls. The code is as follows:
func urlSessionDidFinishEvents(forBackgroundURLSession session: URLSession) {
    print("Background task download back")
    // Because the UI refresh is involved, you need to be sure to do it in the main thread
    // If you do not execute the following code, the page will freeze when you enter the foreground, affecting the user experience and printing a warning message.
    DispatchQueue.main.async {
        guard let appDelegate = UIApplication.shared.delegate as? AppDelegate.let backgroundHandle = appDelegate.backgroundSessionCompletionHandler else { return }
        backgroundHandle()
    }
}
Copy the code

Note: If the callback function in the proxy in step 6 is not executed, the system will print a Warning: Application delegate received call to – application:handleEventsForBackgroundURLSession:completionHandler: but the completion handler was never called. Although this can still achieve background download, it will result in the IOS system always refreshing in the background, resulting in performance waste, page lag, affecting user experience.

  • Complete the above 6 steps to achieve the background download function. savehandleEventsForBackgroundURLSessionmethodscompletionHandlerCallbacks, this is very important. Tell the system background download back to refresh the screen in time.
  • After the cut to the background, URLSessionDownloadDelegate agent method will no longer receive Task related messages. When all the Task is complete, all system will only be called AppDelegate application: handleEventsForBackgroundURLSession: completionHandler: callback.

Alamofire background download

Before explaining Alamofire background downloads, it’s worth familiarizing yourself with a few key classes that Alamofire downloads use.

SessionManager

Reference: Cooci blog: juejin.cn/post/684490…