【问题标题】:Resume downloads when download URL changes下载 URL 更改时恢复下载
【发布时间】:2017-09-17 21:51:15
【问题描述】:

我有一个 API 可以生成签名的下载链接,该链接会在短时间内过期。我想添加恢复下载的功能,但如果资产的 URL 发生变化,URLSession API 不提供恢复下载的本机功能。

我解决这个问题的尝试是跟踪暂停时下载的字节,存储下载的数据 blob,获取新的签名下载 url,使用 Range 标头继续下载,然后将所有数据 blob 连接在一起下载完成。

这是用于开始下载的代码:

let session = URLSession(configuration: URLSessionConfiguration.default, delegate: self, delegateQueue: nil)
let task = session.downloadTask(with: signedURL)
self.sessionDownloadRequest = task

我面临的问题是 resume data var 似乎并未实际包含下载的数据。

self.sessionDownloadRequest.cancel(byProducingResumeData: { (data) in 
    print(data.count) //This surprisingly always returns the same count
}

无论我在暂停前让下载继续多长时间,该数据块的大小似乎始终相同。我在哪里/如何访问已下载的数据块?

谢谢!

【问题讨论】:

  • 你没有展示任何相关代码,所以谁知道你在做什么,对还是错?
  • @matt,我添加了初始请求代码。澄清一下,我在获取新的签名 URL、恢复特定范围的下载或数据 blob 的连接时没有遇到问题,因此我没有包含这些代码以保持问题的简洁。如果您还有什么想看的,请告诉我。

标签: ios swift macos


【解决方案1】:

返回的简历数据:

- (void)cancelByProducingResumeData:(void (^)(NSData *resumeData))completionHandler;

实际上是一个plist,包括:

  • NSURLSessionDownloadURL
  • NSURLSessionResumeBytesReceived
  • NSURLSessionResumeCurrentRequest
  • NSURLSessionResumeEntityTag
  • NSURLSessionResumeInfoTempFileName
  • NSURLSessionResumeInfoVersion
  • NSURLSessionResumeOriginalRequest
  • NSURLSessionResumeServerDownloadDate

您可以使用以下代码访问 plist:

if let resumeDictionary = try? PropertyListSerialization.propertyList(from: self, options: PropertyListSerialization.MutabilityOptions.mutableContainersAndLeaves, format: nil), let plist = resumeDictionary as? [String: Any] {
        print(plist)
}

您实际上不需要像最初建议的那样存储和连接数据 blob。您可以使用更新后的签名 URL 替换存储在 plist (NSURLSessionResumeCurrentRequest) 中的当前请求。之后,创建一个新的 resumeData 实例来代替原来的实例。

 guard let bytesReceived = plist["NSURLSessionResumeBytesReceived"] as? Int
        else {
            return nil
 }
 let headers = ["Range":"bytes=\(bytesReceived)"]
 let newReq = try! URLRequest(url: signedURL, method: .get, headers: headers)             
 let archivedData = NSKeyedArchiver.archivedData(withRootObject: newReq)

 if let updatedResumeData = try? PropertyListSerialization.data(fromPropertyList: plist, format: PropertyListSerialization.PropertyListFormat.binary, options: 0) {
            return updatedResumeData
 }   

您可以从那里操作 plist 并实际创建一个新的以将其传递给实例方法:

- (NSURLSessionDownloadTask *)downloadTaskWithResumeData:(NSData *)resumeData;

注意:如果您使用的是 iOS 10 和 macOS10.12.*,则由于 plist 已损坏,存在阻止恢复功能工作的错误。查看这篇文章以获得修复。在访问 plist 上的某些属性之前,您可能需要修复它。 Resume NSUrlSession on iOS10

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-10-19
    • 2022-01-04
    • 2012-09-15
    • 1970-01-01
    • 1970-01-01
    • 2023-03-12
    • 2014-10-14
    • 1970-01-01
    相关资源
    最近更新 更多