Jimmery
Jimmery

Reputation: 10119

Knowing when a YouTube video starts playing from within a UIWebView

I have made a class that plays YouTube videos (thanks to the help from the kind people of this site).

Now I am wondering how I find out when a YouTube video starts playing. I want to know this so I can show a "Please Wait, Loading..." indicator in-between the video being told to play and it actually playing.

I start the video playing using stringByEvaluatingJavaScriptFromString:, and of course there is a slight delay between me firing off the javascript command to get the video playing and the video actually playing.

I am familiar with YouTube videos and javascript, so Ive been looking at this: [ https://developer.apple.com/library/mac/documentation/AppleApplications/Conceptual/SafariJSProgTopics/Tasks/ObjCFromJavaScript.html ] because I am wondering if a javascript event listener inside the UIWebView could detect when a YouTube video starts playing (listening for the onStateChange event) and fire off an Objective C method.

Is this possible? Do UIWebViews run javascript in the same way as a web browser would?

Is there an easier / better way of doing this?

Here is my youtube class:

// this is the only property declared in the .h file:
@property (strong, nonatomic) UIView * view

// the rest of this is the .m file:
#import "MyYouTube.h"
@interface MyYouTube()
@property (strong, nonatomic) NSDictionary * contentData;
@property (strong, nonatomic) UIWebView * webView;
@property (nonatomic) int videoOffset;
@end

@implementation MyYouTube
@synthesize view,contentData,webView,videoOffset;

- (MyYouTube*) initIntoView: (UIView*) passedView withContent: (NSDictionary*) contentDict {
    NSLog(@"YOUTUBE: begin init");
    self=[super init];
    videoOffset=0;
    view=[[UIView alloc] initWithFrame:passedView.bounds];
    [view setBackgroundColor:[UIColor blackColor]];
    [view setAutoresizesSubviews:YES];
    [view setAutoresizingMask:UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth];
    contentData=contentDict;

    NSString * compiledUrl=[[NSString alloc] initWithFormat:@"http://_xxx_.com/app/youtube.php?yt=%@",[contentData objectForKey:@"cnloc"]];
    NSURL * url=[[NSURL alloc] initWithString:compiledUrl];
    NSURLRequest * request=[[NSURLRequest alloc] initWithURL:url];

    webView=[[UIWebView alloc] initWithFrame:passedView.bounds];
    [webView loadRequest:request];
    [webView setAutoresizingMask:UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight];
    [[webView scrollView] setScrollEnabled:NO];
    [[webView scrollView] setBounces:NO];
    [webView setMediaPlaybackRequiresUserAction:NO];
    [webView setDelegate:self];

    NSLog(@"YOUTUBE: self: %@",self);
    NSLog(@"YOUTUBE: delegate: %@",webView.delegate);

    [view addSubview:webView];
    NSLog(@"YOUTUBE: end init");
    return self;
}

-(void)webViewDidFinishLoad:(UIWebView*)myWebView {
    NSLog(@"YOUTUBE: send play command");
    [webView stringByEvaluatingJavaScriptFromString:[NSString stringWithFormat:@"playVideo(%d)", videoOffset]];
}

@end

Many thanks.

Upvotes: 3

Views: 2077

Answers (1)

Alladinian
Alladinian

Reputation: 35616

I believe that this could work on iOS7 via the new JavaScriptCore framework (although I've not personally tested it).

What I've tested though and it seems to be working fine is this approach:

Instead of registering a listener on different event changes, you could have a timer that queries the state of the player every second.

First, you could define some states on the player class (that would correspond to Youtube's states) (in header file):

typedef NS_ENUM(NSInteger, YoutubeVideoState){
    YOUTUBE_VIDEO_STATE_UNSTARTED   = -1,
    YOUTUBE_VIDEO_STATE_ENDED       = 0,
    YOUTUBE_VIDEO_STATE_PLAYING     = 1,
    YOUTUBE_VIDEO_STATE_PAUSED      = 2,
    YOUTUBE_VIDEO_STATE_BUFFERING   = 3,
    YOUTUBE_VIDEO_STATE_VIDEO_CUED  = 5
};

Then you could have a readonly property to get the state (also in header file):

@property (nonatomic, readonly) YoutubeVideoState state;

which would be implemented like:

- (YoutubeVideoState)state
{
    return (YoutubeVideoState)[[self.webView stringByEvaluatingJavaScriptFromString:@"getPlayerState()"] integerValue];
}

Now you can just ask from your instance to get you the current state in each timer invocation like:

YoutubeVideoState currentState = myPlayerInstance.state;

and possibly decide on your next action via a switch or an if statement:

if (currentState == YOUTUBE_VIDEO_STATE_PLAYING) {
    // Start your engines!
}

Upvotes: 4

Related Questions