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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 04:10:11