Resume AVPlayer video playback after app become active

后端 未结 5 1307
天涯浪人
天涯浪人 2021-02-02 15:53

I write custom player from AVPlayer for video playback. According to Apple docs set the video layer:

    self.player = [IPLPlayer new];
    self.player.playerLa         


        
相关标签:
5条回答
  • 2021-02-02 16:33

    This works for me on Swift 3

    Add somewhere while setting up the view:

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

    Grab your player and force it to play:

    func appWillEnterForegroundNotification() {
      myPlayer.play()
    }
    

    Don't forget to remove the observers when you don't need them:

    override func viewWillDisappear(_ animated: Bool) {
      super.viewWillDisappear(animated)
      NotificationCenter.default.removeObserver(self)
    }
    
    0 讨论(0)
  • 2021-02-02 16:33

    Use the UIApplicationWillEnterForegroundNotification as well. That way you know your app will be active and visible to the user:

    [[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(appEnteredForeground:) name:UIApplicationWillEnterForegroundNotification object:nil];
    
    0 讨论(0)
  • 2021-02-02 16:35

    And one solution that binds all this information together.

    Maybe player status should be handled differently, but I like the recursive way.

    Note: If you do not need the exact seek time, you can use [_player seekToTime:<#(CMTime)#> completionHandler:<#^(BOOL finished)completionHandler#>] It's faster but it seeks to the nearest key frame.

    - (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];
            });
        }
    }
    
    0 讨论(0)
  • 2021-02-02 16:42

    The trick is to detach all video layers from their players when the app did enter background and reattaching them when the app did become active again.

    So in your -applicationDidEnterBackground: you got to trigger a mechanism that results in

    avPlayerLayer.player = nil;
    

    and in your -applicationDidBecomeActive: you reattach the player like

    avPlayerLayer.player = self.avPlayer;
    

    Also have a look at this Tech Note (QA1668) from Apple.

    0 讨论(0)
  • 2021-02-02 16:43

    After some research I've found, that the same bag is in iOS player (WebBrowser, MPMoviePlayerController). May be because distribution type of content is Progressive Download.

    So solution is:

    • Use below notifications and save current time.
    • After app is resumed, recreate AVPlayer and start playing from saved time.

    In all other cases image is blocked, or view become black.

    0 讨论(0)
提交回复
热议问题