Возобновление воспроизведения видео AVPlayer после активации приложения

Я пишу пользовательский плеер из AVPlayer для воспроизведения видео. Согласно документам Apple, установите уровень видео:

    self.player = [IPLPlayer new];
    self.player.playerLayer = (AVPlayerLayer *)self.playerView.layer;

Где self.playerView является обычным классом из этих документов:

    @implementation PlayerView

+ (Class) layerClass {
    return [AVPlayerLayer class];
}

- (AVPlayer *)player {
    return [(AVPlayerLayer *)[self layer] player];
}

- (void)setPlayer:(AVPlayer *) player {
    [(AVPlayerLayer *) [self layer] setPlayer:player];
}

Проблема заключается в следующем: когда закрывается приложение (кнопка "Главная") или экран блока, воспроизведение видео прекращается, и когда возобновляется ТОЛЬКО возобновление воспроизведения звука, изображение на экране по-прежнему остается на экране блока - оно полностью статично и заменяет кадры изменения.

Как возобновить воспроизведение VIDEO после блокировки экрана?

Кажется, я должен зарегистрировать уведомления, и после того, как приложение станет активным, возобновите видеослот:

    -(void)registerNotification
{
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(willEnterBackground)
                                                 name:UIApplicationWillResignActiveNotification object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(didEnterForeground)
                                                 name:UIApplicationDidBecomeActiveNotification object:nil];
}

-(void)unregisterNotification
{
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}


-(void)willEnterBackground
{
    NSLog(@"willEnterBackground");
    [self.playerView willEnterBackground];
}

-(void)didEnterForeground
{
    NSLog(@"didEnterForeground");
    [self.playerView didEnterForeground];
}

Ответ 1

И одно решение, которое связывает всю эту информацию вместе.

Возможно, статус игрока должен обрабатываться по-разному, но мне нравится рекурсивный путь.

Примечание. Если вам не требуется точное время поиска, вы можете использовать [_player seekToTime:<#(CMTime)#> completionHandler:<#^(BOOL finished)completionHandler#>] Это быстрее, но он ищет ближайший ключевой кадр.

- (void)viewDidLoad
{
    [super viewDidLoad];

....

    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(appEnteredForeground) name:UIApplicationWillEnterForegroundNotification object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(appEnteredBackground) name:UIApplicationDidEnterBackgroundNotification object:nil];
}

-(void)viewWillDisappear:(BOOL)animated
{
    [[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationWillEnterForegroundNotification object:nil];
    [[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationDidEnterBackgroundNotification object:nil];
}

....

-(void) appEnteredForeground {
    AVPlayerLayer *player = (AVPlayerLayer *)[playerView layer];
    [player setPlayer:NULL];
    [player setPlayer:_player];
    [self playAt:currentTime];
}

-(void) appEnteredBackground {
    [_player pause];
    currentTime = [_player currentTime];
}

-(void)playAt: (CMTime)time {
    if(_player.status == AVPlayerStatusReadyToPlay && _player.currentItem.status == AVPlayerItemStatusReadyToPlay) {
        [_player seekToTime:time toleranceBefore:kCMTimeZero toleranceAfter:kCMTimeZero completionHandler:^(BOOL finished) {
            [_player play];
        }];
    } else {
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            [self playAt:time];
        });
    }
}

Ответ 2

Это работает для меня на Swift 3

Добавьте где-нибудь во время настройки представления:

NotificationCenter.default.addObserver(self, 
  selector: #selector(appWillEnterForegroundNotification),
  name: .UIApplicationWillEnterForeground, object: nil)

Возьмите игрока и заставите его играть:

func appWillEnterForegroundNotification() {
  myPlayer.play()
}

Не забудьте удалить наблюдателей, когда они вам не понадобятся:

override func viewWillDisappear(_ animated: Bool) {
  super.viewWillDisappear(animated)
  NotificationCenter.default.removeObserver(self)
}

Ответ 3

Используйте также UIApplicationWillEnterForegroundNotification. Таким образом, вы знаете, что ваше приложение будет активным и видимым для пользователя:

[[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(appEnteredForeground:) name:UIApplicationWillEnterForegroundNotification object:nil];

Ответ 4

После некоторых исследований, которые я нашел, этот же пакет находится в iOS-плеере (WebBrowser, MPMoviePlayerController). Может быть, потому, что тип распространения контента - прогрессивная загрузка.

Таким образом, решение:

  • Используйте ниже уведомления и сохраните текущее время.
  • После того, как приложение возобновлено, заново создайте AVPlayer и начните воспроизведение с сохраненного времени.

Во всех остальных случаях изображение блокируется или изображение становится черным.

Ответ 5

Хитрость заключается в том, чтобы отделить все видеослои от своих игроков, когда приложение было ввести фон и реплантации их, когда приложение было снова стать активным.

Итак, в вашем -applicationDidEnterBackground: вам нужно вызвать механизм, который приводит к

avPlayerLayer.player = nil;

и в вашем -applicationDidBecomeActive: вы снова -applicationDidBecomeActive: плеер, как

avPlayerLayer.player = self.avPlayer;

Также взгляните на эту техническую ноту (QA1668) от Apple.