Swift开发中如何基于AVPlayer实现本地视频的不间断循环播放
AVPlayer实现本地视频循环播放的落地方案
首先修正现有代码的两个基础问题:
- 原代码中
AVPlayer、AVPlayerLayer都是局部变量,方法执行结束后会被ARC回收,极易出现播放中途中断、异常闪退的问题,需要改为类的强引用成员变量持有。 - 原代码无播放完成后的进度重置逻辑,AVPlayer默认播放到结尾就会停止,不会自动回到开头。
方案一:使用AVPlayerLooper(推荐,iOS 10+ 支持)
这是苹果官方提供的无缝循环播放工具,内部会自动处理播放完成的重置逻辑,没有手动重置带来的卡顿,性能最优。
实现步骤
- 在对应类中添加强引用的成员变量:
private var player: AVPlayer? private var playerLayer: AVPlayerLayer? private var playerLooper: AVPlayerLooper?
- 修改播放函数:
func playVideo() { guard let path = Bundle.main.path(forResource: "intro", ofType: "mp4") else { return } let url = URL(fileURLWithPath: path) let playerItem = AVPlayerItem(url: url) let player = AVPlayer(playerItem: playerItem) self.player = player // 初始化Looper,自动完成循环播放配置 self.playerLooper = AVPlayerLooper(player: player, templateItem: playerItem) // 配置播放图层 let playerLayer = AVPlayerLayer(player: player) playerLayer.frame = self.view.bounds playerLayer.videoGravity = .resizeAspectFill self.playerLayer = playerLayer self.videoLayer.layer.addSublayer(playerLayer) player.play() }
方案二:监听播放完成通知(兼容iOS 10以下版本)
如果需要支持更低的系统版本,可以通过监听系统通知捕获播放完成事件,手动重置播放进度。
实现步骤
- 在对应类中添加强引用的成员变量:
private var player: AVPlayer? private var playerLayer: AVPlayer?
- 修改播放函数并添加回调逻辑:
func playVideo() { guard let path = Bundle.main.path(forResource: "intro", ofType: "mp4") else { return } let url = URL(fileURLWithPath: path) let player = AVPlayer(url: url) self.player = player // 注册播放完成的通知监听 NotificationCenter.default.addObserver( self, selector: #selector(handlePlayToEnd), name: .AVPlayerItemDidPlayToEndTime, object: player.currentItem ) // 配置播放图层 let playerLayer = AVPlayerLayer(player: player) playerLayer.frame = self.view.bounds playerLayer.videoGravity = .resizeAspectFill self.playerLayer = playerLayer self.videoLayer.layer.addSublayer(playerLayer) player.play() } // 播放完成后的回调方法 @objc private func handlePlayToEnd() { // 重置进度到视频开头 player?.seek(to: .zero) // 重新触发播放 player?.play() }
内存优化:页面销毁时需要移除通知监听,避免内存泄漏:
deinit { NotificationCenter.default.removeObserver(self) }
通用优化点
- 多次调用
playVideo()时,先移除已存在的playerLayer,避免多层视频图层叠加显示:
// playVideo方法开头添加判断 if let oldLayer = self.playerLayer { oldLayer.removeFromSuperlayer() }
内容的提问来源于stack exchange,提问作者John
相关产品推荐
相关产品推荐

