Here, we are going to discuss how to download large files and save partial data even when the app is terminated and also updating the view when it is in the background.
Get your tech solution built by top industry experts!!!
Download Files Using URLSessionDownloadTask
Creating an object of URLSessionDownloadTask
Create an object of URLSessionDownloadTask which you have to config the identifier using URLSessionConfiguration after make isDiscretionary true so that we will enable downloading with performance in the background state.
private lazy var urlSession: URLSession = { let config = URLSessionConfiguration.background(withIdentifier: "\(Bundle.main.bundleIdentifier ?? "").backgrouns") config.isDiscretionary = true config.sessionSendsLaunchEvents = true return URLSession(configuration: config, delegate: self, delegateQueue: nil) }()
Pursuing that pass URL from which you want to download the using downloadTask method of URL session class
urlSession.downloadTask(with: URL(string: "your url")!)
Then file downloading will start to track the download data likes totalBytesExpectedToWrite, totalBytesWritten from that you can calculate how much data is downloaded with this delegate method
func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didWriteData bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64) { print(totalBytesExpectedToWrite) print(totalBytesWritten) let progress = Float(totalBytesWritten) / Float(totalBytesExpectedToWrite) debugPrint("Progress \("") \(progress)") }
In that case, when your file is downloaded you can save it in the directory of your app.
func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL) { guard let httpResponse = downloadTask.response as? HTTPURLResponse, (200...299).contains(httpResponse.statusCode) else { print ("server error") return } do { let documentsURL = try FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false) let savedURL = documentsURL.appendingPathComponent( "\(randomString(length: 2)).pdf") print(location) print(savedURL) try FileManager.default.moveItem(at: location, to: savedURL) } catch { print ("file error: \(error)") } } func randomString(length: Int) -> String { let letters : NSString = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" let len = UInt32(letters.length) var randomString = "" for _ in 0 ..< length { let rand = arc4random_uniform(len) var nextChar = letters.character(at: Int(rand)) randomString += NSString(characters: &nextChar, length: 1) as String } return randomString }
Imagine the user put your application in background mode then handleEventsForBackground URLSessionDownloadTask method call of the app delegate class
var backgroundCompletionHandler : ( () -> Void )? func app (_ app: UIApplication, handleEventsForBackgroundURLSession identifier: String, completionHandler: @escaping () -> Void) { debugPrint("handleEventsForBackgroundURLSession: \(identifier)") backgroundCompletionHandler = completionHandler }
Once the download is finished in the background state then you have to update the view in the main thread,
func urlSessionDidFinishEvents(forBackgroundURLSession session: URLSession) { DispatchQueue.main.async { guard let appDelegate = UIApplication.shared.delegate as? AppDelegate, let backgroundCompletionHandler = appDelegate.backgroundCompletionHandler else { return } backgroundCompletionHandler() } }
Leave a Reply