Воспроизведение видео с YouTube не работает на iOS6 (отлично работает на iOS5)

В моем приложении есть кнопка, при нажатии которой можно посмотреть видео на YouTube (трейлер к фильму). В приложении, без запуска сафари. Ниже вы можете увидеть фрагмент кода. Этот код отлично работает под iOS5. Однако в iOS 6 UIButton в findButtonInView всегда равен нулю. Есть идеи, в чем может быть причина?

youtubeWebView.delegate = self;
youtubeWebView.backgroundColor = [UIColor clearColor];

NSString* embedHTML = @" <html><head> <style type=\"text/css\"> body {background-color: transparent;  color: white; }</style></head><body style=\"margin:0\"><embed id=\"yt\" src=\"%@?version=3&app=youtube_gdata\" type=\"application/x-shockwave-flash\"width=\"%0.0f\" height=\"%0.0f\"></embed></body></html>";

NSURL *movieTrailer;

if(tmdbMovie) movieTrailer = tmdbMovie.trailer;

else movieTrailer = [NSURL URLWithString:movie.trailerURLString];

NSString *html = [NSString stringWithFormat:embedHTML,
                                            movieTrailer,
                                            youtubeWebView.frame.size.width,
                                            youtubeWebView.frame.size.height];

[youtubeWebView loadHTMLString:html baseURL:nil];

[self addSubview:youtubeWebView];


- (void)webViewDidFinishLoad:(UIWebView *)_webView {

    isWatchTrailerBusy = NO;

    [manager displayNetworkActivityIndicator:NO];

    //stop the activity indicator and enable the button

     UIButton *b = [self findButtonInView:_webView];

    //TODO this returns null in case of iOS 6, redirect to the youtube app

    if(b == nil) {

        NSURL *movieTrailer;

        if(tmdbMovie) {
            movieTrailer = tmdbMovie.trailer;
        } else {
            movieTrailer = [NSURL URLWithString:movie.trailerURLString];
        }

        [[UIApplication sharedApplication] openURL:movieTrailer];

    } else {
        [b sendActionsForControlEvents:UIControlEventTouchUpInside];
    }
}


- (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;
}

person Asem H.    schedule 17.09.2012    source источник
comment
Я использую новые API-интерфейсы HTML iFrame (что, кстати, рекомендуется) для встраивания видео на YouTube, и этот метод автоматического воспроизведения findButtonInView никогда не работал для меня (возвращает ноль).   -  person msk    schedule 17.09.2012
comment
@MSK у вас есть ссылка на учебник или фрагмент кода по использованию вместо этого iframe? Спасибо   -  person Asem H.    schedule 17.09.2012
comment
См. мой вопрос и ответ здесь   -  person msk    schedule 17.09.2012
comment
Спасибо. так это означает, что невозможно нажать кнопку для просмотра видео на YouTube внутри приложения?   -  person Asem H.    schedule 17.09.2012
comment
У меня это никогда не работало, и более того, это своего рода хак, который не дает гарантии, что он сработает при следующем обновлении ОС.   -  person msk    schedule 17.09.2012


Ответы (8)


Apple изменила способ обработки видео YouTube в iOS6. Я также использовал метод findButtonInView, но он больше не работает.

Я обнаружил, что работает следующее (не проверено в iOS ‹ 6):

- (void)viewDidLoad 
{
    [super viewDidLoad];
    self.webView.mediaPlaybackRequiresUserAction = NO;
}

- (void)playVideo
{
    self.autoPlay = YES;
    // Replace @"y8Kyi0WNg40" with your YouTube video id
    [self.webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:[NSString stringWithFormat:@"%@%@", @"http://www.youtube.com/embed/", @"y8Kyi0WNg40"]]]];
}

// UIWebView delegate
- (void)webViewDidFinishLoad:(UIWebView *)webView {
    if (self.autoPlay) {
        self.autoPlay = NO;
        [self clickVideo];
    }
}

