In mobile development, developers often get tasked with integrating third-party social platforms like Facebook, Twitter, or YouTube into the applications they build. Clients usually want ways to aggregate their social content into whatever app they build (pulling content in) or to promote other users to share their content within their respective social circles (pushing content out).

Most of these social platforms provide convenient SDKs (Software Development Kits) that allow you to integrate with their services easier. These SDKs are platform-specific tools and components that help expedite the development process by preventing the need to build out particular features from scratch. Additionally, they also have platform-independent APIs that can be queried using the proper application authentication. These APIs can return a multitude of data from within the system, about which you'll discover more in this article.

Throughout the course of this article, you'll focus on one of these platforms in particular: YouTube. You'll learn how to create and register an application and application key, how to pull content from YouTube via their public API, and how to go through the process of integrating their native video player component for playing back YouTube content from within your application.

The YouTube API

YouTube currently has over 1 billion users and serves up millions of hours of content on a daily basis. They reach more 18-to-49 year-olds than any cable network in the U.S. ( www.youtube.com/yt/press/statistics.html ). As a developer, you can take advantage of this content and integrate many of the site's features into your own applications using the provided developer tools and APIs that the service offers.

For the purposes of this demonstration, you'll work with the core platform API to learn how to retrieve a subset of videos from YouTube matching a search query that you define. You'll also learn about various ways to filter the results returned via the query parameters. Lastly, you'll implement the YouTube-provided native iOS video player to play the content that you retrieve. You can access the documentation for the various API endpoints offered, including ones not covered in this article, at https://developers.google.com/youtube/.

YouTube currently has over 1 billion users and serves up millions of hours of content on a daily basis.

API Usage

The YouTube API is free to use for most applications. Larger applications with bigger user bases may need to apply for a higher quota to satisfy its needs, but in most cases, the free tier should suffice. The free tier has the following parameters:

  • 50,000,000 units per day
  • 3,000 requests per user, per second
  • Daily quotas reset at midnight Pacific Time

It's important to note that “units” are a proprietary metric used by Google and are not a one-to-one relationship to the number of API calls that your application makes. Each different API endpoint cost a specific number of units per call. For instance, the YouTube search API demonstrated in this article costs 100 units per call.

It's important to note that “units” are a proprietary metric used by Google and are not a one-to-one relationship to the number of API calls that your application makes.

Before you can begin using the API, you must register your application and enable access to the YouTube API from the Google Developer Console. To do this, first navigate to https://console.developers.google.com. Once there, sign-in with your Google account. After a successful sign-in, you'll arrive at the console dashboard. From the dashboard, complete the following steps:

  • To the left of your profile avatar at the top right of the page, find the drop-down menu with the “Create a Project” option. Click that.
  • A dialogue box appears with a prompt for the project name. Fill in the name of the project and click “Create”. The dashboard automatically switches to the new project that you just created.
  • You should now see a blue dialogue box that says “Use Google APIs” with an option that says, “Enable and manage APIs”. You need to go here to enable YouTube. Click on that option.
  • Now you can see a list of several different services and APIs that Google offers. Find the one on the far right entitled “YouTube Data API”. Click that option and, on the next screen, press “Enable API”.

At this point, you've enabled YouTube Data API access for your application, but your application still needs a valid API key so that Google can verify your app's identity when it makes an API call. The level of authentication that your application needs to access the API can vary based on the functionality that it wants to take advantage of. Three levels of access exist that your application can generate credentials for (also shown in Figure 1):

  1. API Key: Identifies your project using a simple API key to check quota and access. This is the level of access you�ll use later in this article.
  2. Oauth 2.0 Client ID: Requests user consent so that your app can access the user�s data. It�s needed to access account-specific details and APIs.
  3. Service Account: Enables server-to-server, app-level authentication using robot accounts. It�s mainly for use with Google Cloud APIs.

On the screen where you enabled YouTube API access, there's a menu on the left with an option titled “Credentials”. Go here to generate the API Key that you need. Once there, drop down the “Add Credentials” option, as shown in Figure 1, and select “API Key”.

Figure 1: Google API Manager console. Select “API Key” for the purposes of this demonstration.
Figure 1: Google API Manager console. Select “API Key” for the purposes of this demonstration.

Once selected, you'll receive a modal that asks you to identify your application's platform. Select “iOS Key” from the available options to continue. Next, name the key however you see fit and then input the application's Bundle ID: I used com.codemagazine.YTDemo for the purposes of this demonstration. Lastly, a dialogue should appear with your API key listed in it. Copy this ID because you'll need it when you begin working through the code samples later in this article.

