34

I have seen a lot of posts in here about this issue, but still couldn't find a perfect answer for this problem.

So I have a tableview, and each cell has a play button inside it. When the user tap the play button, I add a UIWebView to this cell, and play a YouTube video.

static NSString *youTubeVideoHTML = @"<html>\
    <body style=\"margin:0;\">\
        <iframe class=\"youtube-player\" type=\"text/html\" width=\"%0.0f\" height=\"%0.0f\" src=\"http://www.youtube.com/embed/%@\" frameborder=\"0\">\
        </iframe>\
    </body>\
    </html>";


- (void)playVideoWithId:(NSString *)videoId {
    NSString *html = [NSString stringWithFormat:youTubeVideoHTML, self.frame.size.width, self.frame.size.height, videoId];

    [self loadHTMLString:html baseURL:nil];
}

The problem:

This code doesn't actually play the video like I want, it just initiate the YouTube player and show it with the YouTube red play button. Only when user tap the red button, the video will start playing.
So user has to tap two buttons until the video starts - not the best user experience...

Like I said I saw many posts about this issue, some not work at all, and some works but with some issues that bugs me.

One of the working solutions I found was in this post by @ilias, he shows how to get this working with loading the HTML from a file (instead of a string like I do), problem with this approche is that for every video I play I need to:
load the htm file -> embed the video Id in it -> write the file to disc -> only now I can play the video.

Strange thing is that this solution only work when you load the web view request from a file, if I try to load the request from a string equal to the file content, that doesn't work.

Community
  • 1
  • 1
Eyal
  • 10,777
  • 18
  • 78
  • 130

5 Answers5

49

Apparently the problem was with the nil base url, when I changed it to resourceURL the autoplay worked.

[self loadHTMLString:html baseURL:[[NSBundle mainBundle] resourceURL]];  

The full code for autoplay youtube videos (again this code mostly based on this post I just changed it to load from a string instead of a file):

static NSString *youTubeVideoHTML = @"<!DOCTYPE html><html><head><style>body{margin:0px 0px 0px 0px;}</style></head> <body> <div id=\"player\"></div> <script> var tag = document.createElement('script'); tag.src = \"http://www.youtube.com/player_api\"; var firstScriptTag = document.getElementsByTagName('script')[0]; firstScriptTag.parentNode.insertBefore(tag, firstScriptTag); var player; function onYouTubePlayerAPIReady() { player = new YT.Player('player', { width:'%0.0f', height:'%0.0f', videoId:'%@', events: { 'onReady': onPlayerReady, } }); } function onPlayerReady(event) { event.target.playVideo(); } </script> </body> </html>";  

- (void)playVideoWithId:(NSString *)videoId {
    NSString *html = [NSString stringWithFormat:youTubeVideoHTML, self.frame.size.width, self.frame.size.height, videoId];

    [self loadHTMLString:html baseURL:[[NSBundle mainBundle] resourceURL]];
}
Community
  • 1
  • 1
Eyal
  • 10,777
  • 18
  • 78
  • 130
  • Hi Eyal: I'm having a problem with your solution. Autoplay isn't working (if I remove the call to playVideo(), things work, but without autoplay). It seems my problem is similar to the one found here: https://groups.google.com/forum/?fromgroups#!topic/youtube-api-gdata/vPgKhCu4Vng . Any ideas? I've tried on Simulator and Device. I just get a "video loading" indicator indefinitely. – Tim Arnold May 22 '13 at 20:11
  • 7
    Figured it out! Make sure the `mediaPlaybackRequiresUserAction` property on your `UIWebView` is set to `NO` (default is `YES`)! – Tim Arnold May 22 '13 at 20:26
  • 1
    It is auto-playing nicely, but the video still opening the Youtube video as full screen (vertical) on my iPhone 5, using iOS6..any other ideas? Just to be clear, the small window appears first, then goes full screen once it begins playing. – Fluffhead Aug 01 '13 at 00:24
  • 1
    @Eyal Thanks a lot after searching a lot I got this link and it worked for me. Also appreciate your question style. :) – The iCoder Oct 04 '13 at 06:59
  • Hi Eyal: how could I make the player size auto resize when the orientation is changed? As currently when the page is not playing, and the orientation changed, the view size is not changing. Thank you. – Evelyn Loo Mar 31 '15 at 09:36
  • @Eyal can we make this fullscreen on start – Qadir Hussain Mar 22 '16 at 06:32
  • Autoplay is working for me. Can we make the player full screen and hide the title link of the video? – Qadir Hussain Mar 22 '16 at 06:38
  • I get "This application is modifying the autolayout engine from a background thread, which can lead to engine corruption and weird crashes. This will cause an exception in a future release." warning after the video has started. Any ideas? – sight Sep 08 '16 at 11:29
  • @Eyal Thanks a lot after searching a lot I got this link and it worked for me. Also appreciate your question style. :) – The iCoder Oct 4 '13 at 6:59 how this one is working for you?can you please help me? – Ali Raza Jul 23 '18 at 11:55
