【问题标题】:Forward and backward is not working when app enter background to foreground during video play in tvOS在 tvOS 中播放视频期间,当应用程序进入后台到前台时,前进和后退不起作用
【发布时间】:2016-06-29 13:17:01
【问题描述】:

我正在使用 swift 开发 tvOS 应用程序。我正在使用 AVPlayerViewController 在 Apple 演示应用程序(UIKit 目录(tvOS):创建和自定义 UIKit 控件)之后播放视频。一切正常,但应用程序在视频播放期间进入后台到前台,然后前进和后退不起作用,如果用户可以进入睡眠模式,则会产生同样的问题。这个问题也在 Apple 演示应用中产生。

我不明白为什么会产生这个问题。请建议我如何解决它。

    import UIKit
    import Foundation
    import AVKit

    class ViewController: UIViewController ,AVPlayerViewControllerDelegate{
        let playerController = AVPlayerViewController()
        var playerObj:AVPlayer!
        var asset:AVAsset!
        var playerItem:AVPlayerItem!
        override func viewDidLoad() {
            super.viewDidLoad()
            // Do any additional setup after loading the view, typically from a nib.
         self.playVideo("http://p.events-delivery.apple.com.edgesuite.net/1509pijnedfvopihbefvpijlkjb/m3u8/hls_vod_mvp.m3u8")
        }
  override func viewWillAppear(animated: Bool) {
         playerController.delegate = self
    }
        //MARK:- Play Video Method.
        func playVideo(videoURL:String) {
            print("video URL========\(videoURL)")

            self.asset = AVAsset(URL: NSURL(string: videoURL)!) as AVAsset
            self.playerItem = AVPlayerItem(asset: self.asset)
            self.playerObj = AVPlayer(playerItem: self.playerItem)
            self.playerController.player = self.playerObj
            playerController.view.frame = CGRectMake(0.0, 0.0, UIScreen.mainScreen().bounds.width, UIScreen.mainScreen().bounds.height)
            playerController.delegate = self
            self.view.addSubview(playerController.view)
            self.playerController.showsPlaybackControls = true
            self.playerItem.addObserver(self, forKeyPath: "status", options: NSKeyValueObservingOptions.New, context: nil)
            self.playerController.player!.play()
            //self.playerController.player!.play()


        }
        override func observeValueForKeyPath(keyPath: String?, ofObject object: AnyObject?, change: [String : AnyObject]?, context: UnsafeMutablePointer<Void>){

            if object as? NSObject == playerItem && (keyPath! as NSString).isEqualToString("status") {

                if (playerItem?.status == AVPlayerItemStatus.ReadyToPlay) {
                      print("Player Ready to play")
                }
                if (playerItem?.status == AVPlayerItemStatus.Failed) || (playerItem?.status == AVPlayerItemStatus.Unknown) {

                        print("Player getting play error")
                }
            }
        }


        override func didReceiveMemoryWarning() {
            super.didReceiveMemoryWarning()
            // Dispose of any resources that can be recreated.
        }


    }

【问题讨论】:

  • 您提供的代码上下文数量不足以真正为您提出可行的解决方案,因为我无法确定完整的上下文。根据我使用 AVPlayer 的经验,我建议将其设为类变量,但似乎您将其设为方法变量。如果是这种情况,那么每当方法终止时,您的函数很可能没有保留 AVPlayer。 Apple 甚至建议您为 AVPlayer 创建一个类变量,以便在应用程序的生命周期中“保留” AVPlayer 引用。
  • 我已经尝试过使用类变量,但问题是一样的。
  • 我仍然敢说你的班级正在释放代表来接收转发和返回消息。这可能意味着当应用程序进入后台时您的类未分配。通常为了解决这个问题,我创建了一个单例类来管理我的音频/视频播放,这样我就可以保证我的应用程序在应用程序的整个生命周期中都牢牢地保持在我的 AVPlayer 上。
  • 我建议发布您的整个 UIViewController(或您使用的任何 ViewController)代码,以便我可以看到您的代码的整个上下文。正如我之前所说,根据您提供的微小 sn-p,很难确定到底发生了什么。
  • 看看这个文档。 developer.apple.com/library/ios/documentation/AVKit/Reference/…“在Apple TV上,你可以实现播放导航和插页式内容相关的方法。”根据文档,播放导航在 avplayerviewcontroller 委托中处理。我可能会建议在您的 viewWillAppear 方法中设置 delegate = self 以保证您的类实际上再次成为委托,以防它由于某种原因“放开”它