The Endpoint

For this demonstration, you'll work with the YouTube search API to find videos that relate to a search query that you define. The base API request URL to search YouTube videos looks like the following:

https://www.googleapis.com/youtube/v3/search

In order to call that endpoint and retrieve the relative data, you need to append several parameters to the request. The required parameters for this call include the search query, the API key, and a “part” parameter that indicates the search properties that you'll get back in the response. The “part” parameter for a query to the search endpoint should be set to “snippet.” The following code sample demonstrates what you would append to the above URL in order to search for videos using the keyword “programming”.

?q=programming&part=snippet&key=
{INSERT YOUR API KEY HERE}

Additionally, there's a host of optional parameters that you can append to the URL to filter or organize the results to your liking. The following list describes some of the more useful ones (full documentation on parameters can be found at https://developers.google.com/youtube/v3/docs/search/list).

  • channelId: Search only returns matched content created by the specified channel.
  • location & locationRadius: Together, these two parameters let you limit search results to a specific geographical area.
  • maxResults: The maximum total items returned from the query. Acceptable values range between 0-50 (inclusive).
  • type: Set to “channel,” “playlist,” or “video.” Defines the type of content returned by the search.
  • regionCode: Limits results to a specific country.
  • relevanceLanguage: Returns results most relevant to the indicated language. The parameter is typically an ISO 639-1 two letter language code (en for “English” for instance).
  • order: Defines the order of the search results. Set to “date,” “rating,” “relevance,” “title,” “videoCount,” or “viewCount.”

For the purposes of this article, request videos on “programming” in English from the search API. Using the parameters described above, that full request looks like this:

https://www.googleapis.com/youtube/v3/search?
part=snippet&regionCode=US&relevanceLanguage=en
&type=video&order=relevance&maxResults=20
&q=programming&key={YOUR API KEY}

The Data

After sending a search request to the API, the service responds with the resulting matches. The response format is JSON and following snippet demonstrates the structure of the returned data.

{
    "kind": "youtube#searchListResponse",
    "etag": etag,
    "nextPageToken": string,
    "prevPageToken": string,
    "pageInfo": {
        "totalResults": integer,
        "resultsPerPage": integer
    },
    "items": [
        search Resource
    ]
}

The “items” array contains the matched results. Each individual item in that array has a set of data that describes it. Listing 1 demonstrates the format of each item. Additionally, notice the inclusion of next and previous page tokens. The maxResults parameter described earlier determines the number of items initially returned (if not specified, the default is 5). However, in most cases, the total number of matching items exceeds the maxResults parameter. In those cases, you can use the next and previous page tokens to paginate through the entirety of the results.

Listing 1: JSON format of video items returned from the YouTube search API

{
    "kind": "youtube#searchResult",
    "etag": etag,
    "id": {
        "kind": string,
        "videoId": string,
        "channelId": string,
        "playlistId": string
    },
    "snippet": {
        "publishedAt": datetime,
        "channelId": string,
        "title": string,
        "description": string,
        "thumbnails": {
            (key): {
                "url": string,
                "width": unsigned integer,
                "height": unsigned integer
            }
        },
    "channelTitle": string,
    "liveBroadcastContent": string
    }
}

Referring again to Listing 1, notice that the information returned for each video includes channel information, video title, video description, and video thumbnails among other things. In this demonstration, however, you'll only use the “videoId” property, which gets used to play the video.

YouTube iOS Player

Currently, you can't play a YouTube video directly from an iOS application using an AVPlayer object. The only method currently supported by YouTube involves embedding an iFrame container inside your application to load the video. The user then plays the video from this embedded iFrame and, as is the case with any Web-based-video, the operating system's standard video player takes over once the video begins.