14

The key here is to set playsinline=1 in your iFrame player, and allowsInlineMediaPlayback = true and mediaPlaybackRequiresUserAction = false for your UIWebView. Here's my implementation in Swift:

// Set up your UIWebView
let webView = UIWebView(frame: self.view.frame) // or pass in your own custom frame rect

self.view.addSubview(webView)
self.view.bringSubviewToFront(webView)

// Set properties
webView.allowsInlineMediaPlayback = true
webView.mediaPlaybackRequiresUserAction = false

// get the ID of the video you want to play
let videoID = "zN-GGeNPQEg" // https://www.youtube.com/watch?v=zN-GGeNPQEg

// Set up your HTML.  The key URL parameters here are playsinline=1 and autoplay=1
// Replace the height and width of the player here to match your UIWebView's  frame rect
let embededHTML = "<html><body style='margin:0px;padding:0px;'><script type='text/javascript' src='http://www.youtube.com/iframe_api'></script><script type='text/javascript'>function onYouTubeIframeAPIReady(){ytplayer=new YT.Player('playerId',{events:{onReady:onPlayerReady}})}function onPlayerReady(a){a.target.playVideo();}</script><iframe id='playerId' type='text/html' width='\(self.view.frame.size.width)' height='\(self.view.frame.size.height)' src='http://www.youtube.com/embed/\(videoID)?enablejsapi=1&rel=0&playsinline=1&autoplay=1' frameborder='0'></body></html>"

// Load your webView with the HTML we just set up
webView.loadHTMLString(embededHTML, baseURL: NSBundle.mainBundle().bundleURL)
JAL
  • 41,701
  • 23
  • 172
  • 300
  • I followed your code exactly but it does not autoplay, has something changed since you write this answer? – Kashif Jun 03 '16 at 14:25
  • @Kashif what platform/ios version are you using? – JAL Jun 03 '16 at 14:26
  • @Kashif hmm, let me see if I can reproduce and fix the issue. I've mostly been using YouTube's official [YTPlayerView](https://github.com/youtube/youtube-ios-player-helper) class for things like this, but I can try to fix this answer if it's broken. – JAL Jun 03 '16 at 14:29
  • @JAL Have you been able to autoplay a fullscreen video with YTPlayerView? If yes, can you tell me how? I'm struggling to find a solution using the YT SDK :\ – LS_ Jul 07 '16 at 13:33
  • 1
    I think something has changed since this answer. I used this code and it displays correctly but it isn't playing automatically. – ryantxr Oct 04 '16 at 02:57
  • @ryantxr are you using iOS 10? Some users are reporting automatic playback issues on that iOS version. – JAL Oct 04 '16 at 04:35
  • 1
    After some minor tweaks it is playing automatically now. :-) – ryantxr Oct 04 '16 at 14:35
  • 3
    @ryantxr, What are those minor tweaks. Please share. – pkc456 May 23 '17 at 07:28
  • in 2018, iOS 11 where iOS 12 launching is very close, it works like charm. thanks – boraseoksoon Aug 30 '18 at 21:52
8

Here is full solution:

//
//  S6ViewController.m
//  
//
//  Created by Ökkeş Emin BALÇİÇEK on 11/30/13.
//  Copyright (c) 2013 Ökkeş Emin BALÇİÇEK. All rights reserved.
//

