【问题标题】:iOS Resuming HLS download and deleting partially downloaded fileiOS 恢复 HLS 下载并删除部分下载的文件
【发布时间】:2019-04-18 14:42:31
【问题描述】:

我正在按照Apple Docs 实现 HLS 流式传输

但我面临的问题是当用户终止应用程序时恢复下载。如果下载正在进行中并说它已完成 50% 并且用户终止了应用程序或应用程序由于任何原因被系统终止,并且当应用程序再次处于活动状态时,则调用 didCompleteWithError 的 URL 会话委托

func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
}

这里我没有部分下载的文件路径或恢复任务的能力。

下载完成后通过以下委托调用调用下载文件的唯一位置

func urlSession(_ session: URLSession, assetDownloadTask: AVAssetDownloadTask, didFinishDownloadingTo location: URL) {
}

现在文档说要使用

downloadSession.getAllTasks { tasksArray in }

但不幸的是,它不会恢复下载

所以我的问题是

  1. 如何从该下载状态恢复任务,以使整个下载不会从 0% 重新开始?
  2. 对于不可恢复的任务或我不想恢复的特定场景,如何删除部分下载的文件?我将如何获得下载的路径(我不想搜索整个文档目录)

【问题讨论】:

标签: ios swift http-live-streaming


【解决方案1】:

实际上,您可以使用getAllTasks(completionHandler:)] 来获取上次启动时未完成的待处理任务但不知何故,这些任务将在创建下载会话后立即取消这导致urlSession(_:task:didCompleteWithError:) 是如你所见。

幸运的是,我找到了另一种恢复方式AVAssetDownloadTask

AVAssetDownloadTask 提供在某些情况下恢复先前停止的下载的能力。为此,只需使用 AVURLAsset 实例化一个新的 AVAssetDownloadTask,该文件 NSURL 指向具有所需下载选项的部分下载的包,下载将继续恢复任何以前下载的数据。

这意味着如果你想恢复一个挂起的AVAssetDownloadTask,你必须在下载任务停止时从urlSession(_:assetDownloadTask:didFinishDownloadingTo:)中保存location。之后,根据部分下载的文件创建另一个下载任务。

func urlSession(_ session: URLSession, assetDownloadTask: AVAssetDownloadTask, didFinishDownloadingTo location: URL) {
    destinationURL = location
}

func resumeDownloadTask() {
    let urlAsset = AVURLAsset(url: destinationURL)
    downloadTask = assetDownloadURLSession.makeAssetDownloadTask(asset: urlAsset, assetTitle: "title", assetArtworkData: nil, options: nil)
    downloadTask.resume()
}

urlSession(_:assetDownloadTask:didFinishDownloadingTo:) 将始终在urlSession(_:task:didCompleteWithError:) 之前调用,因此在应用程序终止和重新启动或下载任务被取消的两种情况下,您都可以得到destinationURL

注意不要在urlSession(_:task:didCompleteWithError:)中创建新的下载任务,否则会导致无限循环。

对于第二个问题,只需使用 destinationURL 删除文件即可。

有关更多详细信息,我在以下链接中创建了一个示例存储库。仍然存在一些错误,但它可以在正常情况下运行。尝试开始下载任务,让它运行一段时间并终止应用程序。重新启动并继续任务,您将看到结果。

https://github.com/trungducc/stackoverflow/tree/hls-download-resuming

【讨论】:

  • 我和苹果技术支持有过沟通,他们说 1. 无法恢复 2. 部分下载的文件将被系统删除。但是,文档说我们必须处理它仍在与他们谈判,一旦完成会更新它
  • 1.你试过我的样品吗?有用。 2.即使部分下载的文件会被删除,您也可以将其复制到另一个文件夹以在需要时恢复
  • @GirishNair 哦。那么真的没有办法恢复了吗?
  • @KarenAnne 下载我的示例并尝试。你可以看到它自己工作。
  • @KarenAnne:它没有,trungduc 仅在您在同一会话中暂停和恢复时给出的简历。如果你杀死应用程序并尝试恢复它,它会抛出一个错误
【解决方案2】:

虽然接受的答案效果很好,但这里有一个重要的补充。

从 Xcode 调试时,应用安装目录会在每次重新启动时更改,导致资源目标位置在重新启动后变得无效。

您实际上可以坚持location.relativeString 并在下次启动时重构更新后的 URL,如下所示:

// get it from UserDefaults most likely
let persistedRelativeString = .... 

// this corresponds to the app installation root path
let baseDownloadDirectory = FileManager.default.urls(for: .libraryDirectory, in: .userDomainMask).first!.deletingLastPathComponent()

let updatedLocation = URL(string: persistedRelativeString, relativeTo: baseDownloadDirectory)!

在 iOS 14+ 上,会话似乎会自动恢复下载任务,除非您手动取消它。知道了这种行为,我们可以简单地让它继续,一旦urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) 被调用,你就可以检索到这个任务的有效路径。

要支持多个任务,您可以持久化一个[Int: String],对应于:

  • 键:任务 ID(重新启动后稳定)
  • 值:location.relativeString。

通过这种方式,您可以轻松实现跨重启的下载。

【讨论】:

    猜你喜欢
    • 2011-12-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-04
    • 1970-01-01
    相关资源
    最近更新 更多