YouTube released an iOS library to simplify this process called YTPlayer (https://github.com/youtube/youtube-ios-player-helper). Rather then going through the hassle of implementing a UIWebView and then adding the HTML iFrame code to it directly, you can use the YTPLayer library's provided player view to handle this implementation for you. Simply initialize an instance of YTPlayerView and tell it to load the respective video by passing it a video ID. The sample application you'll build in the next section demonstrates how to add this library to your application and take advantage of it.

Let's Code It

In this code exercise, you'll write a VideoManager class that can fetch videos from YouTube using the search API. The VideoManager class uses callbacks to return an NSArray of videos. You'll also write a Video object that models the video data returned. This portable library can get dropped into any project that needs to fetch and play videos from YouTube.

Getting Started

The first thing you'll want to do is create a new Xcode project for this exercise. To do this, launch Xcode and click Create a new Xcode project. Select Single View Application and press Next. Finally, fill in a project name and match the other settings to the screenshot from Figure 2.

Figure 2: Initial project settings when creating the sample project in Xcode
Figure 2: Initial project settings when creating the sample project in Xcode

Once your settings match Figure 2, click Next. You should now have a blank Xcode project. The only other thing you need to set up before you get coding is YTPlayer. Add the YTPlayer library to the project using CocoaPods, one of the simplest methods to add third-party content to any iOS project. For the sake of this walkthrough, I'll assume that you have a working understanding of how to install a library using CocoaPods. (If not, please refer to the sidebar for additional information on how to use CocoaPods or where you can locate additional installation instructions.) Once you've created a Podfile, add the following line to the file and save.

pod "youtube-ios-player-helper", "~> 0.1.4"

Once saved, launch terminal and navigate to the root folder for your project. Make sure that the project is closed in Xcode and run the following command in terminal.

pod install

This automatically downloads the YTPlayer library and creates an .xcworkspace file. Re-open your project by double clicking that new project file.

Video Model

The next thing you want to add to the project is a video object model that holds the information you receive from the call to the YouTube search API. Click File > New > File and then choose Cocoa Touch Class. Next, choose NSObject and name the object “Video”, as shown in Figure 3.

Figure 3: Settings when creating the video object model to store video data
Figure 3: Settings when creating the video object model to store video data

Once that has been created, you'll need to add various properties to correspond to the video data you want to collect from the API response. Although you'll only use the video ID property in this example, the sample code captures additional details to further demonstrate how to interact with the API. Additionally, you can follow the same structure to store any of the remaining data points that don't get picked up in this sample.

Open the Video.h file that you just generated. Add the properties for the data you'll track, as shown in Listing 2. These properties map to the various data points that get returned by the API and the comments from Listing 2 offer more detail on what each property represents.

Listing 2: Video.h � variable parameters

@interface Video : NSObject

/// title of the video as shown in YouTube
@property (nonatomic, strong) NSString* videoTitle;

/// id of the video used to load the video in the iFrame
@property (nonatomic, strong) NSString* videoID;

/// the name of the channel the video is posted in (author name
@property (nonatomic, strong) NSString* channelTitle;

/// id that can be used to load further content from the channel
@property (nonatomic, strong) NSString* channelID;

/// snippet of the video description from YouTube
@property (nonatomic, strong) NSString* videoDescription;

/// url to the cover thumbnail of the video
@property (nonatomic, strong) NSString* thumbnailURL;

/// date the video was posted on YouTube
@property (nonatomic, strong) NSDate* pubDate;

@end

The next step involves creating the video manager class that gathers the information needed to populate this video object. That manager class retrieves the video data from the search query as a JSON object. Once you cover that in the next section, you'll loop back and create an initializer method on this video model to take the JSON data and parse it into the appropriate properties you just created.

Video Manager

Just like you previously did with the video model, go to File > New > File and select NSObject to create a new class. Name it VideoManager and click Next and then Save. This VideoManager class directly integrates with the YouTube search API endpoint described earlier to get the desired video information. NSURLSession handles the call for data, so you need to write a function that uses a session to make a request to the service. Listing 3 demonstrates this function implementation in VideoManager.m and how to use NSURLRequest and NSURLSession to formulate the query.

Listing 3: VideoManager.m � send API request to specified URL

@implementation VideoManager

/**
*  Search programming videos on Youtube
*
*  @param channelID       ID of channel to only search on
*  @param completionBlock Returns array of search results
*/
- (void)getVideos:(NSString*)channelID completionBlock:
  (void (^)(NSMutableArray *))completionBlock {
      // The API Key you registered for earlier
      NSString* apiKey = @"YOUR API KEY";
      // only used if we want to limit search by channel
      NSString* optionalParams = @"";

    // if channel ID provided, create the paramter
    if(channelID){
        optionalParams = [NSString
        stringWithFormat:@"&channelId=%@", channelID];
    }

    // format the URL request to the YouTube API:
    // max results set to 20, language set to english,
    // order by most relevant
    NSString* URL = [NSString
    stringWithFormat:@"https://www.googleapis.com/youtube
    /v3/search?part=snippet&regionCode=US
    &relevanceLanguage=en&$type=video&order=relevance
    &maxResults=20&q=%@&key=%@&alt=json%@",
    @"programming", apiKey, optionalParams];

    // initialize the request with the encoded URL
    NSURLRequest *request = [[NSURLRequest alloc]
    initWithURL:[NSURL URLWithString:[URL
    stringByAddingPercentEncodingWithAllowedCharacters:
    [NSCharacterSet URLQueryAllowedCharacterSet]]]];

    // create a session and start the request
    NSURLSession *session = [NSURLSession sharedSession];
    [[session dataTaskWithRequest:request
        completionHandler:^(NSData *data,
            NSURLResponse *response,
            NSError *error) {
                if (!error){
                    Video* vid = [[Video alloc] init];

                    // create an array of Video objects from
                    // the JSON received
                    [vid getVideoList:[NSJSONSerialization
                    JSONObjectWithData:data
                    options:0 error:nil] completionBlock:
                    ^(NSMutableArray * videoList) {
                        // return the final list
                        completionBlock(videoList);
                    }];
                }
                else {
                    // TODO: better error handling
                    NSLog(@"error = %@", error);
                }
            }] resume];
  }

@end

Notice that the function definition takes an optional channelID parameter. If included, the search results only contain videos from the specified ID. Also notice that there is a callback block that passes an NSMutableArray to the calling function. That array contains the video objects returned by the search query.

You've now enabled the video manager class to communicate with the API. Next, you need to add the getVideoList function to the Video model object that you previously created. Notice that this function gets called in the Listing 3 code you just wrote. It creates an array of video objects using the JSON response from YouTube. Before doing that, switch over to VideoManager.h and add the function definition for what you just wrote in Listing 3.

@interface VideoManager : NSObject
- (void)getVideos:(NSString*)channelID
  completionBlock:(void (^)(NSMutableArray *))
  completionBlock;
@end

Lastly, you want to import the Video object or else the call to getVideoList in VideoManager.m triggers a build error. Add the import to the top of VideoManager.h.

#import "Video.h"

Now you can move back to the model and add the functions needed to parse the JSON information into manageable video objects. The next section covers this.

Back to the Video Model

You've almost completed the circle. You started by creating a video model object, wrote a manager class to get the data to populate that object, and now you need the final logic that maps that data from the API results into the model. Move back to your Video.h file and declare the following function header.

/**
*create array of video objects
*using the JSON data passed in the
*dictionary parameter
*
*  @param videoData JSON data from API
*  @param completionBlock array of video objects
*/
- (void)getVideoList:(NSDictionary*)videoData
  completionBlock:(void (^)(NSMutableArray *))
  completionBlock;

This is the function that the VideoManager class passes the returned JSON data to as described earlier. Listing 4 demonstrates the implementation of this function that you add to Video.m. That function depends on an initialization function that also gets added to the Video.m file. Listing 5 shows that initialization function, which takes in a single video item as JSON data in dictionary format. It parses out the needed properties and then returns an instance of self. This gets called for each video in the videoData that JSON provided to getVideoList. All of the created instances of video get returned to VideoManager.m in the completion block as an array.

Listing 4: Video.m – parse search query JSON into video objects

/**
*  create array of video objects
*  using the JSON data passed in the
*  dictionary parameter
*
*  @param videoData       JSON data from API
*  @param completionBlock array of video objects
*/
-  (void)getVideoList:(NSDictionary*)videoData
    completionBlock:(void (^)(NSMutableArray *))
    completionBlock {

        // get the array of videos from the dictionary containing
    // the JSON data returned from the call to the YouTube API
    NSArray *videos = (NSArray*)[videoData objectForKey:@"items"];
    NSMutableArray* videoList = [[NSMutableArray alloc] init];

    // loop through each video in the array, if it has an ID
    // initialize an instance of self with the relative
    // properties
    for (NSDictionary *videoDetail in videos) {
        if (videoDetail[@"id"][@"videoId"]){
            [videoList addObject:[[Video alloc]
            initWithDictionary:videoDetail]];
        }
    }

    // pass the array of video objects back to VideoManager.m
    completionBlock(videoList);
    }

Notice that Listing 5 has a call to dateWithJSONString. This helper function takes a date string from the JSON response and converts it into an NSDate object, a more manageable format for your application. That function should get created within an NSString category and its implementation is demonstrated in Listing 6.

Listing 5: Video.m – initialization function

- (instancetype)initWithDictionary:(NSDictionary *)dictionary {
    self = [super init];

    if (self) {
        _videoTitle = dictionary[@"snippet"][@"title"];
        _videoID = dictionary[@"id"][@"videoId"];
        _channelID = dictionary[@"snippet"][@"channelId"];
        _channelTitle = dictionary[@"snippet"][@"channelTitle"];
        _videoDescription = dictionary[@"snippet"][@"description"];
        _pubDate = [dictionary[@"snippet"][@"publishedAt"]
            dateWithJSONString];
        _thumbnailURL = dictionary[@"snippet"][@"thumbnails"]
            [@"high"][@"url"];
    }

    return self;
}

Listing 6: NSString utility function that converts a string to an NSDate

/*
* take the current string and converts it into a manipulatable
* NSDate object and then returns that object
*/
- (NSDate*)dateWithJSONString {
    [NSDateFormatter setDefaultFormatterBehavior: NSDateFormatterBehavior10_4];
    NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];

    [dateFormatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ss.SSSz"];
    [dateFormatter setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0]];
    [dateFormatter setCalendar:[[NSCalendar alloc] 
    initWithCalendarIdentifier:NSCalendarIdentifierGregorian]];

    NSDate *date = [[NSDate alloc] init];
    date = [dateFormatter dateFromString:self];
    return date;
}

