如何在未流播放特定实例时下载FairPlay加密的AVURLAsset
How to Download FairPlay-Encrypted AVURLAsset Without Pre-Playing the Asset?
我之前也碰到过一模一样的-11863错误,真的让人头大——明明逻辑和HLSCatalog示例完全对齐,结果就是下载失败。后来才搞清楚核心问题:AVAssetDownloadTask需要提前确认目标asset具备解密能力,但直接用未加载过密钥的asset创建下载任务时,系统不会自动触发资源加载器去获取CKC。
你之前那种"先静音播放再下载"的路子确实是歪的,正确的做法是手动触发asset的解密密钥获取流程,不需要借助AVPlayer。下面是具体的实现步骤:
正确实现流程
- 单独创建用于下载的
AVURLAsset实例,绑定好你的AVAssetResourceLoaderDelegate(和你播放时用的代理逻辑一致,重点是处理SKD scheme的请求、返回持久化的CKC)。 - 调用
loadValuesAsynchronously(forKeys:)方法,强制asset加载playable状态——这个过程会触发资源加载器去处理解密所需的密钥请求:let downloadAsset = AVURLAsset(url: yourPlaylistURL) downloadAsset.resourceLoader.setDelegate(yourResourceLoaderDelegate, queue: DispatchQueue(label: "download.resource.loader")) downloadAsset.loadValuesAsynchronously(forKeys: ["playable"]) { [weak self] in var loadError: NSError? let status = downloadAsset.statusOfValue(forKey: "playable", error: &loadError) switch status { case .loaded: // 此时asset已完成密钥获取,可安全创建下载任务 guard let downloadTask = self?.downloadSession.makeAssetDownloadTask( asset: downloadAsset, assetTitle: "Your Content Title", assetArtworkData: nil, options: nil ) else { return } downloadTask.resume() case .failed: print("Failed to prepare asset for download: \(loadError?.localizedDescription ?? "Unknown error")") default: break } } - 确保你的
AVAssetResourceLoaderDelegate在处理shouldWaitForLoadingOfRequestedResource时,返回的CKC是可持久化的——也就是调用streamingContentKeyRequestData(forApp:contentIdentifier:options:error:)时,要配置正确的选项让密钥能和离线内容绑定存储。
为什么之前的方法会失败?
当你把asset关联到AVPlayer时,播放器会主动触发资源加载流程去获取解密密钥;但AVAssetDownloadTask不会做这件事,它要求传入的asset必须已经处于"可播放"(即已获取有效密钥)的状态。手动加载playable key,本质是强制asset完成解密所需的所有前置资源请求,不需要播放器介入。
额外注意点
- 不要复用同一个
AVURLAsset实例同时做播放和下载,最好为下载单独创建实例,避免状态冲突。 - 确认你的CKC获取逻辑返回的是持久化形式的密钥,否则下载后的离线内容无法正常解密播放。
这样操作下来,就能跳过"先播放再下载"的奇葩流程,直接完成FairPlay加密内容的离线下载了,亲测和HLSCatalog示例的逻辑完全兼容,也能解决你遇到的-11863错误。
内容的提问来源于stack exchange,提问作者Tom Hamming
相关产品推荐
相关产品推荐

