2017-09-17 55 views
-2

我有一個API可以生成簽名的下載鏈接,並在短時間內過期。我想添加恢復下載的功能,但如果資源的URL發生更改,則URLSession API不會提供恢復下載的本機功能。當下載URL更改時恢復下載

我試圖解決這個問題的方法是跟蹤暫停時下載的字節數,存儲下載的數據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的大小似乎總是相同。在哪裏/如何訪問下載的大量數據?

謝謝!

+0

你還沒有顯示任何相關的代碼,所以誰知道你在做什麼,對或錯? – matt

+0

@matt,我添加了最初的請求代碼。只是爲了澄清,我沒有遇到任何問題,例如獲取新的已簽名URL,恢復具有特定範圍的下載或數據blob的連接,所以我沒有包含這些代碼以保持問題的簡潔。如果您還有其他想看的東西,請告訴我。 – neilb

回答

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) 
} 

你實際上並不需要存儲和連接的數據你最初建議的斑點。您可以使用更新後的簽名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