简体   繁体   English

如何将AVPlayerLayer与AVPlayer分离以在后台播放视频?

[英]How to detach AVPlayerLayer from AVPlayer to play video in background state?

I am trying to play video in background.I follow so many tutorial but i did not get appropriate results.For that i am using AVPlayer.I am able to play my video whenever application state is active.But i want to play music in background for that i need to detach AVPlayerLayer from AVPlayer,If you have any alternate solution so that i can play my video in background.Please help me. 我试图在后台播放视频。我遵循了很多教程,但没有得到合适的结果。为此,我正在使用AVPlayer。只要应用程序处于活动状态,我都可以播放视频。但是我想在后台播放音乐为此,我需要从AVPlayer分离AVPlayerLayer,如果您有任何其他解决方案,以便我可以在后台播放视频。请帮助我。

This is my code: 这是我的代码:

ViewController.m ViewController.m

- (void)viewDidLoad
{
    [super viewDidLoad];
    [[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
    [self becomeFirstResponder];
    [[AVAudioSession sharedInstance] setDelegate: self];
    [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:nil];
    [[AVAudioSession sharedInstance] setActive: YES error: nil];

    NSURL *url = [[NSBundle mainBundle] URLForResource:@"sample"
              withExtension:@"m4v" subdirectory:nil];
avPlayerItem = [AVPlayerItem playerItemWithURL:url];
    self.songPlayer = [AVPlayer playerWithPlayerItem:avPlayerItem];
    self.avPlayerLayer = [AVPlayerLayer playerLayerWithPlayer: self.songPlayer];
    self.avPlayerLayer.frame = self.view.layer.bounds;
    UIView *newView = [[UIView alloc] initWithFrame:self.view.bounds];
    [newView.layer addSublayer:avPlayerLayer];
    [self.view addSubview:newView];
    [self.songPlayer play];
   }

AppDelegate.m AppDelegate.m

- (void)applicationWillResignActive:(UIApplication *)application
{
    ViewController *vc=[[ViewController alloc]init];
    vc.avPlayerLayer = [AVPlayerLayer playerLayerWithPlayer:nil];
}
- (void)applicationDidBecomeActive:(UIApplication *)application
{
    ViewController *vc=[[ViewController alloc]init];
    vc.avPlayerLayer = [AVPlayerLayer playerLayerWithPlayer:vc.songPlayer];

}

You are creating a new view controller in both your application delegate methods, with a new player etc.. That will not change a thing. 您将在两个应用程序委托方法中以及新播放器等中创建一个新的视图控制器。这不会改变任何事情。 You must use the player and layer you created in the view controller's viewDidLoad method, and modify that one later in the delegate methods. 您必须使用在视图控制器的viewDidLoad方法中创建的播放器和图层,并稍后在委托方法中对其进行修改。 For this, your application delegate could store the main view controller in it's properties, or you could implement the NSNotifications for application delegate in your view controller class, like so: (could be added to the view controller's viewDidLoad method) 为此,您的应用程序委托可以将主视图控制器存储在其属性中,或者可以在视图控制器类中为应用程序委托实现NSNotifications,如下所示:(可以添加到视图控制器的viewDidLoad方法中)

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(appDidBecomeActive:) name:UIApplicationDidBecomeActiveNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(appWillResignActive:) name:UIApplicationWillResignActiveNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(appDidEnterBackground:) name:UIApplicationDidEnterBackgroundNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(appWillEnterForeground:) name:UIApplicationWillEnterForegroundNotification object:nil];

To detach the player layer from the player, as it's said in the documentation, is slightly incorrect, at least confusing. 如文档中所述,将播放器层与播放器分离,这是不正确的,至少会造成混淆。 In fact you have to detach the player from the player layer. 实际上,您必须将播放器与播放器层分离。 Add this code to the applicationDidEnterBackground (not applicationWillResignActive) method: 将此代码添加到applicationDidEnterBackground(不是applicationWillResignActive)方法:

// Detach player from playerlayer to avoid pause while in background
if (self.playerLayer && self.player)
{
    [self.playerLayer setPlayer: nil];
}

In your applicationWillEnterForeground, store a flag to remember that when the application becomes active, it is due to entering the foreground, and not one of the other numerous reasons for which applicationDidBecomeActive may be called: 在您的applicationWillEnterForeground中,存储一个标志以记住该应用程序变为活动状态时,这是由于进入前台而引起的,而不是调用applicationDidBecomeActive的其他众多原因之一:

self.enteringForeground = true;

And then, in your applicationDidBecomeActive: method, 然后,在您的applicationDidBecomeActive:方法中,

if (self.enteringForeground)
{
    // Re-attach player to playerlayer
    if (self.playerLayer && self.player)
    {
        if (self.playerLayer.player != self.player)
            [self.playerLayer setPlayer: self.player];
    }

    self.enteringForeground = false;
}

For this to work, you will need a new property in your application delegate .h file or view controller .h file, depending which implementation you chose: 为此,在您的应用程序委托.h文件或视图控制器.h文件中需要一个新属性,具体取决于您选择的实现:

@property (readwrite)           BOOL            enteringForeground;

Of course, you also need to add the entry UIBackgroundModes with value 'audio' to your application's info.plist file (or in the Info tab of your project, add the entry 'Required background modes' and then the value 'App plays audio or streams audio/video using AirPlay'). 当然,您还需要将值为“音频”的UIBackgroundModes条目添加到应用程序的info.plist文件中(或在项目的“信息”标签中,添加条目“必需的背景模式”,然后值为“ App播放音频或使用AirPlay流音频/视频”)。

I hope this is helpful. 我希望这是有帮助的。 I too struggled at first to implement background playback, and this method seems to work quite well. 起初我也很努力地实现后台播放,这种方法似乎效果很好。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM