I write custom player from AVPlayer for video playback. According to Apple docs set the video layer:
self.player = [IPLPlayer new];
self.player.playerLa
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)
}
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];
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];
});
}
}
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.
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:
In all other cases image is blocked, or view become black.