Обнаружение окончания UIWebView для воспроизведения видео YouTube на iPad - PullRequest
10 голосов
/ 27 февраля 2012

Я использую UIWebView для воспроизведения видео с YouTube на iPad.

Как определить, когда видео на YouTube закончено?Я вижу значок воспроизведения в строке состояния и пытался использовать MPMusicPlayerController уведомления для обнаружения playbackStateDidChange, но это не сработало.

Есть идеи, как обнаружить это событие?Опять же, я говорю об iPad, а не iPhone.

Заранее спасибо.

Обновление:

Если вы используете нулевое решение для определения концавоспроизведения, а также для автоматического запуска видео на Youtube установите UIWebView на:

self.webView.mediaPlaybackRequiresUserAction = NO ;

Я просто хочу уточнить об API фрейма YouTube:

"Важно:Это экспериментальная функция, которая означает, что она может неожиданно измениться "(08/05/2012)

Ответы [ 4 ]

15 голосов
/ 07 мая 2012

Нет, нет способа напрямую получить событие веб-страницы от UIWebView.Но мы можем сделать это, используя Javascript.

  • Сначала вы используете Javascript для встраивания в свой пользовательский HTML, чтобы обнаружить событие воспроизведения видео, заканчивающееся.
  • Затем вы пытаетесь загрузить настроенную схемузапрос с использованием JavaScript, и UIWebView может перехватить запрос.

Эти ссылки могут помочь:

  1. Вызов Objective-C из JavaScript в iPhone UIWebView

  2. Обратный вызов Javascript в 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;

11 голосов
/ 24 апреля 2013

Пожалуйста, обратитесь к:

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];
3 голосов
/ 05 февраля 2013

Вот фантастический ответ @ 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, у которой вместо идентификатора видео есть код подстановки (%@):

<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-код в веб-представление непосредственно в виде строки.

0 голосов
/ 20 апреля 2017

Вот ответ Swift 3

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


}

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