I created an AVPlayerViewController
and an attached AVPlayer
in the viewDidAppear
method of a custom UIViewController
. However, when I press the "Done" button my custom view controller is dismissed automatically.
I would like to intercept this action in order to use my own unwind Segue, but I'm not sure how to do this. I've found examples for MPMoviePlayerViewController
but not AVPlayerViewController
.
The code I found for MPMoviePlayerViewController
is below:
- (void)playVideo:(NSString *)aVideoUrl {
// Initialize the movie player view controller with a video URL string
MPMoviePlayerViewController *playerVC = [[[MPMoviePlayerViewController alloc] initWithContentURL:[NSURL URLWithString:aVideoUrl]] autorelease];
// Remove the movie player view controller from the "playback did finish" notification observers
[[NSNotificationCenter defaultCenter] removeObserver:playerVC
name:MPMoviePlayerPlaybackDidFinishNotification
object:playerVC.moviePlayer];
// Register this class as an observer instead
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(movieFinishedCallback:)
name:MPMoviePlayerPlaybackDidFinishNotification
object:playerVC.moviePlayer];
// Set the modal transition style of your choice
playerVC.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
// Present the movie player view controller
[self presentModalViewController:playerVC animated:YES];
// Start playback
[playerVC.moviePlayer prepareToPlay];
[playerVC.moviePlayer play];
}
- (void)movieFinishedCallback:(NSNotification *)aNotification {
// Obtain the reason why the movie playback finished
NSNumber *finishReason = [[aNotification userInfo] objectForKey:MPMoviePlayerPlaybackDidFinishReasonUserInfoKey];
// Dismiss the view controller ONLY when the reason is not "playback ended"
if ([finishReason intValue] != MPMovieFinishReasonPlaybackEnded) {
MPMoviePlayerController *moviePlayer = [aNotification object];
// Remove this class from the observers
[[NSNotificationCenter defaultCenter] removeObserver:self
name:MPMoviePlayerPlaybackDidFinishNotification
object:moviePlayer];
// Dismiss the view controller
[self dismissModalViewControllerAnimated:YES];
}
}
I asked Apple about this problem and they've replied as follows:
Thank you for contacting Apple Developer Technical Support (DTS). Our engineers have reviewed your request and have concluded that there is no supported way to achieve the desired functionality given the currently shipping system configurations.
Since there don't seem to be any perfect answers here, a workaround you can use for some situations is to monitor whether the AVPlayer is still playing and set an observer in case it closes automatically after being played all the way through.
I solved by keeping a weak reference to the AVPlayerViewController instance, and monitoring with a timer where the reference change to nil.
You could do it by subclassing AVPLayerViewController. But there is some undefined behaviour due to this. (Given in Apple docs. See below) I also tried subclassing AVPlayerViewController and I faced Memory issue.
According to the Apple Docs:
Currently, they do not offer a callback when the AVPlayerViewController is dismissed. See Apple developer forum:
In thread1 Apple guy says:
Hope it helps!
Well, there is a fix to the problem. You can add a button as a subview of AVPlayerViewController. By doing so, you could intercept done button tap gesture.
The fact that Apple provides no built-in way to handle the Done button is disappointing.
I didn't feel like inheriting from AVPlayerViewController, because it isn't supported by Apple and will probably open up a can of worms in one of the next iOS updates.
My workaround is to have a timer fire every 200 msec and check for the following condition:
The player's
rate
property of 0 indicates that the video is no longer playing. And if the view controller is being dismissed or already dismissed, we can safely assume that the user clicked the Done button.I subclassed AVPlayerViewController and am posting a notification from viewWillDisappear to indicate dismissing of AVPlayerViewController.
This might not be 100% correct (as it would fail if you have another view being displayed over AVPlayerViewController), but it worked for me as AVPlayerViewController is always at the top of the stack.
Here is code how I managed to detect clicks.
In application delegate class. But it detects every buttons find in that view. You can add some control, check title something like that.