AVPlayer播放远程MP3时网络断开/URL无效未触发错误通知如何解决
AVPlayer播放远程MP3文件错误捕获方案
你之前订阅的两个通知触发场景和资源类型不匹配:AVPlayerItemFailedToPlayToEndTime仅在已经正常播放、中途加载失败无法续播时才会触发;AVPlayerItemNewErrorLogEntry是HLS流媒体(即m3u8格式)专属的错误日志通知,普通MP3这类渐进式下载资源不会触发该通知。且未触发播放动作时,AVPlayer本身的status默认会停留在readyToPlay,不会主动上报资源加载错误。
你可以通过以下组合方案完成错误捕获:
- 主动预校验资源可用性:创建AVPlayerItem后不要直接初始化播放器,先调用
loadValuesAsynchronously主动加载资源核心属性,无效URL、无网络等场景都会在这个异步回调中返回错误
let playerItem = AVPlayerItem(url: audioUrl) playerItem.loadValuesAsynchronously(forKeys: ["duration", "playable"]) { [weak self] in DispatchQueue.main.async { var loadError: NSError? let loadStatus = playerItem.statusOfValue(forKey: "duration", error: &loadError) switch loadStatus { case .failed: // 资源加载失败,直接处理错误逻辑 print("MP3资源不可用:\(loadError?.localizedDescription ?? "未知错误")") case .loaded: // 资源正常,再初始化播放器、注册监听 self?.player = AVPlayer(playerItem: playerItem) self?.addAllObservers() default: break } } }
- 用KVO监听
AVPlayerItem的status属性:不要仅监听AVPlayer本身的status,播放项的status才会直接返回资源相关的加载错误 - 监听
AVPlayer的timeControlStatus:如果状态为waitingToPlayAtSpecifiedRate,同时reasonForWaitingToPlay为toMinimizeStalls,结合网络状态即可判定为网络加载卡顿错误 - 补充订阅
AVPlayerItemPlaybackStalled通知:处理MP3播放中途网络断开、缓存耗尽导致的卡顿场景
完整的监听注册示例代码:
// 存储KVO监听令牌,销毁时需要主动释放 private var kvoTokens = [NSKeyValueObservation]() func addAllObservers() { guard let player = player, let currentItem = player.currentItem else { return } // 监听播放项状态 kvoTokens.append(currentItem.observe(\.status, options: [.new]) { item, _ in if item.status == .failed { print("播放错误:\(item.error?.localizedDescription ?? "未知错误")") // 执行错误处理逻辑 } }) // 监听播放器等待状态 kvoTokens.append(player.observe(\.timeControlStatus, options: [.new]) { player, _ in if player.timeControlStatus == .waitingToPlayAtSpecifiedRate, player.reasonForWaitingToPlay == .toMinimizeStalls { // 这里配合自己实现的网络状态检测逻辑,无网络时直接判定为加载失败 if !NetworkMonitor.shared.isConnected { print("网络断开,播放加载失败") } } }) // 订阅播放卡顿通知 NotificationCenter.default.addObserver( self, selector: #selector(handlePlaybackStalled), name: .AVPlayerItemPlaybackStalled, object: currentItem ) // 保留原有的播放结束失败通知,处理中途播放异常场景 NotificationCenter.default.addObserver( self, selector: #selector(playerDidFail), name: .AVPlayerItemFailedToPlayToEndTime, object: currentItem ) }
注意:对象销毁前需要手动移除所有KVO监听和通知订阅,避免野指针崩溃。
内容的提问来源于stack exchange,提问作者Wojciech Kulik
相关产品推荐
相关产品推荐

