Get started with the IMA DAI SDK

IMA SDKs make it easy to integrate multimedia ads into your websites and apps. IMA SDKs can request ads from any VAST-compliant ad server and manage ad playback in your apps. With IMA DAI SDKs, apps make a stream request for ad and content video—either VOD or live content. The SDK then returns a combined video stream, so that you don't have to manage switching between ad and content video within your app.

Select the DAI solution you're interested in

Full service DAI

This guide demonstrates how to integrate the IMA DAI SDK into a simple video player app. If you would like to view or follow along with a completed sample integration, download the BasicExample from GitHub.

IMA DAI overview

Implementing IMA DAI involves three main SDK components as demonstrated in this guide:

  • IMAAdDisplayContainer: A container object that sits on top of the video playback element and houses the ad UI elements.
  • IMAAdsLoader: An object that requests streams and handles events triggered by stream request response objects. You should only instantiate one ads loader, which can be reused throughout the life of the application.
  • IMAStreamRequest – either a IMAVODStreamRequest or a IMALiveStreamRequest: An object that defines a stream request. Stream requests can either be for video-on-demand or live streams. Requests specify a content ID, as well as an API key or authentication token and other parameters.
  • IMAStreamManager: An object that handles dynamic ad insertion streams and interactions with the DAI backend. The stream manager also handles tracking pings and forwards stream and ad events to the publisher.

Prerequisites

Before you begin, you need the following:

Create a new Xcode project

In Xcode, create a new tvOS project using Objective-C. Use BasicExample as the project name.

Add the IMA DAI SDK to the Xcode project

Use one of these three methods to install the IMA DAI SDK.

Install the SDK using CocoaPods (preferred)

