如何从UIWebView嵌入式YouTube视频播放中接收NSNotifications

Vol*_*da2 51 youtube mpmovieplayercontroller mpmovieplayer nsnotificationcenter ios

我没有收到任何通知MPMoviePlayerController.我究竟做错了什么?

我使用以下逻辑.

我开始播放youtube视频了UIWebView.UIWebView称之为标准MPMoviePlayerController.我不控制MPMoviePlayerController因为我没有实例化MPMoviePlayerController.

我使用自动播放运行youtube的剪辑(延迟1秒):

[self performSelector:@selector(touchInView:) withObject:b afterDelay:1];
Run Code Online (Sandbox Code Playgroud)

我的代码是:

- (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];
}
Run Code Online (Sandbox Code Playgroud)

更新:我正在创建播放youtube视频的应用程序.您可以运行播放列表,您将看到第一个视频.当第一个视频结束时,第二个视频会自动开始播放,依此类推.

我需要支持ios 4.1及以上版本.

UPDATE2: @ H2CO3我正在尝试使用你的url-scheme,但它不起作用.委托方法没有调用退出事件.我添加了我的html url来登录.它是:

<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
}
Run Code Online (Sandbox Code Playgroud)

UPDATE3 @Till,我无法抓住UIMoviePlayerControllerDidExitFullscreenNotification,但我找到了MPAVControllerItemPlaybackDidEndNotification.播放视频结束时会出现MPAVControllerItemPlaybackDidEndNotification.

但是我不明白如何捕获完成通知?

Til*_*ill 64

UIWebView嵌入式电影播放器没有发送任何文档通知.

实际上,在许多方面(例如DRM)UIWebView,公开使用的封闭实现确实与公众不同MPMoviePlayerController.

用于播放视频内容的最重要的类UIWebView称为MPAVControllerUIMoviePlayerController.后者使播放器看起来像MPMoviePlayerController全屏界面.

如果您敢于冒被Apple拒绝的风险,实际上还有一些方法可以实现您的目标.

注意 这没有记录,并且每个新的iOS版本都会中断.但它确实可以在iOS4.3,5.0和5.01,5.1和6.0上运行,它也可以在其他版本上运行.

我无法在iOS 4.1和4.2上测试此解决方案,因此您可以自行决定.我非常怀疑它会起作用.


全屏状态

例如,如果您打算对用户点击DONE按钮作出反应,您可以这样做:

更新 建议使用此答案的旧版本, UIMoviePlayerControllerDidExitFullscreenNotification 而此新版本(针对iOS6更新)建议使用 UIMoviePlayerControllerWillExitFullscreenNotification.

C语言水平:

void PlayerWillExitFullscreen (CFNotificationCenterRef center,
                 void *observer,
                 CFStringRef name,
                 const void *object,
                 CFDictionaryRef userInfo)
{
    //do something...
}

CFNotificationCenterAddObserver(CFNotificationCenterGetLocalCenter(), 
    NULL, 
    PlayerWillExitFullscreen, 
    CFSTR("UIMoviePlayerControllerWillExitFullscreenNotification"), 
    NULL,  
    CFNotificationSuspensionBehaviorDeliverImmediately);
Run Code Online (Sandbox Code Playgroud)

Objective-C级别:

- (void)playerWillExitFullscreen:(NSNotification *)notification
{
    //do something...
}

[[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(playerWillExitFullscreen:)
                                             name:@"UIMoviePlayerControllerWillExitFullscreenNotification" 
                                           object:nil];
Run Code Online (Sandbox Code Playgroud)

我确实选择了C级和Objective-C级选项,因为实际发现所有这些的最佳方法是使用C级(CoreFoundation)函数,如我的答案结尾所示.如果一个通知的发件人不使用的Objective-C(NSNotifications),你可能实际上没有使用NSNotification力学能够捕获它们.


播放状态

要检查播放状态,请注意"MPAVControllerPlaybackStateChangedNotification"(如上所述)并检查userInfo可能如下所示:

{
    MPAVControllerNewStateParameter = 1;
    MPAVControllerOldStateParameter = 2;
}
Run Code Online (Sandbox Code Playgroud)

进一步的逆向工程

对于逆向工程和浏览所有已发送的通知,请使用以下代码段.

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);
Run Code Online (Sandbox Code Playgroud)

  • 标准通知语法对我也有用:[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(movieStartedPlaying :) name:@"UIMoviePlayerControllerDidEnterFullscreenNotification"object:nil]; 同样在4.0之前的iOS上,电影在其自己的模态控制器中打开,并不会触发这些事件.在正面上,将在底层控制器上调用onViewDidAppear. (3认同)

Chr*_*sJP 32

在iOS 4.3+中,您可以使用UIMoviePlayerControllerDidEnterFullscreenNotificationUIMoviePlayerControllerDidExitFullscreenNotification通知:

-(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
}
Run Code Online (Sandbox Code Playgroud)


小智 16

据我所知,在制作Cocoa Touch应用程序时,不依赖于UIWebView(以及Apple制作的所有系统类)的实现细节.也许是这样的情况,UIWebView的视频播放器不是标准的MPMoviePlayerController类,它可能有一个完全不同的委托/通知系统,用户不应该访问它.

我建议你使用HTML5元素并检测这个标签的"onended"事件:

<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>
Run Code Online (Sandbox Code Playgroud)

事实上,从endMovie JavaScript函数,你可以重定向到一个假的网址,你可以在你的-webView赶上:shouldStartLoadWithRequest:(UIWebViewDelegate)方法从而得到通知,该视频已结束:

- (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
}
Run Code Online (Sandbox Code Playgroud)

希望这可以帮助.

  • 您好,这个想法相当精彩我必须说..但是... Youtube视频不是通过使用您的代码嵌入(不是任何),它们最终都是通过播放按钮带条纹的视频元素.所以你不能点击它. - 有人找到了解决方案吗? (2认同)

Fáb*_*ira 6

基于@ H2CO3答案但使用iframe API.这是我能让它发挥作用的唯一方法.

这不使用任何私有API,这使它更具有未来性.

这是嵌入Youtube视频的代码.检查API以了解更多自定义方法.

<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>
Run Code Online (Sandbox Code Playgroud)

这就是您收到视频结束通知的方式(UIWebViewDelegate方法).

- (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
 }
Run Code Online (Sandbox Code Playgroud)


Pra*_*jan 5

在ViewDidLoad中添加以下代码

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(VideoExitFullScreen:) name:@"UIMoviePlayerControllerDidExitFullscreenNotification" object:nil];

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(VideoEnterFullScreen:) name:@"UIMoviePlayerControllerDidEnterFullscreenNotification" object:nil];
Run Code Online (Sandbox Code Playgroud)

以下方法用于显示进入/退出全屏的各个进程的消息/功能

- (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
}
Run Code Online (Sandbox Code Playgroud)