【问题标题】:Detecting UIWebView finish to play youtube video on iPad检测 UIWebView 完成以在 iPad 上播放 youtube 视频
【发布时间】:2012-03-16 14:42:14
【问题描述】:

我正在使用UIWebView 在 iPad 上播放 YouTube 视频。

如何检测 YouTube 视频何时播放完毕? 我在状态栏中看到播放图标,我尝试使用MPMusicPlayerController 通知来检测playbackStateDidChange,但没有成功。

任何想法如何检测此事件?再说一次,我说的是 iPad 而不是 iPhone。

提前致谢。

更新:

如果您使用零解决方案来检测播放结束并且还希望 Youtube 视频自动开始,请将 UIWebView 设置为:

self.webView.mediaPlaybackRequiresUserAction = NO ;

我只是想澄清一下 YouTube 框架 API:

“重要提示:这是一个实验性功能,这意味着它可能 意外改变”(08/05/2012)

【问题讨论】:

    标签: objective-c ipad youtube uiwebview


    【解决方案1】:

    不,无法直接从UIWebView 获取网页事件。但是我们可以通过使用 Javascript 来实现。

    • 首先您使用在您的自定义 HTML 中嵌入 Javascript 来检测视频结束播放事件。
    • 然后您尝试使用 JavaScript 加载方案自定义请求,UIWebView 可以捕获该请求。

    这些链接可能会有所帮助:

    1. Calling Objective-C from JavaScript in an iPhone UIWebView

    2. Javascript callback in Objective-C

    3. YouTube iFrame API

    更新了一个例子:

    在 UIWebView 的委托中,我输入:

    #pragma - mark WebView Delegate
    - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
    
    
    if ( [[[request URL] scheme] isEqualToString:@"callback"] ) {
    
        NSLog(@"get callback");
    
        return NO;
    }
    
    return YES;
    

    }

    网页在viewDidLoad时加载:

    [self.webView loadRequest:[NSURLRequest requestWithURL:[NSURL fileURLWithPath:[[NSBundle       mainBundle] pathForResource:@"youtube" ofType:@"html" ]]]];
    

    在 youtube.html 中我输入:

    <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 = "http://www.youtube.com/player_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 onYouTubePlayerAPIReady() {
        player = new YT.Player('player', {
          height: '390',
          width: '640',
          videoId: 'u1zgFlCw8Aw',
          events: {
            'onReady': onPlayerReady,
            'onStateChange': onPlayerStateChange
          }
        });
      }
    
      // 4. The API will call this function when the video player is ready.
      function onPlayerReady(event) {
        event.target.playVideo();
      }
    
      // 5. The API calls this function when the player's state changes.
      //    The function indicates that when playing a video (state=1),
      //    the player should play for six seconds and then stop.
      var done = false;
      function onPlayerStateChange(event) {
    
        if (event.data == YT.PlayerState.PLAYING && !done) {
          setTimeout(stopVideo, 6000);
          done = true;
        }
        if (event.data == YT.PlayerState.ENDED) {
          window.location = "callback:anything"; //here's the key
        };
      }
      function stopVideo() {
        player.stopVideo();
      }
    </script>
    </body>
    </html>
    

    你可以看到我添加

    if (event.data == YT.PlayerState.ENDED) {
          window.location = "callback:anything";
        };
    

    到 YouTube 的 iFrame API 演示,它捕获播放器结束播放事件并尝试使用方案“回调”加载请求,然后 UIWebView 委托可以捕获它。

    您可以使用此方法通过 JavaScript 触发任何事件;

    【讨论】:

    • 但这取决于 youtube 播放器是否支持此类事件,不是吗?你成功了吗?
    • @user1105951 是的,youtube 播放器支持名为“onStateChange”的结束事件,您应按照 YouTube JavaScript API YouTube JavaScript API - Events 为其添加监听器
    • @Zero,我检查了你的链接,我记得我已经测试过了。尝试运行此演示 developers.google.com/youtube/youtube_player_demo -ON THE IPAD- safari 网络浏览器,您将看到:“您需要 Flash 播放器 9+ 和启用 javascript 才能观看此视频”。
    • @user1105951 iOS 设备上的 safari 不支持 flash,因此您需要按照 YouTube 的 iFrame API 来加载 HTML5 播放器。很抱歉误导,所以我更新了我的答案,给出了一个我编写和测试的简单示例。它运作良好。希望它会有所帮助。
    • @Zero,就像一个魅力!我还学习了酷乐队:D(金属规则)youtube.com/watch?v=zi5AE9LKX04谢谢!
    【解决方案2】:

    这里是 @zero 的绝妙答案,作为一个成熟的课程供您使用:

    @interface YouTubeWebView () <UIWebViewDelegate>
    
    @end
    
    
    @implementation YouTubeWebView 
    
    - (id)initWithFrame:(CGRect)frame
    {
        self = [super initWithFrame:frame];
        if (self == nil) return nil;
    
        self.mediaPlaybackRequiresUserAction = NO;
        self.delegate = self;
        self.alpha = 0;
    
        return self;
    }
    
    - (void)loadVideo:(NSString *)videoId
    {
        NSString *filePath = [[NSBundle mainBundle] pathForResource:@"youtube" ofType:@"html"];
        //    if (filePath == nil)
    
        NSError *error;
        NSString *string = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:&error];
        // TODO: error check
    
        string = [NSString stringWithFormat:string, videoId];
    
        NSData *htmlData = [string dataUsingEncoding:NSUTF8StringEncoding];
        //    if (htmlData == nil)
    
        NSString *documentsDirectoryPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0];
        NSString *targetPath = [documentsDirectoryPath stringByAppendingPathComponent:@"youtube.html"];
        [htmlData writeToFile:targetPath atomically:YES];
    
        [self loadRequest:[NSURLRequest requestWithURL:[NSURL fileURLWithPath:targetPath]]];
    }
    
    - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
    {
        if ([[[request URL] scheme] isEqualToString:@"callback"]) {
            [self removeFromSuperview];
    
            NSString *documentsDirectoryPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0];
            NSString *targetPath = [documentsDirectoryPath stringByAppendingPathComponent:@"youtube.html"];
            NSError *error;
            [[NSFileManager defaultManager] removeItemAtPath:targetPath error:&error];
    //        TODO: error check
        }
    
        return YES;
    }
    

    只需使用这个版本的 youtube.html,它有一个替换代码 (%@) 代替视频 ID:

    <html>
    <head><style>body{margin:0px 0px 0px 44px;}</style></head>
    <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 = "http://www.youtube.com/player_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 onYouTubePlayerAPIReady() {
        player = new YT.Player('player', {
          height: '320',
          width: '480',
          videoId: '%@',
          events: {
            'onReady': onPlayerReady,
            'onStateChange': onPlayerStateChange
          }
        });
      }
    
      // 4. The API will call this function when the video player is ready.
      function onPlayerReady(event) {
        event.target.playVideo();
      }
    
      // 5. The API calls this function when the player's state changes.
      //    The function indicates that when playing a video (state=1),
      //    the player should play for six seconds and then stop.
      var done = false;
      function onPlayerStateChange(event) {
        if (event.data == YT.PlayerState.PLAYING && !done) {
          setTimeout(stopVideo, 6000);
          done = true;
        }
        if (event.data == YT.PlayerState.ENDED) {
          window.location = "callback:anything"; 
        };
      }
      function stopVideo() {
        player.stopVideo();
      }
    </script>
    </body>
    </html>
    

    实现这一点我必须克服的唯一主要障碍是将文件作为字符串加载以进行替换。不幸的是,它必须再次写入文件才能自动播放。如果您的用例不需要这样做,请随意将 HTML 作为字符串直接加载到 Web 视图中。

    【讨论】:

    • 为什么不将视频 ID 作为参数传递给 javascript 函数并调用该函数来加载视频?
    【解决方案3】:

    请参考:

    https://developer.apple.com/library/ios/#documentation/AVFoundation/Reference/AVPlayerItem_Class/Reference/Reference.html

    iOS 4.0 有一个可用的通知,您可以使用它来检测 youtube 视频播放完毕

     [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(youTubePlayed:) name:AVPlayerItemDidPlayToEndTimeNotification object:nil];
    

    【讨论】:

    • 视频播放完毕最好重新加载youtube页面,否则会显示youtube提供的相关视频
    • 不要浪费时间尝试其他解决方案。这个就像魅力一样,它只是一行代码。无论如何,这是被调用的观察者,仅供参考 - (void)youTubePlayed:(id)sender
    • 这仅在用户将视频播放到最后然后按下完成按钮时才有效。如果他们还没有完成视频播放到最后,则不会调用此通知。
    • 帮助很大!!! UIWebView 甚至没有为嵌入的视频提供重播按钮。通过在 youTubePlayed:(id) 中重新加载视频,可以避免最后出现“相关视频”的唯一(简单)解决方案;
    【解决方案4】:

    这是一个 Swift 3 答案

       NotificationCenter.default.addObserver(
        self,
        selector: #selector(self.videoEnded),
        name: .AVPlayerItemDidPlayToEndTime,
        object: nil)
    
    
    }
    
    func videoEnded(){
        print("video ended")
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-07-04
      • 2011-05-05
      • 1970-01-01
      • 2012-01-15
      • 1970-01-01
      • 2014-10-11
      • 1970-01-01
      • 2022-01-27
      相关资源
      最近更新 更多