- (void)clickVideo {
    [self.webView stringByEvaluatingJavaScriptFromString:@"\
        function pollToPlay() {\
            var vph5 = document.getElementById(\"video-player\");\
            if (vph5) {\
                vph5.playVideo();\
            } else {\
                setTimeout(pollToPlay, 100);\
            }\
        }\
        pollToPlay();\
     "];
}
person dharmabruce    schedule 20.09.2012
comment
Я изменил код javascript для опроса элемента до тех пор, пока он не будет доступен перед отправкой события щелчка. Это решило проблему, когда я видел это на некоторых устройствах. Пожалуйста, дайте мне знать, если это поможет! - person dharmabruce; 22.09.2012
comment
Ну, хм, у меня это работает на iPhone 4s, iPhone 5 и iPad. Я обновлю, если найду лучший способ. - person dharmabruce; 25.09.2012
comment
Я могу подтвердить, что это работает для меня на iOS6 на моем iPhone4S! Единственное, вам нужно подождать пару секунд, прежде чем он сработает, но он работает! - person Bob de Graaf; 27.09.2012
comment
Я могу подтвердить, что это работает и для меня. Оба, на iPad и iPhone (под управлением iOS6) - person Sid; 02.10.2012
comment
Однако я обнаружил один сбой: когда я нажимаю полноэкранную кнопку на iPad, воспроизведение останавливается, не знаю почему. Другое дело: умеете ли вы передавать параметры встроенному плееру? Мне нужно удалить все украшения, которые есть по умолчанию (наложение заголовков, похожие видео и т. д.). - person Lvsti; 09.01.2013
comment
Когда мы смотрим первое видео, оно работает. когда я нажимаю на второе видео, приведенный выше код у меня не работает. Нужно ли добавлять дополнительные параметры? - person Dee; 07.03.2013
comment
Он отключил опцию автовоспроизведения после просмотра первого видео и больше не включает для следующего видео. Вот вывод моей консоли: Автозапуск: пропуск автозапуска, отключен (для текущего элемента: 1, на плеере: 1) 2013-03-07 18:29:10.484 CCL[3824:907] [MPAVController] Автозапуск: отключение автозапуска на паузу 2013 -03-07 18:29:10.486 CCL[3824:907] [MPAVController] Автозапуск: отключение автозапуска 07.03.2013 18:29:12.411 CCL[3824:907] [MPAVController] Автозапуск: отключение автозапуска на паузу 2013-03 -07 18:29:12.415 CCL[3824:907] [MPAVController] Автозапуск: отключение автозапуска - person Dee; 07.03.2013

Решение dharmabruce отлично работает на iOS 6, но для того, чтобы заставить его работать на iOS 5.1, мне пришлось заменить javascript click() на playVideo(), и мне пришлось установить для mediaPlaybackRequiresUserAction UIWebView значение NO

Вот измененный код:

- (void)viewDidLoad 
{
    [super viewDidLoad];
    self.webView.mediaPlaybackRequiresUserAction = NO;
}

- (void)playVideo
{
    self.autoPlay = YES;
    // Replace @"y8Kyi0WNg40" with your YouTube video id
    [self.webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:[NSString stringWithFormat:@"%@%@", @"http://www.youtube.com/embed/", @"y8Kyi0WNg40"]]]];
}

// UIWebView delegate
- (void)webViewDidFinishLoad:(UIWebView *)webView {
    if (self.autoPlay) {
        self.autoPlay = NO;
        [self clickVideo];
    }
}

- (void)clickVideo {
    [self.webView stringByEvaluatingJavaScriptFromString:@"\
        function pollToPlay() {\
            var vph5 = document.getElementById(\"video-player-html5\");\
            if (vph5) {\
                vph5.playVideo();\
            } else {\
                setTimeout(pollToPlay, 100);\
            }\
        }\
        pollToPlay();\
     "];
}
person JimmY2K.    schedule 05.11.2012
comment
Он работает в первый раз. Если я хочу посмотреть другое видео, приведенный выше код не работает. Почему? - person Dee; 07.03.2013

Я решил проблемы с dharmabruce и JimmY2K. решений, с тем фактом, что он работает только при первом воспроизведении видео, как упомянул Ди

Вот код (включая событие, когда видео заканчивается):

- (void)embedYouTube:(NSString *)urlString frame:(CGRect)frame {
    videoView = [[UIWebView alloc] init];
    videoView.frame = frame;
    videoView.delegate = self;

    [videoView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:urlString]]];// this format: http://www.youtube.com/embed/xxxxxx
    [self.view addSubview:videoView];

    //https://github.com/nst/iOS-Runtime-Headers/blob/master/Frameworks/MediaPlayer.framework/MPAVController.h
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(playbackDidEnd:)
                                                 name:@"MPAVControllerItemPlaybackDidEndNotification"//@"MPAVControllerPlaybackStateChangedNotification"
                                               object:nil];

}


- (void)webViewDidFinishLoad:(UIWebView *)webView {
    //http://stackoverflow.com/a/12504918/860488
    [videoView stringByEvaluatingJavaScriptFromString:@"\
                                    var intervalId = setInterval(function() { \
                                        var vph5 = document.getElementById(\"video-player\");\
                                        if (vph5) {\
                                            vph5.playVideo();\
                                            clearInterval(intervalId);\
                                        } \
                                    }, 100);"];
}

- (void)playbackDidEnd:(NSNotification *)note
{
    [videoView removeFromSuperview];
    videoView.delegate = nil;
    videoView = nil;
}
person Morten Holmgaard    schedule 08.03.2013
comment
Пожалуйста, напишите свой адрес, я хочу отправить вам подарок! - person Lior Frenkel; 24.03.2013
comment
здесь не работает. Возможно, это сработало один раз, но по какой-то причине больше не работает. У меня есть ваш точный код! ios 6.1.x попробовал в iphone и симуляторе одно и то же - person João Nunes; 27.03.2013

Непроверено и не уверен, что это проблема, потому что я не знаю URL-адрес, который вы используете. Но я наткнулся прямо на следующее:

