How to prevent UIWebView video from getting remote control events - ios

I am using UIWebView in an iOS app to play YouTube videos but to provide native experience, I've implemented playback controls using UIKit. So the UIWebView is only used to display video.
I've also implemented -remoteControlReceivedWithEvent: to allow control from Control Center and controller buttons on earphones. But it seems that UIWebView automatically handles remote control events from the earphones. This is a problem because when you toggle play/pause, my code would pause the video and then UIWebView will toggle it again to play the video.
Is there anyway to prevent this from happening?
Related issue is that UIWebView tries to set "Now Playing" information to MPNowPlayingInfoCenter which is also done by my code.

I encountered same kind of issue with my app which playbacks audio using AVAudioPlayer.
This app displays current audio info in MPNowPlayingInfoCenter during playback.
My requirement was to display an html5 video advert (with audio) inside a webview on top my player.
First i used only UIWebView as i needed to support iOS7 but i met a lot of issues, one of them was MPNowPlayingInfoCenter that displays url of ad video in place of current native audio playback.
I tried several solutions such as method swizzling on UIWebView without any success.
I found only one solution that works for me: use WKWebView by default instead of UIWebView web container. HTML5 video playback will not interact anymore with MPNowPlayingInfoCenter, i had to support also iOS7 so i created a wrapper class to switch between UIWebView (with still the issue) on iOS7 and WKWebView from iOS8 and more.
Hope this helps.

I ran into this question while trying to solve somewhat the reverse problem: I added a UIWebView to an app and remote control events were not working when the UIWeb view was on display, but worked elsewhere in the app.
In my case the solution was to add these 3 methods, which are present on all other view controllers in my app, to the controller of my new UIWebView:
- (void) viewDidAppear:(BOOL)animated {
[self becomeFirstResponder];
}
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
[self resignFirstResponder];
}
-(void)remoteControlReceivedWithEvent:(UIEvent *)event {
// Logic to handle remote control events
}
From this, I suspect that you can prevent your UIWebView from handling remote control events by doing one of two things:
1. Include logic in the remoteControlReceivedWithEvent to ignore the remote control events you don't want handled.
2. Have your UIWebView resign being the first responder by calling resignFirstResponder in the viewDidAppear method of the controller.

Related

iOS Media Player remote control events (MPRemoteCommand) are not working with Unity

