后台下载
就需要按照苹果的规定,使用URLSessionDownloadTask
关于后台下载,其实苹果有提供文档---Downloading Files in the Background
URLSession
首先,如果需要实现后台下载,就必须创建Background Sessions
private lazy var urlSession: URLSession = {
let config = URLSessionConfiguration.background(withIdentifier: "MySession")
config.isDiscretionary = true
config.sessionSendsLaunchEvents = true
return URLSession(configuration: config, delegate: self, delegateQueue: nil)
}()
通过这种方式创建的URLSession,其实是__NSURLBackgroundSession:
- 必须使用background(withIdentifier:)方法创建URLSessionConfiguration,其中这个identifier必须是固定的,而且为了避免跟其他 App 冲突,建议这个identifier跟 App 的Bundle ID相关
- 创建URLSession的时候,必须传入delegate
- 必须在 App 启动的时候创建Background Sessions,即它的生命周期跟 App 几乎一致,为方便使用,最好是作为AppDelegate的属性,或者是全局变量,原因在后面会有详细说明。
URLSessionDownloadTask
只有URLSessionDownloadTask才支持后台下载
let downloadTask = urlSession.downloadTask(with: url)
downloadTask.resume()
断点续传
苹果的官方文档----Pausing and Resuming Downloads
URLSessionDownloadTask 的断点续传依靠的是resumeData
// 取消时保存resumeData
downloadTask.cancel { resumeDataOrNil in
guard let resumeData = resumeDataOrNil else {
// download can't be resumed; remove from UI if necessary
return
}
self.resumeData = resumeData
}
// 或者是在session delegate 的 urlSession(_:task:didCompleteWithError:) 方法里面获取
func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
guard let error = error else {
// Handle success case.
return
}
let userInfo = (error as NSError).userInfo
if let resumeData = userInfo[NSURLSessionDownloadTaskResumeData] as? Data {
self.resumeData = resumeData
}
// Perform any other error handling.
}
// 用resumeData恢复下载
guard let resumeData = resumeData else {
// inform the user the download can't be resumed
return
}
let downloadTask = urlSession.downloadTask(withResumeData: resumeData)
downloadTask.resume()
self.downloadTask = downloadTask
并非所有下载都可以恢复。有关恢复下载必须满足条件,另外,使用后台配置的下载将自动处理恢复,因此仅非后台下载才需要手动恢复。cancel(byProducingResumeData:)
最后 官方推荐。isDiscretionary 设置为ture
一个布尔值,该值确定是否可以由系统决定是否调度后台任务以实现最佳性能。
实际使用过程中发现。最好为false 因为 新机型很有可能无缘无故下载不响应(找了好长时间什么原因。。。。)
部分老机型 App进行前后台切换,会导致urlSession(_:downloadTask:didWriteData:totalBytesWritten:totalBytesExpectedToWrite:)方法不调用 自己找机会弥补