下载URL更改时继续下载

时间:2017-09-17 21:51:16

标签: ios swift macos

我有一个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

我面临的问题是,恢复数据var似乎并未实际包含已下载的数据。

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

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

谢谢!

1 个答案:

答案 0 :(得分:1)

由以下方式返回的简历数据:

$sql = "INSERT INTO $mytable (number, name, description)
             VALUES (" . $_POST['number'] . ","
                       . $_POST['name'] . ","
                       . $_POST['description'] . ")";

实际上是一个包括:

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

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

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

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

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

从那里你可以操纵plist并实际创建一个新的plist,直到实例方法:

 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
 }   

注意:如果您使用的是iOS 10和macOS10.12。*,则会出现一个错误,导致恢复功能无法正常工作,因为plist已损坏。查看本文以获得修复。在访问plist之前,您可能需要修复plist。 Resume NSUrlSession on iOS10