如何在Swift中使用AVAssetResourceLoaderDelegate为AVPlayer的HLS分片URL追加自定义参数?
如何在Swift中使用AVAssetResourceLoaderDelegate为AVPlayer的HLS分片URL追加自定义参数?
看起来你已经找对了核心方向,但AVAssetResourceLoaderDelegate的用法里有几个容易踩的小坑,导致你的代码没达到预期效果。我来帮你梳理下问题点,再给出修正后的完整方案~
原代码的核心问题
- 直接调用
finishLoading()太草率:AVPlayer的资源加载器在收到重定向指令后,需要时间去处理新的URL请求,你直接结束加载会导致它跳过这个过程,拿不到正确的分片数据。 - 未处理相对URL:你的HLS播放列表里的
.ts路径都是相对地址,原代码里的originalURL可能不是完整的绝对URL,直接追加参数会失效。 - 重定向逻辑不完整:设置
redirect后,需要让系统自己去处理新请求,而不是强制结束加载流程。
修正后的完整实现
下面是调整后的代码,我会把关键修改点标出来:
1. 主ViewController部分(保留核心逻辑,新增调试日志)
import AVFoundation import UIKit class ViewController: UIViewController { var player: AVPlayer? var playerLayer: AVPlayerLayer? override func viewDidLoad() { super.viewDidLoad() setupPlayer() } func setupPlayer() { guard let playlistURL = URL(string: "https://your_hls_stream_url.m3u8") else { print("❌ 无效的播放列表URL") return } let asset = AVURLAsset(url: playlistURL) let loaderDelegate = CustomResourceLoaderDelegate(basePlaylistURL: playlistURL) // 单独用一个队列处理资源加载,避免阻塞主线程 asset.resourceLoader.setDelegate(loaderDelegate, queue: DispatchQueue(label: "com.yourapp.resourceLoader.queue")) let playerItem = AVPlayerItem(asset: asset) player = AVPlayer(playerItem: playerItem) // 配置播放器层 playerLayer = AVPlayerLayer(player: player) playerLayer?.frame = view.bounds playerLayer?.videoGravity = .resizeAspect if let layer = playerLayer { view.layer.addSublayer(layer) } player?.play() } }
2. 修正后的ResourceLoaderDelegate
class CustomResourceLoaderDelegate: NSObject, AVAssetResourceLoaderDelegate { // 记录主播放列表的URL,用来拼接分片的相对路径 private let basePlaylistURL: URL init(basePlaylistURL: URL) { self.basePlaylistURL = basePlaylistURL super.init() } func resourceLoader(_ resourceLoader: AVAssetResourceLoader, shouldWaitForLoadingOfRequestedResource loadingRequest: AVAssetResourceLoadingRequest) -> Bool { guard let requestURL = loadingRequest.request.url else { loadingRequest.finishLoading(with: NSError(domain: "com.yourapp.error", code: -1, userInfo: [NSLocalizedDescriptionKey: "无效的请求URL"])) return false } // 只处理.ts分片的请求,非分片请求交给系统默认处理 guard requestURL.pathExtension.lowercased() == "ts" else { return false } // 1. 把相对URL转成绝对URL let absoluteSegmentURL: URL if requestURL.host != nil { absoluteSegmentURL = requestURL } else { // 拼接主播放列表的base URL和相对分片路径 absoluteSegmentURL = basePlaylistURL.appending(path: requestURL.path()) } // 2. 追加自定义参数,保留原有参数(如果有) var urlComponents = URLComponents(url: absoluteSegmentURL, resolvingAgainstBaseURL: false) let customParams = [ URLQueryItem(name: "paramKey1", value: "paramValue1"), URLQueryItem(name: "paramKey2", value: "paramValue2") ] urlComponents?.queryItems = (urlComponents?.queryItems ?? []) + customParams guard let modifiedURL = urlComponents?.url else { loadingRequest.finishLoading(with: NSError(domain: "com.yourapp.error", code: -2, userInfo: [NSLocalizedDescriptionKey: "无法生成修改后的URL"])) return false } print("🔄 分片URL已修改为: \(modifiedURL.absoluteString)") // 3. 设置重定向,让系统自动处理新URL的请求 let redirectedRequest = URLRequest(url: modifiedURL) loadingRequest.redirect = redirectedRequest // 返回true,告诉系统我们已经处理了重定向,它会继续后续流程 return true } }
关键修改点说明
- 新增basePlaylistURL记录:专门用来处理HLS里的相对分片路径,把它转成绝对URL后再追加参数,解决了相对路径无法直接追加参数的问题。
- 重定向逻辑调整:设置
redirect后直接返回true,让AVPlayer的资源加载系统自己去处理新URL的请求,不再强制结束加载流程。 - 完善错误处理:给各种异常情况(比如无效URL、无法生成新URL)添加了错误回调,方便调试定位问题。
- 保留原有参数:如果分片URL本身已经带业务参数,会保留原有参数再追加自定义的,避免覆盖必要的业务逻辑。
调试小技巧
可以用Charles抓包工具查看每个.ts请求的URL,或者在Delegate里打印日志,确认自定义参数是否已经成功追加,这样能快速排查问题。
备注:内容来源于stack exchange,提问作者Sidd Redkar
相关产品推荐
相关产品推荐