Recently I've found out that MediaPlayer remote control event (MPRemoteCommand) handlers are not getting called in iOS application with embedded Unity player. I'm using Xcode 6.3.1 and Unity 5.0.1f1, however, it looks like it can be reproduced with any combination of currently available versions.
This is the official Apple documentation for handling remote control events on iOS: https://developer.apple.com/library/ios/documentation/EventHandling/Conceptual/EventHandlingiPhoneOS/Remote-ControlEvents/Remote-ControlEvents.html
The issue is very easy to reproduce - it's just 24 lines of code added to an empty project.
Create new Single View Application in Xcode (to make working example without Unity player) or create an empty project in Unity and immediately build it targeting iOS platform (File -> Build Settings..., iOS, Build) with all the settings left with their default values to get Xcode project generated by Unity (to make broken example with embedded Unity player).
Import MediaPlayer framework header file in AppDelegate.h (for example without Unity) or UnityAppController.h (for example with Unity):
#import <MediaPlayer/MediaPlayer.h>
Declare a property for MPMoviePlayerController object in the class interface located in AppDelegate.h/UnityAppController.h:
#property (strong, nonatomic) MPMoviePlayerController *player;
Insert this code which creates a player with URL (it's a live radio station, you can use any other HTTP live audio source that you'd like to), registers handlers for play, pause and togglePlayPause remote control events and starts playing the audio (thus making application the "Now Playing" app) in the beginning of application:didFinishLaunchingWithOptions: method located in AppDelegate.m/UnityAppController.mm (you can also add it just before return statement of that method - it doesn't matter):
self.player = [[MPMoviePlayerController alloc] initWithContentURL:[NSURL URLWithString:#"http://81.9.96.34/eldoradio-64k"]];
[[MPRemoteCommandCenter sharedCommandCenter].playCommand addTarget:self action:#selector(playCommand)];
[[MPRemoteCommandCenter sharedCommandCenter].pauseCommand addTarget:self action:#selector(pauseCommand)];
[[MPRemoteCommandCenter sharedCommandCenter].togglePlayPauseCommand addTarget:self action:#selector(togglePlayPauseCommand)];
[self.player play];
Add implementation of handlers to AppDelegate.m/UnityAppController.mm:
- (void)playCommand {
[self.player play];
}
- (void)pauseCommand {
[self.player pause];
}
- (void)togglePlayPauseCommand {
if (self.player.playbackState == MPMoviePlaybackStatePlaying) {
[self.player pause];
} else {
[self.player play];
}
}
Build and run the application. You should hear music playing once it is started.
Trigger some remote control events. The easiest way is to plug-in standard Apple EarPods and press play-pause button on them which should generate togglePlayPause event, but opening iOS Control Center (the UI you get by swiping the screen from the bottom) and pressing Play/Pause button from there is also okay (they should generate separate play and pause events respectively).
In the application without Unity audio stops and starts playing according to remote control events being sent.
In the application with Unity handlers are never getting called (you can set breakpoints in them and see that under debugger) and nothing happens at all. You can also notice that the appearance of iOS Control Center is completely different: in the application with embedded Unity player it has play and two rewind buttons regardless of audio state, but in the application without Unity it shows just pause button when audio is playing or just play button when it is not playing.
You can also replace MPMoviePlayerController with AVPlayer from AVFoundation framework - the result will be exactly the same.
Does anybody know any reason for this behavior and/or any workaround for it? This affects our application very badly.
P.S.: I've already asked similar question before, but didn't get any answers. The example in this one is as simple as possible.
My app has pretty much the same setup as yours - and the same problem. As long as I used a mixable audio session
try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayAndRecord, withOptions: [.DuckOthers, .InterruptSpokenAudioAndMixWithOthers])
my app wouldn't trigger any of the MPRemoteCommand handlers.
When I turned my audio session into a non-mixable one (by removing the options)
try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayAndRecord)
my MPRemoteCommand handlers would get called whenever I pressed the play/pause button on my headset.
So, the solution is to use a non-mixable audio session, which PlayAndRecord is without the explicit mixing options, instead of a mixable audio session.

youtube in background mode in ios

I'm using https://github.com/youtube/youtube-ios-player-helper for implement Youtube videos in my iOS Project.
I implement the YTPlayerView object in Appdelegate; in my ViewController I execute the view. Really YTPlayerView, is a UIView that show an UIWebview.
The proble occure when I want to listen the webview (Youtube Music) in background.
- (void)applicationDidEnterBackground:(UIApplication *)application{
[self.playerView playVideo];
}
I implement this in Appdelegate but the first time I dismiss the app, the music is set in background, but the second time no and I don't know why.
I have seen so many apps at app store that u can make this, so is possible but I don't have seen anything about it.
Thanks

embedded youtube videos not playing in WKWebView while exact same videos work in UIWebView

When I load a web page into a UIWebView (even a www.youtube.com page) that contains an embedded youtube video, it plays just fine for IOS7 or IOS8. But when I switch to WKWebView (IOS8) and load the same web page, the youtube video doesn't play at all on the first click, then plays for a second or two on subsequent play clicks (on the youtube player). Like it is running out of buffer space and pausing until I hit play again only to play for another second.
From Safari this (or any other) youtube video plays from start to finish on the same LAN. Likewise, as I mentioned earlier, UIWebView has no problem inside of IOS7 or IOS8. So it is not a problem with my wireless data thru put or connection.
Is there something I need to do to keep the player going? Maybe increase the streaming video buffer space for WKWebViews?
OK I figured out why this is happening and also why no one else was affected by it. WKWebView and indeed IOS 8 handles several things that are not deprecated yet act differently in IOS 8. And this is one.
My app samples audio from the microphone in real time. This was fine in prior versions of IOS, but apparently in IOS 8 when a WKWebView starts a video stream, the audio sample can kill it (god only knows precisely why).
However, I need to be able to sample audio with WKWebView but I don't necessarily need to do it when a video is playing. So the challenge will be to figure out when the user has clicked on a youtube or vimeo or apparently any other streaming video and pause my audio sampler while the video is streaming. At the moment I don't know how to do that.
I also discovered another difference between IOS8 and prior when using UIView animations. prior to IOS 8 you could animate a swap between images in the UIWebView and the animation was persistent only as long as you set the duration AND you didn't have to enable animations.
[UIView beginAnimations:#"fade1" context:nil];
[UIView setAnimationDuration:1.0];
[UIView setAnimationsEnabled:YES];
[UIView commitAnimations];
Now in IOS8, apparently you have to set a listener and disable animations after it finishes, otherwise your UIView animation is applied to all sorts of unexpected, and even native, behaviors. Like finger scrolling a native list or when the user vertically scrolls a web page in the UIWebView. Disable the animations and these strange affects on other objects disappear.
[UIView setAnimationsEnabled:NO];
And now I am totally confused about what the commit does. It doesn't seem to be needed in IOS 8 anymore.
To know when the video is playing, you can try this solution from Paulo Fierro.

iOS 7 Dev - Minimizing app causes UIWebView inline YouTube Player to stop playing

I'm working on a project that plays YouTube videos, inline in a UIWebView. What I'm trying to do is to continue playing the app's audio, even when the home button is pressed (or focus is off the app in any way). I've done the following (as suggested from searching my question here):
Made sure Audio and Fetch were included in my info.plist for Background Modes
Made sure my ViewController that contained the WebView is registered to receive remote control events:
[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
[self becomeFirstResponder];
Messed with the AVAudioSession (sharedSession) and set the category to playback.
None of these things worked. Either I'm doing one of them incorrectly (which I doubt--I've found several "solutions" here that have worked for other people but not for my particular case).
I have a feeling this might have something to do with the way the WebView plays audio. Any ideas?
You need to add BackgroundMode: "Audio And AirPlay".
It's the following key in your plist:
`<key>UIBackgroundModes</key>
<array>
<string>audio</string>`

iOS embed video, video still plays when in another view

So lets say I have a UIWebView on my view, embed with a YouTube video. The view is connected to a navigation view controller. This means that when i click a button it pushes a view on to the stack. But when I play the youtube video and go to the next view. The video is still playing. Is there anyway to handle stopping an embed youtube video when going to another view?
What if I have multiple cells with a UIWebView embed with a YouTube video in a UICollectionView? I don't have reference to all the UIWebViews to set to nil. (Sorry for the confusion previously above)
What I do is just set the UIWebView's content to nil when I'm moving to another page, which removes the video player completely, but if you just want to pause the video so the user can resume when they come back, you'll have to talk to the youtube player using javascript. See How to Pause Media Playback in UIWebView for one approach.
If you use Youtube Javascript api to play the video - you can pause it when leaving current view with
-(void)viewWillDisapper:(BOOL)animated
{
[super viewWillDisappear:animated];
[webView stringByEvaluatingJavaScriptFromString: #"player.pauseVideo();"];
}
You need to load a blank page into the UIWebView to stop the video playing. Here's a quick way to do it:
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated]
[yourWebView loadHTMLString:nil baseURL:nil];
}

Resources