CocoaPods is a dependency manager for Xcode projects and is the recommended method for installing the IMA DAI SDK. For more information on installing or using CocoaPods, see the CocoaPods documentation. Once you have CocoaPods installed, use the following instructions to install the IMA DAI SDK:

  1. In the same directory as your BasicExample.xcodeproj file, create a text file called Podfile, and add the following configuration:

    source 'https://github.com/CocoaPods/Specs.git'
    platform :tvos, '14'
    target "BasicExample" do
      pod 'GoogleAds-IMA-tvOS-SDK', '~> 4.13.0'
    end
    
  2. From the directory that contains the Podfile, run:

    pod install --repo-update`
  3. Verify that the installation was successful by opening the BasicExample.xcworkspace file and confirming that it contains two projects: BasicExample and Pods (the dependencies installed by CocoaPods).

Install the SDK using Swift Package Manager

The Interactive Media Ads SDK supports Swift Package Manager starting in version 4.8.2. Follow these steps to import the Swift package.

  1. In Xcode, install the GoogleInteractiveMediaAds Swift Package by navigating to File > Add Packages.

  2. In the prompt that appears, search for the GoogleInteractiveMediaAds Swift Package GitHub repository:

    https://github.com/googleads/swift-package-manager-google-interactive-media-ads-tvos
    
  3. Select the version of the GoogleInteractiveMediaAds Swift Package you want to use. For new projects, we recommend using the Up to Next Major Version.

When you're done, Xcode resolves your package dependencies and downloads them in the background. For more details on how to add package dependencies, see Apple's article.

Manually downloading and installing the SDK

If you don't want to use Swift Package Manager or CocoaPods, you can download the IMA DAI SDK and manually add it to your project.

Create a simple video player

First, implement a basic video player. Initially, this player doesn't use the IMA DAI SDK nor does it contain any method to trigger playback.

ViewController.m

#import "ViewController.h"

#import <AVKit/AVKit.h>

@interface ViewController ()
@property(nonatomic) AVPlayerViewController *playerViewController;
@end

@implementation ViewController

- (void)viewDidLoad {
  [super viewDidLoad];
  self.view.backgroundColor = [UIColor blackColor];

  // Create a stream video player.
  AVPlayer *player = [[AVPlayer alloc] init];
  self.playerViewController = [[AVPlayerViewController alloc] init];
  self.playerViewController.player = player;

  // Attach the video player to the view hierarchy.
  [self addChildViewController:self.playerViewController];
  self.playerViewController.view.frame = self.view.bounds;
  [self.view addSubview:self.playerViewController.view];
  [self.playerViewController didMoveToParentViewController:self];
}

@end

Import the SDK and add stubs for IMA interaction

After you've added the IMA DAI SDK to your project, import the SDK and add stubs for the primary points of IMA interaction.

ViewController.m

#import "ViewController.h"

#import <AVKit/AVKit.h>
#import <GoogleInteractiveMediaAds/GoogleInteractiveMediaAds.h>

@interface ViewController ()
@property(nonatomic) IMAAdsLoader *adsLoader;
@property(nonatomic) UIView *adContainerView;
@property(nonatomic) IMAStreamManager *streamManager;
@property(nonatomic) AVPlayerViewController *playerViewController;
@end

@implementation ViewController

- (void)viewDidLoad {
  [super viewDidLoad];
  self.view.backgroundColor = [UIColor blackColor];

  [self setupAdsLoader];

  // Create a stream video player.
  AVPlayer *player = [[AVPlayer alloc] init];
  self.playerViewController = [[AVPlayerViewController alloc] init];
  self.playerViewController.player = player;

  // Attach the video player to the view hierarchy.
  [self addChildViewController:self.playerViewController];
  self.playerViewController.view.frame = self.view.bounds;
  [self.view addSubview:self.playerViewController.view];
  [self.playerViewController didMoveToParentViewController:self];

  [self attachAdContainer];
}

- (void)viewDidAppear:(BOOL)animated {
  [super viewDidAppear:animated];
  [self requestStream];
}

- (void)setupAdsLoader {}

- (void)attachAdContainer {}

- (void)requestStream {}

@end

Implement the IMAAdsLoader

Next, instantiate the IMAAdsLoader and attach the ad container view to the view hierarchy.

ViewController.m

- (void)setupAdsLoader {
  self.adsLoader = [[IMAAdsLoader alloc] init];
  self.adsLoader.delegate = self;
}

- (void)attachAdContainer {
  self.adContainerView = [[UIView alloc] init];
  [self.view addSubview:self.adContainerView];
  self.adContainerView.frame = self.view.bounds;
}

Make a stream request

Create a few constants to hold the stream information and then implement the stream request function to make the request.

ViewController.m

#import <GoogleInteractiveMediaAds/GoogleInteractiveMediaAds.h>

static NSString *const kAssetKey = @"sN_IYUG8STe1ZzhIIE_ksA";
static NSString *const kContentSourceID = @"2548831";
static NSString *const kVideoID = @"tears-of-steel";

@interface ViewController ()
...

- (void)requestStream {
  IMAAVPlayerVideoDisplay *videoDisplay =
      [[IMAAVPlayerVideoDisplay alloc] initWithAVPlayer:self.playerViewController.player];
  IMAAdDisplayContainer *adDisplayContainer =
      [[IMAAdDisplayContainer alloc] initWithAdContainer:self.adContainerView];
  IMALiveStreamRequest *request = [[IMALiveStreamRequest alloc] initWithAssetKey:kAssetKey
                                                              adDisplayContainer:adDisplayContainer
                                                                    videoDisplay:videoDisplay];
  // VOD request. Comment out the IMALiveStreamRequest above and uncomment this IMAVODStreamRequest
  // to switch from a livestream to a VOD stream.
  // IMAVODStreamRequest *request =
  //     [[IMAVODStreamRequest alloc] initWithContentSourceId:kContentSourceID
  //                                                  videoId:kVideoID
  //                                       adDisplayContainer:adDisplayContainer
  //                                             videoDisplay:videoDisplay];
  [self.adsLoader requestStreamWithRequest:request];
}

Handle stream events

The IMAAdsLoader and IMAStreamManager fire events that are used to handle initialization, errors, and changes in stream state. These events are fired over the IMAAdsLoaderDelegate and IMAStreamManagerDelegate protocols. Listen for an ads loaded event and initialize the stream. If an ad fails to load, play a backup stream instead.

ViewController.m

static NSString *const kAssetKey = @"sN_IYUG8STe1ZzhIIE_ksA";
static NSString *const kContentSourceID = @"2548831";
static NSString *const kVideoID = @"tears-of-steel";
static NSString *const kBackupStreamURLString =
    @"https://storage.googleapis.com/interactive-media-ads/media/bbb.m3u8";

@interface ViewController () <IMAAdsLoaderDelegate, IMAStreamManagerDelegate>

...
  [self.adsLoader requestStreamWithRequest:request];
}

- (void)playBackupStream {
  NSURL *backupStreamURL = [NSURL URLWithString:kBackupStreamURLString];
  AVPlayerItem *backupStreamItem = [AVPlayerItem playerItemWithURL:backupStreamURL];
  [self.playerViewController.player replaceCurrentItemWithPlayerItem:backupStreamItem];
  [self.playerViewController.player play];
}

#pragma mark - IMAAdsLoaderDelegate

- (void)adsLoader:(IMAAdsLoader *)loader adsLoadedWithData:(IMAAdsLoadedData *)adsLoadedData {
  // Initialize and listen to stream manager's events.
  self.streamManager = adsLoadedData.streamManager;
  self.streamManager.delegate = self;
  [self.streamManager initializeWithAdsRenderingSettings:nil];
  NSLog(@"Stream created with: %@.", self.streamManager.streamId);
}

- (void)adsLoader:(IMAAdsLoader *)loader failedWithErrorData:(IMAAdLoadingErrorData *)adErrorData {
  // Fall back to playing the backup stream.
  NSLog(@"Error loading ads: %@", adErrorData.adError.message);
  [self playBackupStream];
}

#pragma mark - IMAStreamManagerDelegate

- (void)streamManager:(IMAStreamManager *)streamManager didReceiveAdEvent:(IMAAdEvent *)event {}

- (void)streamManager:(IMAStreamManager *)streamManager didReceiveAdError:(IMAAdError *)error {}

- (void)streamManager:(IMAStreamManager *)streamManager
  adDidProgressToTime:(NSTimeInterval)time
           adDuration:(NSTimeInterval)adDuration
           adPosition:(NSInteger)adPosition
             totalAds:(NSInteger)totalAds
      adBreakDuration:(NSTimeInterval)adBreakDuration {}

@end

Handle logging and error events

There are several events that can be handled by the stream manager delegate, but for basic implementations, the most important uses are to perform event logging, to prevent seek actions while ads are playing, and to handle errors.

ViewController.m

#pragma mark - IMAStreamManagerDelegate

- (void)streamManager:(IMAStreamManager *)streamManager didReceiveAdEvent:(IMAAdEvent *)event {
  NSLog(@"StreamManager event (%@).", event.typeString);
  switch (event.type) {
    case kIMAAdEvent_STARTED: {
      // Log extended data.
      NSString *extendedAdPodInfo = [[NSString alloc]
          initWithFormat:@"Showing ad %zd/%zd, bumper: %@, title: %@, description: %@, contentType:"
                         @"%@, pod index: %zd, time offset: %lf, max duration: %lf.",
                         event.ad.adPodInfo.adPosition, event.ad.adPodInfo.totalAds,
                         event.ad.adPodInfo.isBumper ? @"YES" : @"NO", event.ad.adTitle,
                         event.ad.adDescription, event.ad.contentType, event.ad.adPodInfo.podIndex,
                         event.ad.adPodInfo.timeOffset, event.ad.adPodInfo.maxDuration];

      NSLog(@"%@", extendedAdPodInfo);
      break;
    }
    case kIMAAdEvent_AD_BREAK_STARTED: {
      // Prevent user seek through when an ad starts and show the ad controls.
      self.adContainerView.hidden = NO;
      break;
    }
    case kIMAAdEvent_AD_BREAK_ENDED: {
      // Allow user seek through after an ad ends and hide the ad controls.
      self.adContainerView.hidden = YES;
      break;
    }
    default:
      break;
  }
}

- (void)streamManager:(IMAStreamManager *)streamManager didReceiveAdError:(IMAAdError *)error {
  // Fall back to playing the backup stream.
  NSLog(@"StreamManager error: %@", error.message);
  [self playBackupStream];
}

@end

That's it! You're now requesting and displaying ads with the IMA DAI SDK. To learn about more advanced SDK features, see the other guides or the samples on GitHub.