IOS How to determine when video clip is finished playing - ios

In my application I need to play a movie from vimeo, this goes fine but my hole application is made for portrait only. I want to play the movie in a specific viewController and force this controller to be able to rotate to portrait or landscape.
When someone clicks the thumbnail of the movie, I segue to the VideoViewController, I need to know how to determine when this movie clips is finished so I can segue them back directly after the video is finished.
Code;
#implementation VideoViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
[self vimeoVideo];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(void)vimeoVideo
{
[YTVimeoExtractor fetchVideoURLFromURL:#"http://vimeo.com/1071123395"
quality:YTVimeoVideoQualityMedium
referer:#"http://xxxxx.com"
completionHandler:^(NSURL *videoURL, NSError *error, YTVimeoVideoQuality quality) {
if (error) {
// handle error
NSLog(#"Video URL: %#", [videoURL absoluteString]);
} else {
// run player
self.playerView = [[MPMoviePlayerViewController alloc] initWithContentURL:videoURL];
[self.playerView.moviePlayer prepareToPlay];
[self presentViewController:self.playerView animated:YES completion:^(void) {
self.playerView = nil;
}];
}
}];
}

You need to add an observer on viewDidLoad so when your Video will stop playing, let it execute your method.
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(moviePlayerDidFinish:) name:MPMoviePlayerPlaybackDidFinishNotification object:playerView];
This is the receiver method when the video stops playing
- (void)moviePlayerDidFinish:(NSNotification *)notification
{
//Do your stuff
}

In the MPMoviePlayerController, there are list of Notifications available for you. The one you need is MPMoviePlayerPlaybackDidFinishNotification
Posted when a movie has finished playing. The userInfo dictionary of this notification contains the MPMoviePlayerPlaybackDidFinishReasonUserInfoKey key, which indicates the reason that playback finished. This notification is also sent when playback fails because of an error.

Related

Prevent AVPlayer from pausing when it enters the background?