Начиная с iOS 6 встроенные URL-адреса YouTube в форме http://www.youtube.com/watch?v=oHg5SJYRHA0 больше не будут работать. Эти URL-адреса предназначены для просмотра видео на сайте YouTube, а не для встраивания в веб-страницы. Вместо этого формат, который следует использовать, описан здесь: https://developers.google.com/youtube/player_parameters. .

с http://thetecherra.com/2012/09/12/ios-6-gm-released-full-changelog-inside/

person Marvin Emil Brach    schedule 26.09.2012

Я работаю над этой же общей проблемой и поделюсь подходом, который придумал. У меня есть некоторые оставшиеся перегибы, которые нужно отработать для моей конкретной ситуации, но общий подход может работать для вас, в зависимости от ваших требований к пользовательскому интерфейсу.

Если вы структурируете свой код встраивания HTML так, чтобы проигрыватель YouTube покрывал все границы UIWebView, этот UIWebView фактически становится большой кнопкой воспроизведения — прикосновение в любом месте его поверхности приведет к запуску видео в собственном медиаплеере. Чтобы создать кнопку, просто закройте UIWebView UIView, для которого параметр userInteractionEnabled имеет значение NO. Имеет ли значение размер UIWebView в этой ситуации? Не совсем, так как видео все равно откроется в родном плеере.

Если вы хотите, чтобы пользователь воспринимал область вашего пользовательского интерфейса как место, где будет «воспроизведение» видео, вы можете взять миниатюру видео с YouTube и расположить ее где угодно. При необходимости вы можете поместить второй UIWebView за этим представлением, поэтому, если пользователь коснется этого представления, видео также запустится или просто распространит другой UIWebView так, чтобы он находился «позади» обоих этих представлений.

Если вы опубликуете снимок экрана своего пользовательского интерфейса, я могу сделать несколько более конкретных предложений, но основная идея состоит в том, чтобы превратить UIWebView в кнопку, поместив перед ней представление, в котором отключено взаимодействие с пользователем.

person Rob Reuss    schedule 01.10.2012

Я обнаружил, что приведенный ниже код работает как для iOS5, так и для iOS6. В моем примере у меня есть текстовое поле, содержащее URL-адрес видео. Сначала я конвертирую форматы в одну и ту же начальную строку «http://m...». Затем я проверяю, является ли формат старым форматом, с помощью «watch?v=», а затем заменяю его новым форматом. Я тестировал это на iPhone с iOS5 и в симуляторах iOS5 и iOS6:

-(IBAction)loadVideoAction {
    [activityIndicator startAnimating];

    NSString *urlString = textFieldView.text;
    urlString = [urlString stringByReplacingOccurrencesOfString:@"http://www.youtube" withString:@"http://m.youtube"];
    urlString = [urlString stringByReplacingOccurrencesOfString:@"http://m.youtube.com/watch?v=" withString:@""];
    urlString = [NSString stringWithFormat:@"%@%@", @"http://www.youtube.com/embed/", urlString];
    [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:urlString]]];
}

- (void)webViewDidFinishLoad:(UIWebView *)webView
{
    [activityIndicator stopAnimating];
}
person fawsha1    schedule 02.11.2012

Я считаю, что проблема в том, что когда webViewDidFinishLoad был запущен, UIButton еще не был добавлен в представление. Я реализовал небольшую задержку, чтобы найти кнопку после возврата обратного вызова, и у меня это работает на ios5 и ios6. недостатком является то, что нет гарантии, что UIButton будет готов к обнаружению после задержки.

- (void)autoplay {
    UIButton *b = [self findButtonInView:webView];
    [b sendActionsForControlEvents:UIControlEventTouchUpInside]; }

- (void)webViewDidFinishLoad:(UIWebView *)_webView {
    [self performSelector:@selector(autoplay) withObject:nil afterDelay:0.3]; }

Мне пришлось использовать URL http://www.youtube.com/watch?v=videoid это единственный способ, который мне подойдет

person tzl    schedule 20.12.2012

person    schedule
comment
iOS 6.0 использует жест для обнаружения касания пользователя сейчас, после обнаружения касания используйте автоматическое воспроизведение html5. - person Steve; 24.09.2012
comment
Я не знаю, одобрит ли это Apple, сегодня постараюсь представить версию с этим кодом. Буду держать вас в курсе. - person Steve; 24.09.2012
comment
Стив, тебе повезло, мое приложение только что было отклонено с использованием этого кода. В нем говорилось, что я использовал закрытый API под названием _singleTapRecognized: поэтому я могу посоветовать людям не использовать этот код! - person Bob de Graaf; 07.10.2012
comment
Наше приложение тоже было только что отклонено! Это аргументация Apple: мы обнаружили, что ваше приложение использует один или несколько закрытых API, что не соответствует Руководству по проверке App Store. Использование непубличных API-интерфейсов недопустимо, так как это может привести к ухудшению взаимодействия с пользователем, если эти API-интерфейсы изменятся. Мы обнаружили в вашем приложении следующие закрытые API: _singleTapRecognized: - person vinzenzweber; 04.12.2012
comment
Кто-нибудь проверял это на ‹iOS6? - person Ahmed; 19.12.2012