iOS AVPlayerViewController如何区分画中画退出的用户操作?
问题:iOS画中画模式下区分「关闭」与「恢复」操作的处理
需求:
- 关闭PIP:销毁播放器控制器并保持关闭状态
- 恢复PIP:重新展示播放器并继续播放
当前遇到的问题:
实现AVPlayerViewControllerDelegate后,用户点击「关闭」或「恢复」按钮时,都会触发以下两个方法:
playerViewControllerWillStopPictureInPicture(_ playerViewController: AVPlayerViewController) playerViewControllerDidStopPictureInPicture(_ playerViewController: AVPlayerViewController)
同时已定义restoreUserInterfaceForPictureInPictureStopWithCompletionHandler方法,但退出PIP时该方法未被调用,相关代码如下:
func restoreUserInterfaceForFullScreenExit(completionHandler: @escaping (Bool) -> Void) { completionHandler(true) } func restoreUserInterfaceForPictureInPictureStop(completionHandler: @escaping (Bool) -> Void) { completionHandler(true) }
解决方案
1. 先确认代理与基础配置
首先必须确保:
AVPlayerViewController的delegate已正确赋值给当前控制器allowsPictureInPicturePlayback属性设为true- 设备系统版本支持画中画(iOS 14+,iPadOS更早支持)
示例初始化代码:
let playerVC = AVPlayerViewController() playerVC.allowsPictureInPicturePlayback = true playerVC.delegate = self // 配置AVPlayer及播放内容...
2. 区分「恢复」与「关闭」的核心逻辑
restoreUserInterfaceForPictureInPictureStopWithCompletionHandler方法仅在用户点击「恢复」按钮时触发,点击「关闭」时不会调用该方法。如果该方法没触发,优先排查:
- 播放器控制器是否通过
present/push方式展示(系统恢复逻辑依赖控制器栈,子控制器方式可能导致失效) Info.plist是否添加了NSPictureInPictureUsageDescription权限说明(iOS 15+强制要求)
3. 完整实现代码
class PlayerContainerVC: UIViewController, AVPlayerViewControllerDelegate { private var playerVC: AVPlayerViewController? private var isRestoringPIP = false // 初始化播放器 func setupPlayer(with url: URL) { let player = AVPlayer(url: url) playerVC = AVPlayerViewController() playerVC?.player = player playerVC?.allowsPictureInPicturePlayback = true playerVC?.delegate = self present(playerVC!, animated: true) } // 恢复PIP时触发:重新展示播放器并继续播放 func restoreUserInterfaceForPictureInPictureStop(withCompletionHandler completionHandler: @escaping (Bool) -> Void) { isRestoringPIP = true // 根据你的展示逻辑调整,这里用present示例 present(playerVC!, animated: true) { [weak self] in self?.playerVC?.player?.play() completionHandler(true) } } // PIP停止后处理:区分关闭/恢复操作 func playerViewControllerDidStopPictureInPicture(_ playerViewController: AVPlayerViewController) { guard !isRestoringPIP else { isRestoringPIP = false return } // 未触发恢复逻辑,判定为点击「关闭」:销毁控制器 playerViewController.player?.pause() playerViewController.dismiss(animated: true) { [weak self] in self?.playerVC = nil } } }
4. 额外排查点
- 若播放内容已结束(
AVPlayerItem状态为completed),系统可能不会触发恢复逻辑,需确保播放处于活跃状态 - 避免在
playerViewControllerWillStopPictureInPicture中执行销毁操作,该方法在两种操作下都会触发
内容的提问来源于stack exchange,提问作者Mando
相关产品推荐
相关产品推荐

