【开发者】iOS下载器中两个令人窒息的诡异Bug及破局思路
本篇文章不会聚焦iOS下载器的具体实现,主要是剖析和解决两个棘手的下载异常。
一是在下载的过程中,把App退到后台待一会再进入前台,大概率会触发下载失败。
二是下载过程中反复退后台进前台再杀死App,重新打开App,大概率会碰到下载失败并且反复重试总是失败。
下载器整体逻辑
我们的下载器底层使用的是Alamofire,并且支持断点续传。
问题一 退后台后下载失败
我们的App并没有申请Background mode,因此推测是跟App退到后台下载线程被挂起有关,而且这个问题在release包尤其明显。
解决方案
申请后台任务时间,防止切后台被挂起导致连接中断。
if backgroundTaskID == .invalid {backgroundTaskID = UIApplication.shared.beginBackgroundTask(withName: "Downloader-\(id)") { [weak self] inself?.endBackgroundTask()}}func endBackgroundTask() {if backgroundTaskID != .invalid {UIApplication.shared.endBackgroundTask(backgroundTaskID)backgroundTaskID = .invalid}}
对于下载失败,拦截-1005(连接断开)错误并尝试静默续传重试。同时设置静默续传的次数,防止无限次重试。
case NSURLErrorNetworkConnectionLost:downloadError = EPODownloadError(code: .networkConnectionLost)// 拦截 -1005 (Connection Lost) 错误并尝试静默续传重试if let resumeData = response.resumeData, current1005RetryCount < max1005RetryCount {self.saveResumeData(resumeData)current1005RetryCount += 1shouldSilentRetry = true} elseif let resumeData = response.resumeData {self.saveResumeData(resumeData)}
问题二 下载重试总是失败
通过分析下载失败的日志,发现下载失败的原因总是“文件校验失败”。
因此怀疑是新的下载任务受到了之前“脏数据”的污染。
解决方案
在下载任务启动前,如果不需要断点续传,则强制清理目标路径下的残留“脏文件”。
if resumeModel == nil {if FileManager.default.fileExists(atPath: fileURL.path) {try? FileManager.default.removeItem(at: fileURL)}}
如果文件校验失败,除了强制清理上次下载的脏数据之外,同时清理下断点续传的文件数据。
clearResumeData()
亲测通过上面的解决方案,这两个问题都得到了比较好的解决。
1
END
1

球分享

球点赞

球在看
夜雨聆风