I have a UIWebview within a UIScrollView. Within the webview I have an embedded YouTube movie. When I play the YouTube movie everything works fine, however, when I press the fullscreen button the movie starts playing behind the webview. Bringing the WebView to the front does not work, because I want the scrolling capabilities of the ScrollView to do horizontal scrolling.
Basically, you want to be able to detect when a movie starts playing fullscreen and arrange your views appropriately. Then, when the fullscreen playback ends you want to be able to get your views back to how they are.
The problem is there's no documented way to hook into or detect when a UIWebView triggers video playback in full screen.
I said 'documented way', because there are some notifications you can use to detect when a UIWebView triggers fullscreen playback. You can just listen out for them and rearrange your views accordingly. However, I don't necessarily recommend this, because they're undocumented and subject to change (in fact, they have a spelling mistake in them up until iOS 4.3, see answers below).
// For iOS 4.3 and above:
UIMoviePlayerControllerDidEnterFullscreenNotification
UIMoviePlayerControllerDidExitFullscreenNotification
// For iOS 4.2 and below:
UIMoviePlayerControllerDidEnterFullcreenNotification
UIMoviePlayerControllerDidExitFullcreenNotification // (note spelling mistake)
Finding these out was a bit of a pain - there are actually several more notifications that get triggered when a YouTube video in a UIWebView gets played back. To find them out you'll need to drop a breakpoint on all posting of notifications, and then manually inspect the memory locations of those notifications to figure out their string names. I don't actually think anyone has pulled these out before, because when I google them I get nothing. But they do work, promise!
I hope being able to get notified when the fullscreen playback is entered/exited will be helpful, with the massive caveat that Apple could change this undocumented behavior at any time. Your app won't get rejected outright for using them (because you're not calling any undocumented methods), and I've used it in shipping apps. But it's still not the best idea in the world...may be the only option you have though.
Edit: To clarify, based off the comment below: they're not constants, so you'd need to put them in quotes if you were registered for notifications.
For iOS 4.3+, Apple have changed the names of these notifications:
UIMoviePlayerControllerDidEnterFullcreenNotification now is UIMoviePlayerControllerDidEnterFullscreenNotification
UIMoviePlayerControllerDidExitFullcreenNotification now is UIMoviePlayerControllerDidExitFullscreenNotification
Please pay attention: The term "Fullcreen" has changed to "Fullscreen".
Thanks!
Just wanted to confirm that this works after playing around with it for awhile. You can get direct access to the view that the video is playing in. This is a blocks method of registering for the notification and pulling out the pertinent views.
Notice: You will need to delay adding subviews and/or access Apple internal subviews to remove the navbar for further customization.
[[NSNotificationCenter defaultCenter]
addObserverForName:#"UIMoviePlayerControllerDidEnterFullcreenNotification"
object:nil
queue:nil
usingBlock:^(NSNotification *note){
MPMoviePlayerController *theMovieController = [note object];
UIView *theDestinationVideoView = [[note userInfo]
objectForKey:#"UIMoviePlayerControllerFullscreenViewUserInfoKey"];
}];
Related
I am using the MPMoviePlayerController to play the video files in my application, videos are playing nice. But suddenly I opened one file and the MPMoviePlayerController opens in complete black screen, no controls are there. But I can see that there is a problem in my file and I resolved it.
I wonder is there any event that will be sent like MPMoviePlayerDidExitFullscreenNotification for these black screen issue. I tried with MPMovieSourceTypeUnknown event which seems to be not correct and tried with many events.
Now I want to know , is there any event will be sent , when the MPMoviePlayerController trying to open a file which results in black screen.
The documentations are fairly descriptive, though I will assume a black screen is a loading error:
MPMovieFinishReason Constants describing the reason that playback ended.
enum
{
MPMovieFinishReasonPlaybackEnded,
MPMovieFinishReasonPlaybackError,
MPMovieFinishReasonUserExited
};
typedef NSInteger MPMovieFinishReason;
Constants:
MPMovieFinishReasonPlaybackEnded
The end of the movie was reached.
Available in iOS 3.2 and later.
Declared in MPMoviePlayerController.h.
MPMovieFinishReasonPlaybackError
There was an error during playback.
Available in iOS 3.2 and later.
Declared in MPMoviePlayerController.h.
MPMovieFinishReasonUserExited
The user stopped playback.
Available in iOS 3.2 and later.
Declared in MPMoviePlayerController.h.
These are passed through the MPMoviePlayerPlaybackDidFinishNotification notification with the MPMoviePlayerPlaybackDidFinishReasonUserInfoKey key.
I have an app that's worked since version 2.0 of the SDK where I create and add a UIWebView and then load the URL of an .mov to play a movie. Ever since the early version of the 4.0 beta up until the 4.0 GM this has stopped working. When I load a movie now I get the following error: :Plug-in handled load" and the movie never displays.
Is this a known issue? Am I doing something wrong in 4.0?
I figured this out. It appears to be an issue with iOS4 not being backward compatible with a UIWebView created with 'init' rather than 'initWithFrame'. In 2.0 - 3.1.3, you could only show video in a UIWebview as full screen. I think this is why it didn't matter if you called 'init' -- the movie player would kick in and go fullscreen. However, in 3.2 and higher you can now inline video in a UIWebView so you have to call initWithFrame and give it something like [[UIScreen mainScreen] bounds] so there's a visible view. Not quite sure if this is bull or not but seems to be the case.
I got a situation of "this movie could not be played" when playing a video clip.
This happened when recorder was just used. And this would NOT happen when player was just used.
Then I set audio session category to kAudioSessionCategory_AmbientSound after recorder finished.
This problem was solved after I did that.
Simply just ignore it. No harm in doing so.
if (![error.localizedDescription isEqualToString:#"Plug-in handled load"])
At least in PhoneGap's ChildBrowser, the didFailLoadWithError method handles and displays this message. Simply don't display the error, problem solved, but in this specific case there are two 'done' buttons to press before you get back to the application.
I'm making a Web app (at chirpid.com) for the iPhone that plays audio files for cricket chirp identification. The user can start and stop the audio by tapping screen buttons. But if the user taps the home button while a sound file is playing, it continues to play in the background (an iOS4 feature). I want to stop the audio in this case. Is there an event or property that I can use via Javascript in Safari to determine when I have been put into the background?
You could manually trigger the "stop" button like this when closing the application.
- (void)applicationDidEnterBackground:(UIApplication *)application {
if(audioIsPlaying) {
[btnStop sendActionsForControlEvents:UIControlEventTouchUpInside];
}
}
You get 5 seconds to do anything when using the applicationDidEnterBackground: function.
That should be enough to stop the audio ;-).
I would guess you need to create a listener that listens to system events...
Perhaps you should read this book: http://books.google.com/books?id=a09NMFdA6m0C&pg=PA94&lpg=PA94&dq=iOS+home+button+event+javascript&source=bl&ots=4Nop45gmwI&sig=8mTEGQI1ym65H7XjmBSzRQ2KyMc&hl=en&ei=_qDWTrmMDsPh4QSR9I2rAQ&sa=X&oi=book_result&ct=result&resnum=6&ved=0CEsQ6AEwBQ#v=onepage&q=iOS%20home%20button%20event%20javascript&f=false
iOS4 has some kind of lock function you can assign to buttons, perhaps you could tie in a script to turn down volume that way.
If you found the solution be nice and post it here for others to see.
Best of luck!
I can detect that the iPhone went to sleep and came back from sleep, by using the applicationWillResignActive and applicationDidBecomeActive. But how do I find out what kind of interrupt it was. I am making an audio player application, and need to keep the audio playing when the iPhone goes to sleep (which I know how to do). But I need to interrupt the audio when a message, alarm or low battery interrupt occurs. Also I need to resume the audio when the event is over.
So how do I differentiate between these different interrupts.
That information is probably not available to your app, but here's some things to try.
In applicationWillResignActive:, check the NSNotification's object and userInfo properties to see if there are any hints there.
Register to receive all notifications posted to the default notification center:
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(didReceiveNotification:) name:nil object:nil];
Your method will be called when anything is posted. Log the notification object and userInfo dictionary and maybe you will see a useful notification being posted. If you find one, you can register just for that.
This is the most hacky, but you might be able to get access to the alert that is displayed if it is a message or battery warning. Alerts are displayed in a UIWindow over your app's main UIWindow. You could register for UIWindowDidBecomeVisibleNotification, then look at the window's subviews to see if you can find an alert or some other useful clue.
All of the above methods would be relying on undocumented behavior to work, and could possibly get your submission rejected from the App Store. None of them involve private method calls, though you could argue that observing an undocumented notification name counts as private API. In the end, Apple's opinion is the only one that will matter.
Personally, I'd try it, making sure the code fails gracefully if and when the system changes.
Use an audio session?
I've got an iPhone app that I'm working on that uses Push Notifications.
In the payload I'm specifying a few things:
message body
sound
action-loc-key because I don't want the user to be able to launch the app from the notification
The notification is getting to my iPhone just fine. It shows a message without buttons. So body and action-loc-key are working just fine. But, it's not playing any sound.
However, there are a couple of things I've noticed during troubleshooting:
if I implement application:didReceiveRemoteNotification, everything looks fine. The Dictionary argument contains a key for sound, whose value is indeed the name of the file I want to play.
The sound file itself "works" because if I play it inside of the app (using the SoundEffect class from the BubbleLevel sample) it works just fine.
Despite these two facts, the sound effect simply isn't playing.
In the settings app, everything looks right - Push is turned on for my app, and I have both "sounds" and "alerts" set to on as well.
The iPhone documentation center suggests using Quicktime to look at the format of the file. This is what it looks like.
Finally, if I look at the info for this file in XCode, it says the file type is simply the default, "file." From what I could tell there is no audio-caf option in the list. I tried audio-WAV (the sound engineer told me the original files were WAVs) but that didn't change anything.
In addition, the code:
- (void)applicationDidFinishLaunching:(UIApplication *)application {
// view controller set up stuff
// ...
[[UIApplication sharedApplication] registerForRemoteNotificationTypes:(UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeSound)];
}
I should have posted the JSON as well, it turns out I was constructing it wrong. The reason it worked in didReceieveRemote notification is b/c I was parsing the JSON myself and the fact that I had stuff out of order didn't matter.