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

使用AVPlayerViewController后台播放后返回应用视频自动关闭如何解决

问题根因

该问题核心由两个原因导致:

  1. 未实现AVPlayerViewControllerDelegate的全屏控制回调,系统默认会在用户点击退出全屏按钮时自动dismiss当前弹出的播放器实例
  2. 每次点击播放都新建播放器实例,且没有做播放进度持久化,实例销毁后进度自然丢失,同时你原来的音频会话使用了自定义初始化的实例而非系统单例,本身配置也不生效

修复方案

步骤1:改造自定义VideoPlayer类,实现代理和状态保存

import AVKit
import AVFoundation

class VideoPlayer: AVPlayerViewController, AVPlayerViewControllerDelegate {
    // 对外暴露保存的播放进度,外部持有实例时可直接复用
    var lastPlayTime: CMTime = .zero
    
    init(url: URL) {
        super.init(nibName: nil, bundle: nil)
        // 设置代理接管全屏控制逻辑
        delegate = self
        player = AVPlayer(url: url)
        // 必须使用音频会话单例配置,自定义初始化的实例无效
        let audio = AVAudioSession.sharedInstance()
        do {
            try audio.setCategory(.playback, mode: .moviePlayback)
            try audio.setActive(true)
        } catch {
            print("音频会话配置失败: \(error.localizedDescription)")
        }
        // 监听播放进度实时保存
        player?.addPeriodicTimeObserver(forInterval: CMTimeMake(value: 1, timescale: 1), queue: .main) { [weak self] time in
            self?.lastPlayTime = time
        }
        // 禁止下拉手势关闭播放器,可选配置
        isModalInPresentation = true
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    // 接管退出全屏逻辑,禁止系统自动dismiss播放器
    func playerViewController(_ playerViewController: AVPlayerViewController, willEndFullScreenPresentationWithAnimationCoordinator coordinator: UIViewControllerTransitionCoordinator) {
        coordinator.animate(alongsideTransition: nil) { _ in
            // 如果你需要退出全屏时主动关闭播放器才打开下面的注释,否则留空即可
            // self.dismiss(animated: true)
        }
    }
}

步骤2:修改唤起逻辑,全局持有播放器实例复用

不要每次点击播放都新建实例,在当前控制器中声明属性持有播放器,复用已有的实例恢复播放:

// 在当前控制器类中声明属性,持有播放器实例避免被销毁
var videoPlayer: VideoPlayer?

// 修改按钮点击的唤起逻辑
imageViewButton.addAction(UIAction() { [weak self] _ in
    guard let self = self, let movieUrl = post.movie else { return }
    if let existPlayer = self.videoPlayer {
        // 已有实例直接恢复上次播放进度后弹出
        existPlayer.player?.seek(to: existPlayer.lastPlayTime, completionHandler: { _ in
            existPlayer.player?.play()
        })
        self.vc?.present(existPlayer, animated: true)
    } else {
        // 首次播放新建实例并保存
        let newPlayer = VideoPlayer(url: movieUrl)
        self.videoPlayer = newPlayer
        self.vc?.present(newPlayer, animated: true)
    }
}, for: .touchUpInside)

可选优化:后台切回前台自动续播

如果需要应用从后台切回前台时自动恢复播放,可以在VideoPlayer的init方法中添加通知监听:

// 放在init方法中
NotificationCenter.default.addObserver(self, selector: #selector(resumePlayWhenEnterForeground), name: UIApplication.willEnterForegroundNotification, object: nil)

// 实现回调方法
@objc private func resumePlayWhenEnterForeground() {
    player?.play()
}

内容的提问来源于stack exchange,提问作者Trev347

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.29 00:15:03