2012-02-27 120 views
10

我使用UIWebView在iPad中播放YouTube视频。检测UIWebView完成在iPad上播放YouTube视频

如何检测YouTube视频播放完毕? 我在状态栏中看到播放图标,我试图使用MPMusicPlayerController通知来检测playbackStateDidChange,但它不起作用。

任何想法如何检测此事件?再次,我谈论的不是iPhone。

在此先感谢。

更新:

如果使用零解决方案来检测的演奏结束,也希望Youtube视频开始自动设置UIWebView到:

self.webView.mediaPlaybackRequiresUserAction = NO ; 

我只是想澄清有关YouTube框架API:

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

回答

15

没有,有没有办法从UIWebView直接获取网页的事件。但是我们可以通过使用Javascript来完成。

  • 首先使用嵌入的JavaScript在您的自定义HTML,检测视频结束播放事件。
  • 然后,您尝试使用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的任何事件;

+0

但它取决于如果YouTube播放器支持这样的事件,不是吗? 你成功了吗? – user1105951 2012-05-07 12:53:22

+0

@ user1105951是,YouTube播放器支持结束事件称为“onStateChange”,你要添加一个侦听它符合YouTube的JavaScript API [YouTube上的JavaScript API - 活动(https://developers.google.com/youtube/js_api_reference#Events ) – ZeR0 2012-05-07 15:46:32

+0

@Zero,我检查你的链接,我记得alreay测试它。 尝试运行这个演示https://developers.google.com/youtube/youtube_player_demo-ON THE IPAD- Safari网络浏览器,你会看到:“您需要Flash Player 9+并启用javascript才能观看此视频”。 – user1105951 2012-05-07 19:43:25

3

这里是@零的梦幻般的答案供你使用一个完整的类:

@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视图来代替。

+0

你为什么不传视频ID作为参数传递给javascript函数,并调用该函数加载视频? – 2015-07-21 13:27:11

11

请参考,以:

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]; 
+0

它的好来重新加载页面的YouTube视频时结束,否则,它会显示由YouTube提供 – chings228 2013-05-10 02:43:16

+3

不要浪费时间去尝试其他的解决方案相关的视频。这个作品像魅力一样,只是一行代码。无论如何,这是被称为,仅供参考观察者 - (空)youTubePlayed:(ID)发送 – 2013-09-06 10:23:33

+0

作品中的iOS 8 .. – 2014-11-07 10:38:18

0

这里的斯威夫特3回答

的通知
NotificationCenter.default.addObserver(
    self, 
    selector: #selector(self.videoEnded), 
    name: .AVPlayerItemDidPlayToEndTime, 
    object: nil) 


} 

func videoEnded(){ 
    print("video ended") 
}