iOS应用播放网络m3u8视频失败求助(Xcode9.2+Swift4)
解决iOS中播放网络m3u8视频的崩溃问题
看起来你遇到的崩溃大概率和强制解包URL、ATS网络限制或者播放器生命周期管理有关,我来一步步帮你解决这个问题:
首先,排查核心问题
你的原有代码有几个风险点:
- 直接用
videoURL!强制解包,如果URL字符串无效(比如拼写错误、协议缺失),会直接触发崩溃; - iOS 9及以后默认启用ATS(App Transport Security),会阻止HTTP协议的网络请求,而你用的是HTTP链接,这会导致视频无法加载甚至引发崩溃;
- 没有持有
AVPlayerViewController的引用,可能在present后被系统提前释放,导致播放异常。
分步解决方案
1. 配置Info.plist允许HTTP请求
因为m3u8链接如果是HTTP协议,iOS默认会拦截请求,需要在Info.plist中添加ATS例外:
打开Info.plist,右键选择"Add Row",添加NSAppTransportSecurity,然后在其下添加NSAllowsArbitraryLoads并设置为YES。如果是正式项目,更推荐只允许特定域名(添加NSExceptionDomains),测试阶段可以先用全局允许:
<key>NSAppTransportSecurity</key> <dict> <key>NSAllowsArbitraryLoads</key> <true/> </dict>
2. 优化代码,避免崩溃并正确播放m3u8
下面是修正后的完整代码,我加入了错误处理、生命周期管理和HLS适配:
import UIKit import AVKit import AVFoundation class ViewControllerPlayer: UIViewController { // 持有播放器控制器,防止被提前释放 private var videoPlayerVC: AVPlayerViewController? override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) // 替换成你的m3u8链接,这里用一个公开的测试链接示例 guard let videoURL = URL(string: "http://devimages.apple.com/iphone/samples/bipbop/bipbopall.m3u8") else { print("⚠️ 无效的视频URL,请检查链接格式") // 可以在这里给用户显示弹窗提示 let alert = UIAlertController(title: "错误", message: "视频链接无效", preferredStyle: .alert) alert.addAction(UIAlertAction(title: "确定", style: .default)) present(alert, animated: true) return } // 针对HLS(m3u8)创建PlayerItem,方便监听加载状态和错误 let playerItem = AVPlayerItem(url: videoURL) let videoPlayer = AVPlayer(playerItem: playerItem) // 监听播放错误,便于排查问题 NotificationCenter.default.addObserver( self, selector: #selector(handlePlaybackError(_:)), name: .AVPlayerItemFailedToPlayToEndTime, object: playerItem ) // 初始化播放器控制器并持有引用 videoPlayerVC = AVPlayerViewController() videoPlayerVC?.player = videoPlayer // 弹出播放器并开始播放 present(videoPlayerVC!, animated: true) { videoPlayer.play() } } // 处理播放错误的回调 @objc private func handlePlaybackError(_ notification: Notification) { guard let errorInfo = notification.userInfo, let error = errorInfo[AVPlayerItemFailedToPlayToEndTimeErrorKey] as? Error else { print("❌ 播放出错,但无法获取详细错误信息") return } print("播放错误详情:\(error.localizedDescription)") // 给用户显示错误提示 let alert = UIAlertController(title: "播放失败", message: error.localizedDescription, preferredStyle: .alert) alert.addAction(UIAlertAction(title: "确定", style: .default)) // 确保在主线程弹窗 DispatchQueue.main.async { self.present(alert, animated: true) } } // 移除通知监听,避免内存泄漏 deinit { NotificationCenter.default.removeObserver(self) } }
3. 额外注意事项
- 如果你的m3u8链接需要请求头(比如鉴权token),可以用
AVURLAsset来配置:let headers = ["Authorization": "Bearer your-auth-token"] let asset = AVURLAsset(url: videoURL, options: ["AVURLAssetHTTPHeaderFieldsKey": headers]) let playerItem = AVPlayerItem(asset: asset) - 确保测试用的m3u8链接是可正常访问的,有些链接可能有地域限制或者已经失效;
- 不要在
viewDidLoad中执行present操作,因为此时视图还未完全加入视图层级,放在viewDidAppear中更可靠。
内容的提问来源于stack exchange,提问作者Alex D.
相关产品推荐
相关产品推荐

