Embed YouTube Videos in iOS Applications with the YouTube Helper Library

, YouTube Developer Relations – April 2014

The youtube-ios-player-helper is an open source library that helps you embed a YouTube iframe player into an iOS application. The library creates a UIWebView and a bridge between your application’s Objective-C code and the YouTube player’s JavaScript code, thereby allowing the iOS application to control the YouTube player. This article describes the steps to install the library and get started using it from your iOS application.

Installation

This article assumes you have created a new Single View Application iOS project targeting iOS 7, and that you have the following files in addition to the other files added when creating this project:

  • Main.storyboard
  • ViewController.h
  • ViewController.m

There are two ways to install the library. The library is available to install via CocoaPods, which has seen adoption as the iOS developer community’s dependency management tool of choice. Alternatively, the library and source files are available via the project’s GitHub page and can be copied into an existing project.

Install the library via CocoaPods

If your project is using CocoaPods for dependency management, installing the library is just a matter of adding the following line to your Podfile:

pod "YouTube-Player-iOS-Helper", "~> 0.1"

At the command line prompt, type pod install to update your workspace with the dependencies.

Tip: Remember that when using CocoaPods, you must open the .xcworkspace file in Xcode, not the .xcodeproj file.

To learn more about CocoaPods, check out their tutorial.

Manually install the library

The helper library is also easy to install manually. Either download the source via GitHub’s download link or clone the repository. Once you have a local copy of the code, follow these steps:

  1. Open the sample project in Xcode or Finder.

  2. Select YTPlayerView.h, YTPlayerView.m, and the Assets folder. If you are opening the workspace in Xcode, these will be available under Pods -> Development Pods -> YouTube-Player-iOS-Helper and Pods -> Development Pods -> YouTube-Player-iOS-Helper -> Resources. In the Finder, these are available in the project's root directory in the Classes and Assets directories.

  3. Drag these files and folders into your project. Make sure the Copy items into destination group’s folder option is checked. When dragging the Assets folder, make sure that the Create Folder References for any added folders option is checked:

The library should now be installed.

Add a YTPlayerView via Interface Builder or the Storyboard

To add a YTPlayerView via Interface Builder or the Storyboard:

  1. Drag a UIView instance onto your View.

  2. Select the Identity Inspector and change the class of the view to YTPlayerView.

  3. Open ViewController.h and add the following header:

    #import “YTPlayerView.h”

    Also add the following property:

    @property(nonatomic, strong) IBOutlet YTPlayerView *playerView;
  4. In Interface Builder, create a connection from the View element that you defined in the previous step to your View Controller's playerView property.

  5. Now open ViewController.m and add the following code to the end of your viewDidLoad method:

    [self.playerView loadWithVideoId:@"M7lc1UVf-VE"];

Build and run your application. When the video thumbnail loads, tap the video thumbnail to launch the fullscreen video player.

Control video playback

The ViewController::loadWithVideoId: method has a variant, loadWithVideoId:playerVars:, that allows developers to pass additional player variables to the view. These player variables correspond to the player parameters in the JavaScript Player API. The playsinline parameter enables the video to play directly in the view rather than playing fullscreen. When a video is playing inline, the containing iOS application can programmatically control playback.

Replace the loadWithVideoId: call with this code:

NSDictionary *playerVars = @{
  @"playsinline" : @1,
};
[self.playerView loadWithVideoId:@"M7lc1UVf-VE" playerVars:playerVars];

Open up the storyboard or Interface Builder. Drag two buttons onto your View, labeling them Play and Stop. Open ViewController.h and add these methods, which will be mapped to the buttons

- (IBAction)playVideo:(id)sender;
- (IBAction)stopVideo:(id)sender;

Now open ViewController.m and define these two functions:

- (IBAction)playVideo:(id)sender {
  [self.playerView playVideo];
}

- (IBAction)stopVideo:(id)sender {
  [self.playerView stopVideo];
}

Most of the JavaScript Player API functions have Objective-C equivalents, though some of the naming may differ slightly to more closely match Objective-C coding guidelines. Notable exceptions are methods controlling the volume of the video, since these are controlled by the phone hardware or with built in UIView instances designed for this purpose, such as MPVolumeView.

Open your storyboard or Interface Builder and control-drag to connect the Play and Stop buttons to the playVideo: and stopVideo: methods.

Now build and run the application. Once the video thumbnail loads, you should be able to play and stop the video using native controls in addition to the player controls.

Handle player callbacks

It can be useful to programmatically handle playback events, such as playback state changes and playback errors. In the JavaScript API, this is done with event listeners. In Objective-C,this is done with a delegate.

The following code shows how to update the interface declaration in ViewController.h so the class conforms to the delegate protocol. Change ViewController.h’s interface declaration as follows:

@interface ViewController : UIViewController<YTPlayerViewDelegate>

YTPlayerViewDelegate is a protocol for handling playback events in the player. To update ViewController.m to handle some of the events, you first need to set the ViewController instance as the delegate of the YTPlayerView instance. To make this change, add the following line to the viewDidLoad method in ViewController.h.

self.playerView.delegate = self;

Now add the following method to ViewController.m:

- (void)playerView:(YTPlayerView *)playerView didChangeToState:(YTPlayerState)state {
  switch (state) {
    case kYTPlayerStatePlaying:
      NSLog(@"Started playback");
      break;
    case kYTPlayerStatePaused:
      NSLog(@"Paused playback");
      break;
    default:
      break;
  }
}

Build and run the application. Watch the log output in Xcode as the player state changes. You should see updates when the video is played or stopped.

The library provides the constants that begin with the kYT* prefix for convenience and readability. For a full list of these constants, look at YTPlayerView.m. Other useful methods include:

- (void)playerViewDidBecomeReady:(YTPlayerView *)playerView;
- (void)playerView:(YTPlayerView *)playerView didChangeToState:(YTPlayerState)state;
- (void)playerView:(YTPlayerView *)playerView didChangeToQuality:(YTPlaybackQuality)quality;
- (void)playerView:(YTPlayerView *)playerView receivedError:(YTPlayerError)error;

Best practices and limitations

The library builds on top of the iframe player API by creating a UIWebView and rendering the HTML and JavaScript required for a basic player. The library's goal is to be as easy-to-use as possible, bundling methods that developers frequently have to write into a package. There are a few limitations that should be noted:

  • The library does not support concurrent video playback in multiple YTPlayerView instances. If your application has multiple YTPlayerView instances, a recommended best practice is to pause or stop playback in any existing instances before starting playback in a different instance. In the example application that ships with the project, the ViewControllers make use of NSNotificationCenter to dispatch notifications that playback is about to begin. Other ViewControllers are notified and will pause playback in their YTPlayerView instances.
  • Reuse your existing, loaded YTPlayerView instances when possible. When a video needs to be changed in a View, don't create a new UIView instance or a new YTPlayerView instance, and don't call either loadVideoId: or loadPlaylistId:. Instead, use the the cueVideoById:startSeconds:suggestedQuality: family of functions, which do not reload the UIWebView. There is a noticeable delay when loading the entire iframe player.
  • This player cannot play private videos, but it can play unlisted videos. Since this library wraps the existing iframe player, the player's behavior should be nearly identical to that of a player embedded on a webpage in a mobile browser.

Open source

The library's best feature is that it is open source. Prefer a different way of doing something? Fork the code! If you have any questions about this code or anything related to the API, ask away using the youtube-api tag on StackOverflow.