You have now completed both the VideoManager and Video classes. Simply initialize a VideoManager object from anywhere in your application and call getVideos to retrieve the desired video information.

The Last Piece to the Puzzle

The final piece of the puzzle involves the YTPlayer class that you added to the project earlier. Using the code you already wrote in Listings 1-6, you can get YouTube videos by adding the following code to any controller in your application.

NSMutableArray *ytVideos = [[NSMutableArray alloc] init];

VideoManager* vidManager = [[VideoManager alloc] init];

[vidManager getVideos:nil
completionBlock:^(NSMutableArray *videoList) {
    ytVideos = [[videoList
    sortedArrayUsingDescriptors:[NSArray
    arrayWithObject:[[NSSortDescriptor alloc]
    initWithKey:@"pubDate" ascending:NO]]]
    mutableCopy];
}];

The previous code initializes an instance of the VideoManager class and makes a request to get videos. Once the videos return, they get sorted by publication date and stored in a local array object where you can do with it what you please. Now you have the video results and you want to display them so your users can play them. To do this, you first want to import YTPlayer as follows.

#import "YTPlayerView.h"

Next, you create an instance of the player and load the video using the video ID. The next code snippet demonstrates how this is done by taking the first video object from the previous code's result array, ytVideos, and creating a YTPLayerView to display it.