#import "S6ViewController.h"

@interface S6ViewController ()

@end

@implementation S6ViewController

- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.

    [self playVideoWithId:@"sLVGweQU7rQ"];

}




- (void)playVideoWithId:(NSString *)videoId {

     NSString *youTubeVideoHTML = @"<html><head><style>body{margin:0px 0px 0px 0px;}</style></head> <body> <div id=\"player\"></div> <script> var tag = document.createElement('script'); tag.src = 'http://www.youtube.com/player_api'; var firstScriptTag = document.getElementsByTagName('script')[0]; firstScriptTag.parentNode.insertBefore(tag, firstScriptTag); var player; function onYouTubePlayerAPIReady() { player = new YT.Player('player', { width:'768', height:'1024', videoId:'sLVGweQU7rQ', events: { 'onReady': onPlayerReady } }); } function onPlayerReady(event) { event.target.playVideo(); } </script> </body> </html>";

    NSString *html = [NSString stringWithFormat:youTubeVideoHTML, videoId];

    UIWebView *videoView = [[UIWebView alloc] initWithFrame:CGRectMake(0, 0, 768, 1024)];
    videoView.backgroundColor = [UIColor clearColor];
    videoView.opaque = NO;
    //videoView.delegate = self;
    [self.view addSubview:videoView];

    videoView.mediaPlaybackRequiresUserAction = NO;

    [videoView loadHTMLString:youTubeVideoHTML baseURL:[[NSBundle mainBundle] resourceURL]];
}

@end
okkesemin
  • 103
  • 4
  • 8
4
- (void)playVideoWithId:(NSString *)videoId {

NSString *youTubeVideoHTML = @"<html><head><style>body{margin:0px 0px 0px 0px;}</style></head> <body> <div id=\"player\"></div> <script> var tag = document.createElement('script'); tag.src = 'http://www.youtube.com/player_api'; var firstScriptTag = document.getElementsByTagName('script')[0]; firstScriptTag.parentNode.insertBefore(tag, firstScriptTag); var player; function onYouTubePlayerAPIReady() { player = new YT.Player('player', { width:'768', height:'1024', videoId:'%@', events: { 'onReady': onPlayerReady } }); } function onPlayerReady(event) { event.target.playVideo(); } </script> </body> </html>";

NSString *html = [NSString stringWithFormat:youTubeVideoHTML, videoId];

UIWebView *videoView = [[UIWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 300)];
videoView.backgroundColor = [UIColor clearColor];
videoView.opaque = NO;
//videoView.delegate = self;
[self.view addSubview:videoView];

videoView.mediaPlaybackRequiresUserAction = NO;

[videoView loadHTMLString:html baseURL:[[NSBundle mainBundle] resourceURL]];
}

I did some correction to the code above.

Ullas
  • 11,450
  • 4
  • 33
  • 50
Vannian
  • 1,490
  • 5
  • 14
  • 26
2

Use following code to play a youtube video in the UIWebView

Here we required "embed link" :

  • Just open your youtube link in browser
  • Right click on video
  • Select option "Get embed code"
  • You'll get output like -

    <iframe width="640" height="390" src="https://www.youtube.com/embed/xtNXZA4XMBY" frameborder="0" allowfullscreen></iframe>
    
  • copy the link in "src" field, this is your embed link

    Now just put this embed link on the place of "YOU_TUBE LINK" in the following code:

    NSString *htmlString = [NSString stringWithFormat:@"<html><head><meta name = \"viewport\" content = \"initial-scale = 1.0, user-scalable = yes, width = 320\"/></head><body style=\"background:#00;margin-top:0px;margin-left:0px\"><div><object width=\"320\" height=\"480\"><param name=\"movie\" value=\"YOUTUBE_LINK\"></param><param name=\"wmode\" value=\"transparent\"></param><embed src=\"YOUTUBE_LINK\"type=\"application/x-shockwave-flash\" wmode=\"transparent\" width=\"320\" height=\"480\"></embed></object></div></body></html>"];
    
    [self.webView_youTube loadHTMLString:htmlString baseURL:nil];
    
nilam_mande
  • 931
  • 7
  • 14