我的应用程序的登录页面上有一个循环播放的视频。我遵循了Youtube的教程,让它在视环视频控制器上工作
问题是,当应用程序转到后台时,如果我不马上回来,当我回来的时候,视频就会被冻结。
根据苹果文档的说法,这是应该发生的。
我试着使用NotificationCenter的Notification.Name.UIApplicationWillResignActive
,但这不起作用。
,当应用程序从后台返回后,我如何让视频继续播放?
var player: AVPlayer!
var playerLayer: AVPlayerLayer!
override func viewDidLoad() {
super.viewDidLoad()
configurePlayer()
}
@objc fileprivate func configurePlayer(){
let url = Bundle.main.url(forResource: "myVideo", withExtension: ".mov")
player = AVPlayer.init(url: url!)
playerLayer = AVPlayerLayer(player: player!)
playerLayer.videoGravity = AVLayerVideoGravityResizeAspectFill
playerLayer.frame = view.layer.frame
player.actionAtItemEnd = AVPlayerActionAtItemEnd.none
player.play()
view.layer.insertSublayer(playerLayer, at: 0)
NotificationCenter.default.addObserver(self, selector: #selector(playerItemReachedEnd), name: NSNotification.Name.AVPlayerItemDidPlayToEndTime, object: player.currentItem)
NotificationCenter.default.addObserver(self, selector: #selector(playerItemReachedEnd), name: Notification.Name.UIApplicationWillResignActive, object: player.currentItem)
}
@objc fileprivate func playerItemReachedEnd(){
player.seek(to: kCMTimeZero)
}
发布于 2018-01-28 14:18:19
根据苹果文档的说法,当播放视频并将应用程序发送到后台时,播放机会自动暂停:
他们要做的是在应用程序到后台时删除AVPlayerLayer
(设置为零),然后在前景时重新初始化它:
他们说最好的处理方法是在applicationDidEnterBackground
和applicationDidBecomeActive
中
我使用NSNotification侦听背景和前景事件,并设置函数来暂停播放机&将playerLayer设置为零(都用于背景事件),然后重新初始化playerLayer,并为前台事件播放播放机。这些是我使用的.UIApplicationWillEnterForeground
和.UIApplicationDidEnterBackground
通知
我发现,由于某种原因,如果你长时间按“主页”按钮,弹出的屏幕上会显示“我能帮你什么”,如果你再次按“主页”按钮回到你的应用程序,视频就会被冻结,使用上面的2份通知并不能阻止它的发生。我发现防止这种情况的唯一方法是,也使用通知.UIApplicationWillResignActive
和.UIApplicationDidBecomeActive
。如果您不添加这些除了上述通知,那么您的视频将冻结在主页按钮,长按和后退。我发现防止所有冻结方案的最佳方法是使用所有4种通知。
与上面的代码不同的是,我必须将player和playerLayer类变量设置为选项,而不是隐式地展开选项,我还向AVPlayer类添加了一个扩展,以检查它是否在iOS 9或更低版本中运行。在iOS 10和更高版本中,有一个内置方法.timeControlStatus
AVPlayer定时器状态
我上面的代码:
var player: AVPlayer?
var playerLayer: AVPlayerLayer?
在AVPlayer 9或更低版本中向检查AVPlayer的状态添加一个扩展:
import AVFoundation
extension AVPlayer{
var isPlaying: Bool{
return rate != 0 && error == nil
}
}
以下是完整的代码:
var player: AVPlayer?
var playerLayer: AVPlayerLayer? //must be optional because it will get set to nil on background event
override func viewDidLoad() {
super.viewDidLoad()
// background event
NotificationCenter.default.addObserver(self, selector: #selector(setPlayerLayerToNil), name: UIApplication.didEnterBackgroundNotification, object: nil)
// foreground event
NotificationCenter.default.addObserver(self, selector: #selector(reinitializePlayerLayer), name: UIApplication.willEnterForegroundNotification, object: nil)
// add these 2 notifications to prevent freeze on long Home button press and back
NotificationCenter.default.addObserver(self, selector: #selector(setPlayerLayerToNil), name: UIApplication.willResignActiveNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(reinitializePlayerLayer), name: UIApplication.didBecomeActiveNotification, object: nil)
configurePlayer()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
// this is also for the long Home button press
if let player = player{
if #available(iOS 10.0, *) {
if player.timeControlStatus == .paused{
player.play()
}
} else {
if player.isPlaying == false{
player.play()
}
}
}
}
@objc fileprivate func configurePlayer(){
let url = Bundle.main.url(forResource: "myVideo", withExtension: ".mov")
player = AVPlayer.init(url: url!)
playerLayer = AVPlayerLayer(player: player!)
playerLayer?.videoGravity = AVLayerVideoGravityResizeAspectFill
playerLayer?.frame = view.layer.frame
player?.actionAtItemEnd = AVPlayerActionAtItemEnd.none
player?.play()
view.layer.insertSublayer(playerLayer!, at: 0)
NotificationCenter.default.addObserver(self, selector: #selector(playerItemReachedEnd), name: NSNotification.Name.AVPlayerItemDidPlayToEndTime, object: player.currentItem)
}
@objc fileprivate func playerItemReachedEnd(){
// this works like a rewind button. It starts the player over from the beginning
player?.seek(to: kCMTimeZero)
}
// background event
@objc fileprivate func setPlayerLayerToNil(){
// first pause the player before setting the playerLayer to nil. The pause works similar to a stop button
player?.pause()
playerLayer = nil
}
// foreground event
@objc fileprivate func reinitializePlayerLayer(){
if let player = player{
playerLayer = AVPlayerLayer(player: player)
if #available(iOS 10.0, *) {
if player.timeControlStatus == .paused{
player.play()
}
} else {
// if app is running on iOS 9 or lower
if player.isPlaying == false{
player.play()
}
}
}
}
isPlaying
不要忘记将扩展添加到AVPlayer
发布于 2018-08-20 06:53:38
接受的答案对我没有用。我的“欢迎”视频在某些场合随机暂停。
以下是我们所做的:
后台:由于播放器和playerLayer对象不会在应用程序"resignsActive“中被销毁,或者进入”背景“(在调用它们各自的通知时可以通过观察它们的状态来验证),所以我推测将这些对象中的任何一个设置为零,然后在进入背景或前景时重新初始化它们是有点不必要的。
当玩家对象进入前台时,我才再次播放它。
var player: AVPlayer?
var playerLayer: AVPlayerLayer?
在ViewDidLoad中,我配置我的player对象。
override func viewDidLoad() {
configurePlayer()
}
configurePlayer()函数定义如下
private func configurePlayer() {
guard let URL = Bundle.main.url(forResource: "welcome", withExtension: ".mp4") else { return }
player = AVPlayer.init(url: URL)
playerLayer = AVPlayerLayer(player: player)
playerLayer?.videoGravity = AVLayerVideoGravity.resizeAspectFill
playerLayer?.frame = view.layer.frame
player?.actionAtItemEnd = AVPlayerActionAtItemEnd.none
playItem()
setupPlayNotificationItems()
}
下面是帮助函数的实现
private func setupPlayNotificationItems() {
NotificationCenter.default.addObserver(self,
selector: #selector(restartPlayerItem),
name: NSNotification.Name.AVPlayerItemDidPlayToEndTime,
object: player?.currentItem)
NotificationCenter.default.addObserver(self,
selector: #selector(playItem),
name: .UIApplicationWillEnterForeground,
object: nil)
}
@objc private func playItem() {
// If you please, you can also restart the video here
restartPlayerItem()
player?.play()
if let playerlayer = playerLayer {
view.layer.insertSublayer(playerlayer, at: 0)
}
}
@objc func restartPlayerItem() {
player?.seek(to: kCMTimeZero)
}
发布于 2018-01-27 07:29:51
添加观察者
func addPlayerNotifications() {
NotificationCenter.default.addObserver(self, selector: #selector(playerItemDidPlayToEnd), name: .AVPlayerItemDidPlayToEndTime, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(applicationWillEnterForeground), name: .UIApplicationWillEnterForeground, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(applicationDidEnterBackground), name: .UIApplicationDidEnterBackground, object: nil)
}
移除观察者
func removePlayerNotifations() {
NotificationCenter.default.removeObserver(self, name: .AVPlayerItemDidPlayToEndTime, object: nil)
NotificationCenter.default.removeObserver(self, name: .UIApplicationWillEnterForeground, object: nil)
NotificationCenter.default.removeObserver(self, name: .UIApplicationDidEnterBackground, object: nil)
}
方法
// Player end.
@objc func playerItemDidPlayToEnd(_ notification: Notification) {
// Your Code.
player.seek(to: kCMTimeZero)
}
//App enter in forground.
@objc func applicationWillEnterForeground(_ notification: Notification) {
player.play()
}
//App enter in forground.
@objc func applicationDidEnterBackground(_ notification: Notification) {
player.pause()
}
试试这段代码
https://stackoverflow.com/questions/48473144
复制相似问题