Video *video = [ytVideos objectAtIndex:0];
// initialize a player with the frame that you
// want the video preview to be initially
// displayed in.
// Can also set the view up in Interface Builder
// using auto-layout and use an IBOutlet to
// connect to your instance of YTPlayerView
YTPlayerView *videoPlayerView = [[YTPlayerView alloc] initWithFrame:
CGRectMake(0, 0, 375, 320)];

[videoPlayerView loadWithVideoId:video.videoID];
[self.view addSubview:videoPlayerView];

In the above example, the video preview frame is manually set to 375px wide by 320px high. Figure 4 demonstrates an example of what that looks like once it's added to the view. When the user taps the red play button in the middle of that preview, the standard iOS video player goes to full screen and begins to play the corresponding video.

Figure 4: Sample of what a YTVideoPlayer looks like
Figure 4: Sample of what a YTVideoPlayer looks like

Practical Application

The code you just wrote is a portable library that can be dropped into any application; just add the VideoManager and Video classes to the project and import the YTPlayer library. To demonstrate the practicality of the library, I've used it to create a demo application that uses the additional video properties that you captured in the Video model to visually display the search results in a UITableView. Figure 5 and Figure 6 depict the application UI. The table lists the search results using the video title and thumbnail properties. Thumbnails are loaded asynchronously to prevent any lagging in the scroll. The code included alongside this article not only encompasses the YouTube library covered previously, but it also includes all code for this sample application as well. This should help you understand exactly how to call the library and how to apply the results.

Figure 5      : Sample application using the YouTube library from this article
Figure 5 : Sample application using the YouTube library from this article
Figure 6: Sample application using the YouTube library from this article
Figure 6: Sample application using the YouTube library from this article

Wrapping Up

Hopefully, over the course of this article, you gained a basic understanding of how to use the search service offered by YouTube's API and how to use that service to pull video content into your iOS application. If you'd like a more detailed breakdown of the search API or additional YouTube APIs, be sure to visit developers.google.com/youtube for full API documentation. The sidebars for this article have links to additional resources that may also be of use.