iOS 15/16使用makeAssetDownloadTask下载HLS仅完成部分的问题求助
问题:AVAssetDownloadURLSession下载HLS点播流仅完成部分内容,无法完整下载
在iOS 15和iOS 16系统中,使用AVAssetDownloadURLSession的makeAssetDownloadTask方法同时播放并下载HLS点播流,初始状态正常(下载快、可立即播放),但几秒后下载停止,通过loadedTimeRanges发现仅下载了约15分钟的音频内容。相关示例代码如下:
@objc func createDownloadSession() { // Create new background session configuration. let configuration = URLSessionConfiguration.background(withIdentifier: "TestAppSession") configuration.timeoutIntervalForResource = 60 * 60 * 2 // Create a new AVAssetDownloadURLSession with background configuration, delegate, and queue downloadSession = AVAssetDownloadURLSession(configuration: configuration, assetDownloadDelegate: self, delegateQueue: OperationQueue.main) } @objc func downloadAndCreatePlayerItem(_ url: URL) -> AVPlayerItem? { // Create new AVAssetDownloadTask for the desired asset let asset = AVURLAsset(url: url) // Create the task to download the track. let downloadTask = downloadSession.makeAssetDownloadTask(asset: asset, assetTitle: "Test Title", assetArtworkData: nil, options: nil) // Start task downloadTask!.resume() // Return the URL asset return AVPlayerItem(asset: downloadTask!.urlAsset) }
需解决的问题:如何实现完整HLS流的下载?是否遇到系统限流?前台应用使用后台会话是否有遗漏设置?
解决方案
1. 配置下载选项,强制完整下载
系统默认会优先保障播放,仅预加载播放所需的超前内容(通常10-20分钟)。要触发完整下载,需在创建downloadTask时传入指定选项,告知系统下载全部媒体资产:
let options: [String: Any] = [ // 强制下载所有媒体资产,而非仅预加载播放内容 AVAssetDownloadTaskOptionDownloadAllMediaAssetsKey: true, // 设置足够高的最低码率,确保下载最高质量的完整流(需高于流中所有码率值) AVAssetDownloadTaskOptionMinimumRequiredMediaBitrateKey: NSNumber(value: 1000000) ] let downloadTask = downloadSession.makeAssetDownloadTask(asset: asset, assetTitle: "Test Title", assetArtworkData: nil, options: options)
2. 正确实现URLSessionAVAssetDownloadDelegate回调
必须实现相关代理方法,处理下载进度、完成状态及错误重试,确保下载过程的稳定性:
// 监控下载进度 func urlSession(_ session: URLSession, assetDownloadTask: AVAssetDownloadTask, didLoad timeRange: CMTimeRange, totalTimeRangesLoaded loadedTimeRanges: [NSValue], timeRangeExpectedToLoad: CMTimeRange) { // 可在此处跟踪下载进度,排查是否出现停滞 } // 下载完成处理 func urlSession(_ session: URLSession, assetDownloadTask: AVAssetDownloadTask, didFinishDownloadingTo location: URL) { // 处理本地已下载的媒体文件,比如移动到指定目录 } // 下载错误处理 func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) { if let error = error { let nsError = error as NSError // 网络中断等可恢复错误,主动重试任务 if nsError.code == NSURLErrorNetworkConnectionLost { task.resume() } } }
3. 优化后台会话配置
即使应用处于前台,后台会话的部分配置也会影响下载持续性,需调整:
let configuration = URLSessionConfiguration.background(withIdentifier: "TestAppSession") // 延长请求超时时间 configuration.timeoutIntervalForRequest = 60 // 延长资源超时时间到24小时,避免长时下载被中断 configuration.timeoutIntervalForResource = 60 * 60 * 24 // 启用网络恢复自动重试 configuration.waitsForConnectivity = true
4. 解除播放进度对下载的限制
默认情况下,播放进度会影响下载调度:若播放速度慢于下载速度,系统会暂停下载以节省资源。如需强制完整下载,可采取两种方式:
- 暂时暂停播放器(
player.rate = 0),待下载到一定进度后再恢复播放; - 使用独立的
AVAssetDownloadTask负责下载,同时用另一个AVPlayer直接播放原始HLS URL,让下载任务不受播放进度干扰。
关于系统限流的说明
应用处于前台时,系统对后台下载的资源限制较低,出现15分钟左右的下载停止,并非系统限流导致,而是默认的预加载调度策略——系统仅下载保障当前及近期播放所需的内容,当播放进度未跟上下载进度时,会自动暂停后续下载。
内容的提问来源于stack exchange,提问作者Brian Schrameck
相关产品推荐
相关产品推荐

