Swift中AVPlayer后台模式下play()失效无法实现音频循环的问题
解决方案:AVPlayer 前后台循环播放问题
核心问题分析
后台播放失效的本质是系统音频会话权限未正确配置,加上手动监听通知的方式在后台状态下存在线程或权限触发的不确定性。虽然你能收到播放结束的通知,但play()调用因系统音频策略限制无法生效。
步骤1:配置后台音频权限
首先必须完成两项系统级配置:
Info.plist 添加后台模式
向Info.plist中添加UIBackgroundModes键,包含audio值(对应"Audio, AirPlay, and Picture in Picture"权限)。初始化音频会话
在App启动时配置并激活音频会话,确保系统允许后台播放:import AVFoundation func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { do { try AVAudioSession.sharedInstance().setCategory(.playback, mode: .default) try AVAudioSession.sharedInstance().setActive(true) } catch { print("音频会话配置失败: \(error)") } return true }
步骤2:替换循环实现方式(推荐)
放弃手动监听通知的方式,使用Apple官方推荐的AVPlayerLooper,它专为循环播放设计,后台兼容性更好:
import AVFoundation // 全局或类级变量保存实例,避免被释放 private var queuePlayer: AVQueuePlayer? private var playerLooper: AVPlayerLooper? func setupLoopPlayback(for audioURL: URL) { let playerItem = AVPlayerItem(url: audioURL) queuePlayer = AVQueuePlayer(playerItem: playerItem) // 创建循环器,自动处理播放结束后的循环逻辑 playerLooper = AVPlayerLooper(player: queuePlayer!, templateItem: playerItem) queuePlayer?.play() }
若坚持使用通知方式的修复方案
如果必须保留原有的通知逻辑,需调整两点确保后台生效:
- 仅监听当前播放器的结束通知,避免干扰
- 在主队列执行播放操作,必要时重新激活音频会话
func loopVideo(videoPlayer: AVPlayer, index: Int) { currentSoundIDs[index]["observer"] = NotificationCenter.default.addObserver( forName: .AVPlayerItemDidPlayToEndTime, object: videoPlayer.currentItem, // 指定监听当前播放器的item queue: .main // 强制在主队列执行 ) { [weak videoPlayer] _ in guard let player = videoPlayer else { return } player.seek(to: CMTime.zero) // 后台状态下重新激活音频会话 do { try AVAudioSession.sharedInstance().setActive(true) } catch { print("重新激活音频会话失败: \(error)") } player.play() } }
关键注意事项
- 确保
AVPlayer和相关循环实例(如playerLooper)不会被提前释放,需用全局或类级变量持有 - 后台播放时避免执行过多非音频相关的耗时操作,防止被系统挂起
内容的提问来源于stack exchange,提问作者Minh Tâm Nguyễn
相关产品推荐
相关产品推荐

