使用自定义请求在AVPlayer中无法播放视频的问题排查
问题描述
我尝试给AVPlayer的请求添加自定义请求头,使用了自定义scheme:
let asset = AVURLAsset(url: URL(string: "mycustomscheme://tungsten.aaplimg.com/VOD")!, options: nil)
结果请求失败,触发了shouldWaitForLoadingOfRequestedResource代理方法。
在这个代理方法中,我发起了自定义请求并成功从服务器获取到数据,但AVPlayer仍然无法播放视频。我的代理代码如下:
func resourceLoader(_ resourceLoader: AVAssetResourceLoader, shouldWaitForLoadingOfRequestedResource loadingRequest: AVAssetResourceLoadingRequest) -> Bool { resourceLoader.delegateQueue?.async { var request: URLRequest? = loadingRequest.request request?.url = self.url // 添加请求头 request?.setValue(HeadersForWS.DeviceOS, forHTTPHeaderField: HeadersForWS.DeviceType) request?.setValue(Utility.getUserId(), forHTTPHeaderField:HeadersForWS.UserId ) if let aRequest = request { let session = URLSession(configuration: .default, delegate: self, delegateQueue: nil) session.dataTask(with: aRequest as URLRequest) { (data, response, error) in guard let data = data else { try? loadingRequest.finishLoading() return } loadingRequest.dataRequest?.respond(with: data) loadingRequest.finishLoading() }.resume() } } return true }
将获取到的数据保存为sample.mp4文件后可以正常播放,说明数据本身是没问题的,那问题可能出在哪里呢?
可能的问题及解决办法
未向AVPlayer传递响应元信息
AVPlayer不仅需要视频数据,还需要服务器返回的响应头(比如Content-Type、Content-Length这类关键信息)来识别数据类型、规划播放逻辑。你现在只把数据传给了dataRequest,但没将服务器返回的response赋值给loadingRequest.response,导致AVPlayer无法正确解析数据。修改代码,在拿到有效响应和数据后,先设置响应信息:
guard let data = data, let response = response else { if let error = error { loadingRequest.finishLoading(with: error) } else { loadingRequest.finishLoading() } return } loadingRequest.response = response // 新增这一行,传递响应元信息 loadingRequest.dataRequest?.respond(with: data) loadingRequest.finishLoading()URLSession实例重复创建+代理处理不规范
你每次请求都新建URLSession实例,还设置了delegate: self,如果你的类没有正确实现URLSessionDelegate相关方法(比如HTTPS证书验证),可能会出现隐性错误。建议复用一个全局的URLSession实例,同时确保代理回调逻辑完整。数据传递方式不符合流式播放要求
如果视频文件较大,一次性把所有数据传给respond(with: data)可能超出AVPlayer的处理预期。可以尝试分块传递数据,或者确保dataRequest的状态被正确设置。另外要注意先判断loadingRequest.dataRequest是否为nil,避免空对象调用。错误处理不完整
当前代码在data为空时直接调用finishLoading(),但如果请求过程中有error产生,应该调用finishLoading(with: error)告知AVPlayer具体错误原因,这有助于你排查问题:if let error = error { loadingRequest.finishLoading(with: error) return }
内容的提问来源于stack exchange,提问作者Manish Malviya