I have a simple app with an AVPlayer playing M3U8 content. Within the app, I do the following to allow background audio:
NSError *audioError;
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:&audioError];
if (audioError == nil)
{
[[AVAudioSession sharedInstance] setActive:YES error:nil];
}
When I hit the lock button on my phone, the audio pauses. If I hit the lock button again (to look at the lock screen) I see media controls and I can un-pause the content to hear the audio.
My question is, how do I prevent this auto-pause so it keeps playing when the lock button is first pressed? I tried something like the following:
- (id) init
{
// ...
[[NSNotificationCenter defaultCenter] addObserver: self selector: #selector(handleEnteredBackground) name: UIApplicationDidEnterBackgroundNotification object: nil];
// ...
}
- (void) handleEnteredBackground
{
// [player play];
[player performSelector:#selector(play) withObject:nil afterDelay:1];
}
But this didn't seem to work.
After some searching I figured out my issue:
https://developer.apple.com/documentation/avfoundation/media_assets_playback_and_editing/creating_a_basic_video_player_ios_and_tvos/playing_audio_from_a_video_asset_in_the_background
If you’re playing audio-only assets, such as MP3 or M4A files, your setup is complete and your app can play background audio. If you need to play the audio portion of a video asset, an additional step is required. If the player’s current item is displaying video on the device, playback of the AVPlayer instance is automatically paused when the app is sent to the background. If you want to continue playing audio, you disconnect the AVPlayer instance from the presentation when entering the background and reconnect it when returning to the foreground.
Their (Swift) example code looks like so:
func applicationDidEnterBackground(_ application: UIApplication) {
// Disconnect the AVPlayer from the presentation when entering background
// If presenting video with AVPlayerViewController
playerViewController.player = nil
// If presenting video with AVPlayerLayer
playerLayer.player = nil
}
func applicationWillEnterForeground(_ application: UIApplication) {
// Reconnect the AVPlayer to the presentation when returning to foreground
// If presenting video with AVPlayerViewController
playerViewController.player = player
// If presenting video with AVPlayerLayer
playerLayer.player = player
}
An Objective-C equivalent would be:
- (void) applicationDidEnterBackground:(UIApplication*)application
{
playerViewController.player = nil;
}
- (void) applicationWillEnterForeground:(UIApplication*)application
{
playerViewController.player = player;
}
Or in my case the player was embedded into a View and was not controlled directly by the app delegate or the view controller, so I used the following:
- (id) init
{
// ...
[[NSNotificationCenter defaultCenter] addObserver: self selector: #selector(handleEnteredBackground) name: UIApplicationDidEnterBackgroundNotification object: nil];
[[NSNotificationCenter defaultCenter] addObserver: self selector: #selector(handleEnteredForeground) name: UIApplicationDidBecomeActiveNotification object: nil];
// ...
}
- (void) handleEnteredBackground
{
controller.player = nil;
}
- (void) handleEnteredForeground
{
controller.player = player;
}

Check if AVPlayer is playing already

I have a tableview of songs on the ios device and if I select a row, I push to a new view where AVPlayer starts playing the selected song. Now if I go back and select another row, pushing to the view the app will start playing the new song, while continue to play the one that was running already.
EDIT:
I tried using the rate value like this without success, as it will always output "not playing" if i put it in my viewdidload method, even if a song is playing:
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
appDelegate = (SimpleTableAppDelegate *)[[UIApplication sharedApplication] delegate];
appDelegate.audioPlayer = [[AVPlayer alloc] init];
if (appDelegate.audioPlayer.rate == 0.0f)
{
NSLog(#"not playing");
} else {
NSLog(#"already playing");
}
}
In this line
appDelegate.audioPlayer = [[AVPlayer alloc] init];
you seem to be alloc'ing and init'ing a new AVPlayer. As such it's not surprising that you get a "not playing" result. Simply leave out that line.
AVPlayer has a rate property which indicates the speed of playback as a float. 0.0f indicates stopped. The play and stop methods just change the rate property.
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
appDelegate = (SimpleTableAppDelegate *)[[UIApplication sharedApplication] delegate];
//Stop potential existing audioPlayer prior to creating new player
[appDelegate.audioPlayer stop];
//Create new audio player
appDelegate.audioPlayer = [[AVPlayer alloc] init];
}

MPMoviePlayerController plays only when called twice. Only occurs in iOS 4

I have an app for iOS 4.0-5.1 that uses HTTP Live Streaming to play videos. I have a simple setup with a button in a view that starts playing the stream when it is tapped. This works fine in iOS 5 but the button needs to be tapped twice before the stream begins playing in iOS 4. Does anybody know why this is happening and how to make the video play on the first tap of the button?
Here is what I'm doing:
.h
#import <UIKit/UIKit.h>
#import <MediaPlayer/MediaPlayer.h>
#interface ViewController : UIViewController{
MPMoviePlayerController *moviePlayer;
}
#property (nonatomic, strong) MPMoviePlayerController *moviePlayer;
-(IBAction)playApple:(id)sender;
#end
.m
-(IBAction)playApple:(id)sender{
if(self.moviePlayer){
self.moviePlayer = nil;
}
//Use Apple's sample stream
NSURL *mediaURL = [NSURL URLWithString:#"http://devimages.apple.com/iphone/samples/bipbop/bipbopall.m3u8"];
self.moviePlayer = [[MPMoviePlayerController alloc] initWithContentURL:mediaURL];
//Begin observing the moviePlayer's load state.
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(moviePlayerLoadStateChanged:)
name:MPMoviePlayerLoadStateDidChangeNotification
object:self.moviePlayer];
[self.moviePlayer setMovieSourceType:MPMovieSourceTypeStreaming];
[self.moviePlayer setShouldAutoplay:NO];//Stop it from autoplaying
[self.moviePlayer prepareToPlay];//Start preparing the video
}
#pragma mark Notification Center
- (void)moviePlayerLoadStateChanged:(NSNotification *)notification{
NSLog(#"State changed to: %d\n", moviePlayer.loadState);
if(self.moviePlayer.loadState == MPMovieLoadStatePlayable){
//if load state is ready to play
[self.view addSubview:[self.moviePlayer view]];
[self.moviePlayer setFullscreen:YES];
[self.moviePlayer play];//play the video
}
}
I can see some possible issues - just try it out and let us know if any or all of this did the trick.
1. loadstate masking
The loadstate should not be directly compared but masked before comparing as it might contain a mixture of multiple states.
MPMovieLoadState
Constants describing the network load state of the movie player.
enum {
MPMovieLoadStateUnknown = 0,
MPMovieLoadStatePlayable = 1 << 0,
MPMovieLoadStatePlaythroughOK = 1 << 1,
MPMovieLoadStateStalled = 1 << 2,
};
typedef NSInteger MPMovieLoadState;
So instead of directly comparing it, as you are, mask it to be on the safe side.
2. view setup
Why not setting up the player view right before starting the playback. I have never seen it the way you do it (not that I was positively sure that this is the problem - still, seems odd to me). Additionally, even though the player will not actually use the view you are assigning (fullscreen mode does it a bit differently), you may want to enhance the view-setup with assigning a proper frame.
All of the above rolled into this new version of your code...
-(IBAction)playApple:(id)sender
{
if(self.moviePlayer)
{
self.moviePlayer = nil;
}
//Use Apple's sample stream
NSURL *mediaURL = [NSURL URLWithString:#"http://devimages.apple.com/iphone/samples/bipbop/bipbopall.m3u8"];
self.moviePlayer = [[MPMoviePlayerController alloc] initWithContentURL:mediaURL];
//Begin observing the moviePlayer's load state.
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(moviePlayerLoadStateChanged:)
name:MPMoviePlayerLoadStateDidChangeNotification
object:self.moviePlayer];
self.moviePlayer.view.frame = self.view.bounds;
[self.view addSubview:[self.moviePlayer view]];
[self.moviePlayer setFullscreen:YES];
[self.moviePlayer setMovieSourceType:MPMovieSourceTypeStreaming];
[self.moviePlayer setShouldAutoplay:NO]; //Stop it from autoplaying
[self.moviePlayer prepareToPlay]; //Start preparing the video
}
- (void)moviePlayerLoadStateChanged:(NSNotification *)notification
{
NSLog(#"State changed to: %d\n", moviePlayer.loadState);
if((self.moviePlayer.loadState & MPMovieLoadStatePlayable) == MPMovieLoadStatePlayable)
{
//if load state is ready to play
[self.moviePlayer play];//play the video
}
}

MPMoviePlayerController - Split view controller should have its children set before layout

What is the appropriate point to send the play message to a MPMoviePlayerController instance instantiated in a splitView detail View Controller?
My app is receiving the above console message (with a !) but not crashing...
The app is utilizing MPMoviePlayerController to play a movie from an asset URL
and the responsilble method is called as follows:
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
[self startPlayingVideo:self];
}
It plays the video just fine but the console message is looming...
If I move the method call to viewWillAppear:animate:, the console message does not show up. The issue is now I can only hear audio and do not see the video.
For completeness, here is the called method...
- (void) startPlayingVideo:(id)sender
NSURL *movieURL = [NSURL URLWithString:self.movieURLString];
if (self.moviePlayer != nil){
[self stopPlayingVideo:nil];
}
self.moviePlayer = [[MPMoviePlayerController alloc] initWithContentURL:movieURL ];
if (self.moviePlayer != nil){
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:#selector(videoHasFinishedPlaying:)
name:MPMoviePlayerPlaybackDidFinishNotification
object:self.moviePlayer];
self.moviePlayer.scalingMode = MPMovieScalingModeAspectFit;
[self.moviePlayer prepareToPlay];
[self.moviePlayer play];
[self.view addSubview:self.moviePlayer.view];
[self.moviePlayer setFullscreen:YES animated:YES];
} else {
NSLog(#"Failed to instantiate the movie player.");
}
}
My original issue stemmed from having the MoviePlayerController as an entirely different viewController (embedded in a detail navigation controller). I redesigned the parent view to include a moviePlayer child view. This solved the issue.

How to receive NSNotifications from UIWebView embedded YouTube video playback

I didn't received any notifications for MPMoviePlayerController. What am I doing wrong?
I use following logic.
I'm begining to play youtube video in UIWebView. UIWebView calls a standard MPMoviePlayerController. I don't control MPMoviePlayerController because I didn't instantiate MPMoviePlayerController.
I run youtube's clip with autoplay (1 second delay):
[self performSelector:#selector(touchInView:) withObject:b afterDelay:1];
My code is:
- (void)viewDidLoad
{
[super viewDidLoad];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(loadStateDidChange:) name:MPMoviePlayerLoadStateDidChangeNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(playbackDidFinish:) name:MPMoviePlayerDidExitFullscreenNotification object:nil];
[self embedYouTube];
}
- (void)loadStateDidChange:(NSNotification*)notification
{
NSLog(#"________loadStateDidChange");
}
- (void)playbackDidFinish:(NSNotification*)notification
{
NSLog(#"________DidExitFullscreenNotification");
}
- (void)embedYouTube
{
CGRect frame = CGRectMake(25, 89, 161, 121);
NSString *urlString = [NSString stringWithString:#"http://www.youtube.com/watch?v=sh29Pm1Rrc0"];
NSString *embedHTML = #"<html><head>\
<body style=\"margin:0\">\
<embed id=\"yt\" src=\"%#\" type=\"application/x-shockwave-flash\" \
width=\"%0.0f\" height=\"%0.0f\"></embed>\
</body></html>";
NSString *html = [NSString stringWithFormat:embedHTML, urlString, frame.size.width, frame.size.height];
UIWebView *videoView = [[UIWebView alloc] initWithFrame:frame];
videoView.delegate = self;
for (id subview in videoView.subviews)
if ([[subview class] isSubclassOfClass: [UIScrollView class]])
((UIScrollView *)subview).bounces = NO;
[videoView loadHTMLString:html baseURL:nil];
[self.view addSubview:videoView];
[videoView release];
}
- (void)webViewDidFinishLoad:(UIWebView *)_webView
{
UIButton *b = [self findButtonInView:_webView];
[NSObject cancelPreviousPerformRequestsWithTarget:self selector:#selector(touchInView:) object:b];
[self performSelector:#selector(touchInView:) withObject:b afterDelay:1];
}
- (UIButton *)findButtonInView:(UIView *)view
{
UIButton *button = nil;
if ([view isMemberOfClass:[UIButton class]]) {
return (UIButton *)view;
}
if (view.subviews && [view.subviews count] > 0)
{
for (UIView *subview in view.subviews)
{
button = [self findButtonInView:subview];
if (button) return button;
}
}
return button;
}
- (void)touchInView:(UIButton*)b
{
[b sendActionsForControlEvents:UIControlEventTouchUpInside];
}
UPDATE: I'm creating application that plays youtube's video. You can run playlist and you will see first video. When first video has ended, second video begins play automatically and so on.
I need to support ios 4.1 and above.
UPDATE2: #H2CO3 I'm trying to use your url-scheme, but it don't works. Delegate method didn't called on exit event. I added my html url to log.
It is:
<html><head> <body style="margin:0">
<script>function endMovie()
{document.location.href="somefakeurlscheme://video-ended";}
</script> <embed id="yt" src="http://www.youtube.com/watch?v=sh29Pm1Rrc0"
onended="endMovie()" type="application/x-shockwave-flash"
width="161" height="121"></embed>
</body></html>
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{
if ([[[request URL] absoluteString] hasPrefix:#"somefakeurlscheme://video-ended"])
{
[self someMethodSupposedToDetectVideoEndedEvent];
return NO; // prevent really loading the URL
}
return YES; // else load the URL as desired
}
UPDATE3
#Till, I cann't caught UIMoviePlayerControllerDidExitFullscreenNotification, but I found MPAVControllerItemPlaybackDidEndNotification. MPAVControllerItemPlaybackDidEndNotification appears when playback video is ended.
But I don't understand how do I catch onDone notifications?
There are no documented notifications sent by the UIWebView embedded movie player.
In fact, the closed implementation used within the UIWebView does differ from the public MPMoviePlayerController in many aspects (e.g. DRM).
The most important classes used for playing video content within that UIWebView are called MPAVController and UIMoviePlayerController. The latter one makes the player appear like the MPMoviePlayerController fullscreen interface.
In case you dare to risk a rejection by Apple, there are actually ways to still achieve what you are looking for.
NOTE
This is not documented and is subject to break on each and every new iOS release. It does however work on iOS4.3, 5.0 and 5.01, 5.1 and 6.0 and it may work on other versions as well.
I am not able to test this solution on iOS 4.1 and 4.2, so that is up to you to do. I highly suspect that it will work.
Fullscreen State
If, for example you are intending to react upon the user tapping the DONE button, you may be able to do it this way:
UPDATE The old version of this answer recommended to use UIMoviePlayerControllerDidExitFullscreenNotification whereas this new version (updated for iOS6) recommends using UIMoviePlayerControllerWillExitFullscreenNotification.
C-Language Level:
void PlayerWillExitFullscreen (CFNotificationCenterRef center,
void *observer,
CFStringRef name,
const void *object,
CFDictionaryRef userInfo)
{
//do something...
}
CFNotificationCenterAddObserver(CFNotificationCenterGetLocalCenter(),
NULL,
PlayerWillExitFullscreen,
CFSTR("UIMoviePlayerControllerWillExitFullscreenNotification"),
NULL,
CFNotificationSuspensionBehaviorDeliverImmediately);
Objective-C Level:
- (void)playerWillExitFullscreen:(NSNotification *)notification
{
//do something...
}
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(playerWillExitFullscreen:)
name:#"UIMoviePlayerControllerWillExitFullscreenNotification"
object:nil];
I did draft both, C-Level and Objective-C-Level options because the best way to actually find out about all of this is to use C-Level (CoreFoundation) functions as shown at the end of my answer. If the sender of a notification does not use Objective-C (NSNotifications), you may actually not be able to trap them using the NSNotification-mechanics.
Playback State
For examining the playback state, look out for "MPAVControllerPlaybackStateChangedNotification" (as drafted above) and examine the userInfo which may look like this:
{
MPAVControllerNewStateParameter = 1;
MPAVControllerOldStateParameter = 2;
}
Further Reverse Engineering
For reverse engineering and exploring all the notifications sent, use the following snippet.
void MyCallBack (CFNotificationCenterRef center,
void *observer,
CFStringRef name,
const void *object,
CFDictionaryRef userInfo)
{
NSLog(#"name: %#", name);
NSLog(#"userinfo: %#", userInfo);
}
CFNotificationCenterAddObserver(CFNotificationCenterGetLocalCenter(),
NULL,
MyCallBack,
NULL,
NULL,
CFNotificationSuspensionBehaviorDeliverImmediately);
In iOS 4.3+ you can use the UIMoviePlayerControllerDidEnterFullscreenNotification and UIMoviePlayerControllerDidExitFullscreenNotification notifications:
-(void)viewDidLoad
{
...
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(youTubeStarted:) name:#"UIMoviePlayerControllerDidEnterFullscreenNotification" object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(youTubeFinished:) name:#"UIMoviePlayerControllerDidExitFullscreenNotification" object:nil];
}
-(void)youTubeStarted:(NSNotification *)notification{
// your code here
}
-(void)youTubeFinished:(NSNotification *)notification{
// your code here
}
As far as I know, the implementation details of UIWebView (and all system classes made by Apple) are not to be relied upon when making a Cocoa Touch application. Maybe it's the case that an UIWebView's video player is not a standard MPMoviePlayerController class and it might have a totally different delegation/notification system, which is not supposed to be accessible by the user.
I suggest you to use the HTML5 element and detect the "onended" event of this tag:
<html>
<body>
<script>
function endMovie() {
// detect the event here
document.location.href="somefakeurlscheme://video-ended";
}
</script>
<video src="http://youtube.com/watch?v=aiugvdk755f" onended="endMovie()"></video>
</body>
</html>
In fact, from the endMovie JavaScript function, you can redirect to a bogus URL which you can catch in your -webView:shouldStartLoadWithRequest: (UIWebViewDelegate) method thus get notified that the video has ended:
- (BOOL) webView:(UIWebView *)wv shouldStartLoadWithRequest:(NSURLRequest *)req {
if ([[[req URL] absoluteString] hasPrefix:#"somefakeurlscheme://video-ended"]) {
[self someMethodSupposedToDetectVideoEndedEvent];
return NO; // prevent really loading the URL
}
return YES; // else load the URL as desired
}
Hope this helps.
Based on the #H2CO3 answer but with the iframe API. It was the only way I could make it work.
This doesn't use any private API which makes it more future proof.
Here's the code to embed your Youtube video. Check the API for more ways to customise this.
<html>
<body>
<!-- 1. The <iframe> (and video player) will replace this <div> tag. -->
<div id="player"></div>
<script>
// 2. This code loads the IFrame Player API code asynchronously.
var tag = document.createElement('script');
tag.src = "https://www.youtube.com/iframe_api";
var firstScriptTag = document.getElementsByTagName('script')[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
// 3. This function creates an <iframe> (and YouTube player)
//    after the API code downloads.
var player;
function onYouTubeIframeAPIReady() {
player = new YT.Player('player', {
height: '480',
width: '640',
videoId: 'aiugvdk755f',
events: {
'onStateChange': onPlayerStateChange
}
});
}
// 5. The API calls this function when the player's state changes.
function onPlayerStateChange(event) {
if (event.data == YT.PlayerState.ENDED) {
endedMovie();
}
}
function endedMovie() {
// detect the event here
document.location.href="somefakeurlscheme://video-ended";
}
</script>
</body>
</html>
And this is how you get notified that the video ended (UIWebViewDelegate method).
- (BOOL) webView:(UIWebView *)wv shouldStartLoadWithRequest:(NSURLRequest *)req {
if ([[[req URL] absoluteString] hasPrefix:#"somefakeurlscheme://video-ended"]) {
[self someMethodSupposedToDetectVideoEndedEvent];
return NO; // prevent really loading the URL
}
return YES; // else load the URL as desired
}
in ViewDidLoad add the following code
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(VideoExitFullScreen:) name:#"UIMoviePlayerControllerDidExitFullscreenNotification" object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(VideoEnterFullScreen:) name:#"UIMoviePlayerControllerDidEnterFullscreenNotification" object:nil];
The following methods are for showing the message/functions for respective process of entering/exiting to/from full screen
- (void)VideoExitFullScreen:(id)sender{
// Your respective content/function for Exit from full screen
}
- (void)VideoEnterFullScreen:(id)sender{
// Your respective content/function for Enter to full screen
}
This works for me in iOS 6.1, it hides/removes other windows when the AVPlayerItemDidPlayToEndTimeNotification is received:
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(playerItemEnded:) name:AVPlayerItemDidPlayToEndTimeNotification object:nil];
...
- (void)playerItemEnded:(NSNotification *)notification
{
for (UIWindow *window in [[UIApplication sharedApplication] windows]) {
if (window != self.window) {
window.hidden = YES;
}
}
}
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(youTubeStarted:) name:UIWindowDidBecomeVisibleNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(youTubeFinished:) name:UIWindowDidBecomeHiddenNotification object:nil];
-(void)youTubeStarted:(NSNotification *)notification
{
// Entered Fullscreen code goes here..
AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
appDelegate.fullScreenVideoIsPlaying = YES;
NSLog(#"%f %f",webViewForWebSite.frame.origin.x,webViewForWebSite.frame.origin.y);
}
-(void)youTubeFinished:(NSNotification *)notification{
// Left fullscreen code goes here...
AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
appDelegate.fullScreenVideoIsPlaying = NO;
//CODE BELOW FORCES APP BACK TO PORTRAIT ORIENTATION ONCE YOU LEAVE VIDEO.
[[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationPortrait animated:NO];
//present/dismiss viewcontroller in order to activate rotating.
UIViewController *mVC = [[UIViewController alloc] init];
[self presentViewController:mVC animated:NO completion:Nil];
// [self presentModalViewController:mVC animated:NO];
[self dismissViewControllerAnimated:NO completion:Nil];
// [self dismissModalViewControllerAnimated:NO];
}
For iOS8 (Also I have an embedded video that is not a youtube video) the only solution I could get to work was to catch either one of viewWill/DidLayoutSubviews, and as an added bonus you don't need to change the HTML or use any private APIs :
So basically:
#property (nonatomic) BOOL showingVideoFromWebView;
...
...
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request
navigationType:(UIWebViewNavigationType)navigationType {
if (navigationType == UIWebViewNavigationTypeOther) {
//Was "other" in my case... Might be UIWebViewNavigationTypeLinkClicked
self.showingVideoFromWebView = YES;
}
}
- (void)viewWillLayoutSubviews {
[super viewWillLayoutSubviews];
// Do whatever...
// Note: This will get called both when video is entering fullscreen AND exiting!
self.showingVideoFromWebView = NO;
}
In my case my web view is inside a UITableViewCell so I had to find a way to communicate between the cell and the view controller, and to also avoid using a BOOL flag I did this:
- (BOOL)webView:(UIWebView *)webView shouldStartLoad.....
... if (opening video check....) {
[[NSNotificationCenter defaultCenter] addObserverForName:#"webViewEmbedVidChangedState" object:nil queue:nil usingBlock:^(NSNotification *note) {
// Do whatever need to be done when the video is either
// entering fullscreen or exiting fullscreen....
[[NSNotificationCenter defaultCenter] removeObserver:self name:#"webViewEmbedVidChangedState" object:nil];
}];
}
- (void)viewWillLayoutSubviews.....
[[NSNotificationCenter defaultCenter] postNotificationName:#"webViewEmbedVidChangedState" object:nil];
Actually for the reverse engineering purposes you can also use Cocoa API
like
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(handleNotification:)
name:nil
object:nil];
In this case you will receive all notifications

Resources