如何解决带Token的视频URL无法在AV Player中播放的问题?
带Token的视频URL无法在AV Player流式播放的解决方案
问题概述
带Token参数的视频URL(示例:http://example.com/video.mp4?token=authtoken)可在Chrome正常播放,但在AV Player中无响应,抛出错误:
Error : Error Domain=AVFoundationErrorDomain Code=-11829 "Cannot Open" UserInfo={NSLocalizedFailureReason=This media may be damaged., NSLocalizedDescription=Cannot Open, NSUnderlyingError=0x600000c8e430 {Error Domain=NSOSStatusErrorDomain Code=-12848 "(null)"}}
现有代码片段:
let urlString = "http://example.com/video/X-ABC- The Super Hero (2000).mp4?token=_CTV24K7jFmNnH2TFH4Ehw&a=1708455493".addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) let url = URL(string: urlString!) //url = http://example.com/video/X-ABC-%20The%20Super%20Hero%20(2000).mp4?token=_CTV24K7jFmNnH2TFH4Ehw&a=1708455493 Text(url!.absoluteString) VideoPlayer(url: url!, play: $play, time: $time) .mute(mute) .onBufferChanged { progress in // Network loading buffer progress changed print(progress) } .onPlayToEndTime { // Play to the end time. } .onReplay { // Replay after playing to the end. } .onStateChanged { state in switch state { case .loading: print(url!.absoluteString) print(state) case .playing(let totalDuration): print(state) case .paused(let playProgress, let bufferProgress): print(state) case .error(let error): print(error) } }
解决方案
1. 修正URL编码逻辑
直接对整个URL字符串调用addingPercentEncoding会重复编码已转义的字符(比如原URL中的&会被再次编码),导致URL无效。正确做法是拆分路径和参数分别编码:
// 拆分原始URL为路径和查询参数两部分 let rawPath = "http://example.com/video/X-ABC- The Super Hero (2000).mp4" let rawQuery = "token=_CTV24K7jFmNnH2TFH4Ehw&a=1708455493" // 仅对路径中的特殊字符编码 guard let encodedPath = rawPath.addingPercentEncoding(withAllowedCharacters: .urlPathAllowed), let fullUrlString = "\(encodedPath)?\(rawQuery)".addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed), let url = URL(string: fullUrlString) else { // 编码或URL创建失败的处理逻辑 return }
2. 通过请求头传递Token(适配服务端要求)
部分服务端要求Token放在HTTP请求头而非URL参数中,此时需要自定义AVURLAsset的资源加载逻辑:
// 先创建不带Token的基础URL let baseUrl = URL(string: "http://example.com/video/X-ABC- The Super Hero (2000).mp4")! let asset = AVURLAsset(url: baseUrl) // 设置资源加载代理 asset.resourceLoader.setDelegate(self, queue: DispatchQueue.main) // 实现AVAssetResourceLoaderDelegate协议方法 extension YourViewController: AVAssetResourceLoaderDelegate { func resourceLoader(_ resourceLoader: AVAssetResourceLoader, shouldWaitForLoadingOfRequestedResource loadingRequest: AVAssetResourceLoadingRequest) -> Bool { guard let requestUrl = loadingRequest.request.url else { return false } // 构建带Token请求头的请求 var customRequest = URLRequest(url: requestUrl) customRequest.setValue("_CTV24K7jFmNnH2TFH4Ehw", forHTTPHeaderField: "Authorization") // 根据服务端要求调整头字段 // 发起网络请求 let task = URLSession.shared.dataTask(with: customRequest) { data, response, error in if let data = data, let httpResponse = response as? HTTPURLResponse { // 响应加载请求 loadingRequest.dataRequest?.respond(with: data) loadingRequest.contentInformationRequest?.contentType = httpResponse.mimeType loadingRequest.contentInformationRequest?.contentLength = httpResponse.expectedContentLength loadingRequest.finishLoading() } else { loadingRequest.finishLoading(with: error) } } task.resume() return true } } // 用自定义asset创建PlayerItem并关联到VideoPlayer let playerItem = AVPlayerItem(asset: asset) let player = AVPlayer(playerItem: playerItem) // 后续将player绑定到VideoPlayer组件
3. 检查ATS配置(针对HTTP链接)
如果使用的是HTTP协议,需要在Info.plist中配置允许非HTTPS请求:
<key>NSAppTransportSecurity</key> <dict> <key>NSAllowsArbitraryLoads</key> <true/> </dict>
建议优先切换到HTTPS链接,避免ATS限制。
4. 验证Token有效性
错误码-11829可能是Token过期或无效导致的,检查URL中的时间戳参数a=1708455493是否已过期,重新获取有效Token后测试。
内容的提问来源于stack exchange,提问作者Bimal Desai
相关产品推荐
相关产品推荐

