You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

iOS应用播放网络m3u8视频失败求助(Xcode9.2+Swift4)

解决iOS中播放网络m3u8视频的崩溃问题

看起来你遇到的崩溃大概率和强制解包URL、ATS网络限制或者播放器生命周期管理有关,我来一步步帮你解决这个问题:

首先,排查核心问题

你的原有代码有几个风险点:

  1. 直接用videoURL!强制解包,如果URL字符串无效(比如拼写错误、协议缺失),会直接触发崩溃;
  2. iOS 9及以后默认启用ATS(App Transport Security),会阻止HTTP协议的网络请求,而你用的是HTTP链接,这会导致视频无法加载甚至引发崩溃;
  3. 没有持有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.

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 03:47:26