标签: ios swift avplayer tvos avplayerviewcontroller


【解决方案1】:

试试这个...可能不是“最佳”解决方案,但它显示了我在谈论的关于视图控制器生命周期的内容。

旁注,我建议您始终在视图控制器的覆盖函数中调用 super.viewWillAppear(animated)。

import UIKit
import Foundation
import AVKit
import AVFoundation

class ViewController: UIViewController ,AVPlayerViewControllerDelegate{
    let playerController = AVPlayerViewController()
    var playerObj:AVPlayer = AVPlayer()
    var asset:AVAsset!
    var playerItem:AVPlayerItem!
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
    }
override func viewWillAppear(animated: Bool) {
    super.viewWillAppear(animated) // always call this
    playerController.delegate = self
    NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(setDelegateOnForground), name: "application_forgrounded", object: nil)
}

override func viewDidAppear(animated: Bool) {
    super.viewDidAppear(animated) // always call this
    // check the player rate if 0 means it's paused / not playing

如果 playerObj.rate == 0 { playVideo("http://p.events-delivery.apple.com.edgesuite.net/1509pijnedfvopihbefvpijlkjb/m3u8/hls_vod_mvp.m3u8") } } //MARK:- 播放视频方法。 func playVideo(videoURL:String) { print("视频网址========(视频网址)") self.asset = AVAsset(URL: NSURL(string: videoURL)!) 作为 AVAsset self.playerItem = AVPlayerItem(资产:self.asset) self.playerObj = AVPlayer(playerItem: self.playerItem) self.playerController.player = self.playerObj playerController.view.frame = CGRectMake(0.0, 0.0, UIScreen.mainScreen().bounds.width, UIScreen.mainScreen().bounds.height) self.view.addSubview(playerController.view) self.playerController.showsPlaybackControls = true self.playerItem.addObserver(self, forKeyPath: "status", options: NSKeyValueObservingOptions.New, context: nil) self.playerController.player!.play() //self.playerController.player!.play()

}

func setDelegateOnForground() {
    playerController.delegate = self
}
override func observeValueForKeyPath(keyPath: String?, ofObject object: AnyObject?, change: [String : AnyObject]?, context: UnsafeMutablePointer<Void>){

    if object as? NSObject == playerItem && (keyPath! as NSString).isEqualToString("status") {

        if (playerItem?.status == AVPlayerItemStatus.ReadyToPlay) {
            print("Player Ready to play")
        }
        if (playerItem?.status == AVPlayerItemStatus.Failed) || (playerItem?.status == AVPlayerItemStatus.Unknown) {

            print("Player getting play error")
        }
    }
}


override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
}

}

在你的 AppDelegate.swift 中

    func applicationDidBecomeActive(application: UIApplication) {
    // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
    NSNotificationCenter.defaultCenter().postNotification(NSNotification(name: "application_forgrounded", object: nil))
}

这将保证设置你的委托

【讨论】:

  • 此代码无效。如果应用程序从后台进入前台,则 viewWillAppear 不会调用。
  • 所以在发布了正确的版本后,它对我有用。我可以使用跳过功能在视频中来回切换
  • 你能在我的邮箱 vipul@fusionitechnologies.com 中给我发送演示应用吗
  • 发送压缩文件。代码和这里的一样。
  • 我已经运行了演示应用程序但无法正常工作。如果应用程序进入背景到前景并且用户在触摸表面上点击,则暂停缩略图不会显示,也不会使用触摸表面向前和向后。此代码在模拟器中有效,但在 Apple tv 中无效。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-02-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多