设置 IMA SDK

请选择平台HTML5 Android iOS tvOS

借助 IMA SDK,您可以轻松地将多媒体广告集成到网站和应用中。IMA SDK 可以从任何 符合 VAST 标准的广告服务器请求广告,并在您的应用中管理广告播放。借助 IMA 客户端 SDK,您可以继续控制内容视频播放,而 SDK 则负责处理广告播放。广告在位于应用内容视频播放器顶部的单独视频播放器中播放。

本指南演示了如何将 IMA SDK 集成到简单的视频播放器应用中。如果您想查看或跟随完成的示例集成,请从 GitHub 下载 BasicExample

IMA 客户端概览

实现 IMA 客户端涉及四个主要 SDK 组件,本指南将对此进行演示:

  • IMAAdDisplayContainer:一个容器对象,用于指定 IMA 呈现广告界面元素和衡量可见率的位置,包括 Active ViewOpen Measurement
  • IMAAdsLoader: 一个用于请求广告并处理广告请求响应中的事件的对象。您只需实例化一个广告加载程序,该加载程序可在整个应用生命周期内重复使用。
  • IMAAdsRequest: 用于定义广告请求的对象。广告请求会指定 VAST 广告代码的网址以及其他参数(例如广告尺寸)。
  • IMAAdsManager: 一个包含广告请求响应、控制广告播放并监听 SDK 触发的广告事件的对象。

前提条件

在开始之前,您需要做好以下准备:

1. 创建新的 Xcode 项目

在 Xcode 中,使用 Objective-C 或 Swift 创建新的 tvOS 项目。使用 BasicExample 作为项目名称。

2. 将 IMA SDK 添加到 Xcode 项目

使用 CocoaPods 安装 SDK(首选)

CocoaPods 是 Xcode 项目的依赖项管理器,也是安装 IMA SDK 的推荐方法。如需详细了解如何安装或使用 CocoaPods,请参阅 CocoaPods 文档。安装 CocoaPods 后,请按照以下说明安装 IMA SDK:

  1. BasicExample.xcodeproj 文件所在的目录中,创建一个名为 Podfile 的文本文件,并添加以下配置:

    source 'https://github.com/CocoaPods/Specs.git'
    platform :tvos, '14'
    target "BasicExample" do
      pod 'GoogleAds-IMA-tvOS-SDK', '~> 4.15.1'
    end
    
  2. 在包含 Podfile 的目录中,运行 pod install --repo-update

  3. 打开 BasicExample.xcworkspace 文件,确认其中包含两个项目:BasicExamplePods(由 CocoaPods 安装的依赖项),以验证安装是否成功。

使用 Swift Package Manager 安装 SDK

互动式媒体广告 SDK 支持 4.8.2 及更高版本的 Swift Package Manager。请按照以下步骤导入 Swift 软件包。

  1. 在 Xcode 中,依次前往“File”(文件)>“Add Packages…”(添加软件包…),安装 IMA SDK Swift 软件包。

  2. 在显示的提示中,搜索 IMA SDK Swift 软件包的 GitHub 代码库:

    https://github.com/googleads/swift-package-manager-google-interactive-media-ads-tvos
    
  3. 选择您要使用的 IMA SDK Swift 软件包版本。 对于新项目,我们建议使用 Up to Next Major Version

完成之后,Xcode 会解析您的软件包依赖项,并在后台下载它们。如需详细了解如何添加软件包依赖项,请参阅 Apple 的文章

手动下载并安装 SDK

如果您不想使用 CocoaPods,可以下载 IMA SDK 并手动将其添加到项目中。

3. 创建简单的视频播放器

首先,实现一个基本的视频播放器。最初,此播放器不使用 IMA SDK,并且尚未包含任何用于触发播放的方法。

ViewController.m

Objective-C

#import "ViewController.h"

#import <AVKit/AVKit.h>

NSString *const kContentURLString =
    @"https://storage.googleapis.com/interactive-media-ads/media/stock.mp4";

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

@implementation ViewController

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

- (void)setupContentPlayer {
  // Create a content video player.
  NSURL *contentURL = [NSURL URLWithString:kContentURLString];
  AVPlayer *player = [AVPlayer playerWithURL:contentURL];
  self.contentPlayerViewController = [[AVPlayerViewController alloc] init];
  self.contentPlayerViewController.player = player;
  self.contentPlayerViewController.view.frame = self.view.bounds;

  // Attach content video player to view hierarchy.
  [self showContentPlayer];
}

// Add the content video player as a child view controller.
- (void)showContentPlayer {
  [self addChildViewController:self.contentPlayerViewController];
  self.contentPlayerViewController.view.frame = self.view.bounds;
  [self.view insertSubview:self.contentPlayerViewController.view atIndex:0];
  [self.contentPlayerViewController didMoveToParentViewController:self];
}

// Remove and detach the content video player.
- (void)hideContentPlayer {
  // The whole controller needs to be detached so that it doesn't capture events from the remote.
  [self.contentPlayerViewController willMoveToParentViewController:nil];
  [self.contentPlayerViewController.view removeFromSuperview];
  [self.contentPlayerViewController removeFromParentViewController];
}

@end
      

Swift

import AVFoundation
import UIKit

class ViewController: UIViewController {
  static let ContentURLString = "https://storage.googleapis.com/interactive-media-ads/media/stock.mp4"

  var playerViewController: AVPlayerViewController!

  override func viewDidLoad() {
    super.viewDidLoad()
    self.view.backgroundColor = UIColor.black;
    setUpContentPlayer()
  }

  func setUpContentPlayer() {
    // Load AVPlayer with path to your content.
    let contentURL! = URL(string: ViewController.ContentURLString)
    let player = AVPlayer(url: contentURL)
    playerViewController = AVPlayerViewController()
    playerViewController.player = player

    showContentPlayer()
  }

  func showContentPlayer() {
    self.addChild(playerViewController)
    playerViewController.view.frame = self.view.bounds
    self.view.insertSubview(playerViewController.view, at: 0)
    playerViewController.didMove(toParent:self)
  }

  func hideContentPlayer() {
    // The whole controller needs to be detached so that it doesn't capture  events from the remote.
    playerViewController.willMove(toParent:nil)
    playerViewController.view.removeFromSuperview()
    playerViewController.removeFromParent()
  }
}
      

4. 导入 IMA SDK

接下来,使用 import 语句在现有 import 下方添加 IMA 框架。

ViewController.m

Objective-C

#import "ViewController.h"

#import <AVKit/AVKit.h>
#import <GoogleInteractiveMediaAds/GoogleInteractiveMediaAds.h>
NSString *const kContentURLString =
    @"https://storage.googleapis.com/interactive-media-ads/media/stock.mp4";
      

Swift

import AVFoundation
import GoogleInteractiveMediaAds
import UIKit

class ViewController: UIViewController {
  static let ContentURLString = "https://storage.googleapis.com/interactive-media-ads/media/stock.mp4"
      

5. 实现内容播放头跟踪器和流结束观察器

为了播放中贴片广告,IMA SDK 需要跟踪视频内容的当前位置。为此,请创建一个实现 IMAContentPlayhead 的类。如果您使用的是 AVPlayer(如本示例所示),SDK 会提供 IMAAVPlayerContentPlayhead 类,该类可为您执行此操作。如果您未使用 AVPlayer,则需要在自己的类中实现 IMAContentPlayhead

您还需要告知 SDK 内容何时播放完毕,以便 SDK 可以展示后贴片广告。这是通过使用 AVPlayerItemDidPlayToEndTimeNotificationIMAAdsLoader 调用 contentComplete 来实现的。

ViewController.m

Objective-C

...

@interface ViewController ()
@property(nonatomic) IMAAVPlayerContentPlayhead *contentPlayhead;
@property(nonatomic) AVPlayerViewController *contentPlayerViewController;
@end

...

- (void)setupContentPlayer {
  // Create a content video player.
  NSURL *contentURL = [NSURL URLWithString:kContentURLString];
  AVPlayer *player = [AVPlayer playerWithURL:contentURL];
  self.contentPlayerViewController = [[AVPlayerViewController alloc] init];
  self.contentPlayerViewController.player = player;
  self.contentPlayerViewController.view.frame = self.view.bounds;
  self.contentPlayhead =
      [[IMAAVPlayerContentPlayhead alloc] initWithAVPlayer:self.contentPlayerViewController.player];

  // Track end of content.
  AVPlayerItem *contentPlayerItem = self.contentPlayerViewController.player.currentItem;
  [NSNotificationCenter.defaultCenter addObserver:self
                                         selector:@selector(contentDidFinishPlaying:)
                                             name:AVPlayerItemDidPlayToEndTimeNotification
                                           object:contentPlayerItem];

  // Attach content video player to view hierarchy.
  [self showContentPlayer];
}

...

- (void)contentDidFinishPlaying:(NSNotification *)notification {}

- (void)dealloc {
  [NSNotificationCenter.defaultCenter removeObserver:self];
}

@end
      

Swift

...

class ViewController: UIViewController {
  static let ContentURLString = "https://storage.googleapis.com/interactive-media-ads/media/stock.mp4"

  var contentPlayhead: IMAAVPlayerContentPlayhead?
  var playerViewController: AVPlayerViewController!

  deinit {
    NotificationCenter.default.removeObserver(self)
  }

...

  func setUpContentPlayer() {
    // Load AVPlayer with path to your content.
    let contentURL! = URL(string: ViewController.ContentURLString)
    let player = AVPlayer(url: contentURL)
    playerViewController = AVPlayerViewController()
    playerViewController.player = player

    // Set up your content playhead and contentComplete callback.
    contentPlayhead = IMAAVPlayerContentPlayhead(avPlayer: player)
    NotificationCenter.default.addObserver(
      self,
      selector: #selector(ViewController.contentDidFinishPlaying(_:)),
      name: NSNotification.Name.AVPlayerItemDidPlayToEndTime,
      object: player.currentItem);

    showContentPlayer()
  }

...

  @objc func contentDidFinishPlaying(_ notification: Notification) {
    adsLoader.contentComplete()
  }
}
      

6. 初始化广告加载程序并发出广告请求

如需请求一组广告,您需要创建 IMAAdsLoader 实例。此加载器可用于处理与指定广告代码网址关联的 IMAAdsRequest 对象。

最佳做法是在应用的整个生命周期内仅维护一个 IMAAdsLoader 实例。如需发出其他广告请求,请创建一个新的 IMAAdsRequest 对象,但重复使用同一 IMAAdsLoader。如需了解详情,请参阅 IMA SDK 常见问题解答

ViewController.m

Objective-C

...

NSString *const kContentURLString =
    @"https://storage.googleapis.com/interactive-media-ads/media/stock.mp4";
NSString *const kAdTagURLString = @"https://pubads.g.doubleclick.net/gampad/ads?"
    @"iu=/21775744923/external/vmap_ad_samples&sz=640x480&"
    @"cust_params=sample_ar%3Dpremidpostlongpod&"
    @"ciu_szs=300x250&gdfp_req=1&ad_rule=1&output=vmap&unviewed_position_start=1&"
    @"env=vp&cmsid=496&vid=short_onecue&correlator=";

@interface ViewController ()
@property(nonatomic) IMAAdsLoader *adsLoader;
@property(nonatomic) IMAAVPlayerContentPlayhead *contentPlayhead;
@property(nonatomic) AVPlayerViewController *contentPlayerViewController;
@end

@implementation ViewController

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

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

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

- (void)requestAds {
  // Pass the main view as the container for ad display.
  IMAAdDisplayContainer *adDisplayContainer =
      [[IMAAdDisplayContainer alloc] initWithAdContainer:self.view];
  IMAAdsRequest *request = [[IMAAdsRequest alloc] initWithAdTagUrl:kAdTagURLString
                                                adDisplayContainer:adDisplayContainer
                                                   contentPlayhead:self.contentPlayhead
                                                       userContext:nil];
  [self.adsLoader requestAdsWithRequest:request];
}

...

- (void)contentDidFinishPlaying:(NSNotification *)notification {
  // Notify the SDK that the postrolls should be played.
  [self.adsLoader contentComplete];
}

...

@end
      

Swift

...

class ViewController: UIViewController {
  static let ContentURLString = "https://storage.googleapis.com/interactive-media-ads/media/stock.mp4"
  static let AdTagURLString = "https://pubads.g.doubleclick.net/gampad/ads?iu=/21775744923/external/single_ad_samples&sz=640x480&cust_params=sample_ct%3Dlinear&ciu_szs=300x250%2C728x90&gdfp_req=1&output=vast&unviewed_position_start=1&env=vp&correlator="

  var adsLoader: IMAAdsLoader!
  var contentPlayhead: IMAAVPlayerContentPlayhead?
  var playerViewController: AVPlayerViewController!

...

  override func viewDidLoad() {
    super.viewDidLoad()
    self.view.backgroundColor = UIColor.black;
    setUpContentPlayer()
    setUpAdsLoader()
  }

  override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated);
    requestAds()
  }

...

  func setUpAdsLoader() {
    adsLoader = IMAAdsLoader(settings: nil)
  }

  func requestAds() {
    // Create ad display container for ad rendering.
    let adDisplayContainer = IMAAdDisplayContainer(adContainer: self.view)
    // Create an ad request with your ad tag, display container, and optional user context.
    let request = IMAAdsRequest(
        adTagUrl: ViewController.AdTagURLString,
        adDisplayContainer: adDisplayContainer,
        contentPlayhead: contentPlayhead,
        userContext: nil)

    adsLoader.requestAds(with: request)
  }

  @objc func contentDidFinishPlaying(_ notification: Notification) {
    adsLoader.contentComplete()
  }
}
      

7. 设置广告加载程序代理

在成功加载事件中,IMAAdsLoader 会调用其分配的委托的 adsLoadedWithData 方法,并向其传递 IMAAdsManager 的实例。然后,您可以初始化广告管理器,该管理器会根据广告代码网址的响应加载各个广告。

此外,请务必处理加载过程中可能发生的任何错误。如果广告未加载,请确保媒体播放继续进行(不含广告),以免干扰用户体验。

ViewController.m

Objective-C

...

@interface ViewController () <IMAAdsLoaderDelegate>
@property(nonatomic) IMAAdsLoader *adsLoader;
@property(nonatomic) IMAAdsManager *adsManager;
@property(nonatomic) IMAAVPlayerContentPlayhead *contentPlayhead;
@property(nonatomic) AVPlayerViewController *contentPlayerViewController;
@end

@implementation ViewController

...

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

...

#pragma mark - IMAAdsLoaderDelegate

- (void)adsLoader:(IMAAdsLoader *)loader adsLoadedWithData:(IMAAdsLoadedData *)adsLoadedData {
  // Initialize and listen to the ads manager loaded for this request.
  self.adsManager = adsLoadedData.adsManager;
  [self.adsManager initializeWithAdsRenderingSettings:nil];
}

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

@end
      

Swift

...

class ViewController: UIViewController, IMAAdsLoaderDelegate {

...

  var adsLoader: IMAAdsLoader!
  var adsManager: IMAAdsManager!
  var contentPlayhead: IMAAVPlayerContentPlayhead?
  var playerViewController: AVPlayerViewController!

...

  func setUpAdsLoader() {
    adsLoader = IMAAdsLoader(settings: nil)
    adsLoader.delegate = self
  }

...

  // MARK: - IMAAdsLoaderDelegate

  func adsLoader(_ loader: IMAAdsLoader!, adsLoadedWith adsLoadedData: IMAAdsLoadedData!) {
    adsManager = adsLoadedData.adsManager
    adsManager.initialize(with: nil)
  }

  func adsLoader(_ loader: IMAAdsLoader!, failedWith adErrorData: IMAAdLoadingErrorData!) {
    print("Error loading ads: " + adErrorData.adError.message)
    showContentPlayer()
    playerViewController.player?.play()
  }
}
      

8. 设置广告管理器委托人

最后,为了管理事件和状态变化,广告管理器需要自己的委托。IMAAdManagerDelegate 具有处理广告事件和错误的方法,以及触发视频内容播放和暂停的方法。

开始播放

didReceiveAdEvent 方法可用于处理许多事件,但在此基本示例中,只需监听 LOADED 事件,以告知广告管理器开始播放内容和广告。

ViewController.m

Objective-C

@interface ViewController () <IMAAdsLoaderDelegate, IMAAdsManagerDelegate>

...

- (void)adsLoader:(IMAAdsLoader *)loader adsLoadedWithData:(IMAAdsLoadedData *)adsLoadedData {
  // Initialize and listen to the ads manager loaded for this request.
  self.adsManager = adsLoadedData.adsManager;
  self.adsManager.delegate = self;
  [self.adsManager initializeWithAdsRenderingSettings:nil];
}

...

#pragma mark - IMAAdsManagerDelegate

- (void)adsManager:(IMAAdsManager *)adsManager didReceiveAdEvent:(IMAAdEvent *)event {
  // Play each ad once it has loaded.
  if (event.type == kIMAAdEvent_LOADED) {
    [adsManager start];
  }
}

...
      

Swift

...

class ViewController: UIViewController, IMAAdsLoaderDelegate, IMAAdsManagerDelegate {

...

  func adsLoader(_ loader: IMAAdsLoader!, adsLoadedWith adsLoadedData: IMAAdsLoadedData!) {
    // Grab the instance of the IMAAdsManager and set yourself as the delegate.
    adsManager = adsLoadedData.adsManager
    adsManager.delegate = self
    adsManager.initialize(with: nil)
  }

...

  // MARK: - IMAAdsManagerDelegate

  func adsManager(_ adsManager: IMAAdsManager!, didReceive event: IMAAdEvent!) {
    // Play each ad once it has been loaded
    if event.type == IMAAdEventType.LOADED {
      adsManager.start()
    }
  }

...
      

处理错误

同时添加了广告错误的处理程序。如果发生错误(如上一步所示),请恢复内容播放。

ViewController.m

Objective-C

...

- (void)adsManager:(IMAAdsManager *)adsManager didReceiveAdError:(IMAAdError *)error {
  // Fall back to playing content.
  NSLog(@"AdsManager error: %@", error.message);
  [self showContentPlayer];
  [self.contentPlayerViewController.player play];
}
@end
      

Swift

...

  func adsManager(_ adsManager: IMAAdsManager!, didReceive error: IMAAdError!) {
    // Fall back to playing content
    print("AdsManager error: " + error.message)
    showContentPlayer()
    playerViewController.player?.play()
  }
      

触发播放和暂停事件

您需要实现的最后两个委托方法用于在 IMA SDK 请求时触发底层视频内容的播放和暂停事件。在需要时触发暂停和播放可防止用户在展示广告时错过部分视频内容。

ViewController.m

Objective-C

...

- (void)adsManagerDidRequestContentPause:(IMAAdsManager *)adsManager {
  // Pause the content for the SDK to play ads.
  [self.contentPlayerViewController.player pause];
  [self hideContentPlayer];
}

- (void)adsManagerDidRequestContentResume:(IMAAdsManager *)adsManager {
  // Resume the content since the SDK is done playing ads (at least for now).
  [self showContentPlayer];
  [self.contentPlayerViewController.player play];
}

@end
      

Swift

...

  func adsManagerDidRequestContentPause(_ adsManager: IMAAdsManager!) {
    // Pause the content for the SDK to play ads.
    playerViewController.player?.pause()
    hideContentPlayer()
  }

  func adsManagerDidRequestContentResume(_ adsManager: IMAAdsManager!) {
    // Resume the content since the SDK is done playing ads (at least for now).
    showContentPlayer()
    playerViewController.player?.play()
  }
}
      

大功告成!您现在可以使用 IMA SDK 请求和展示广告了。如需了解其他 SDK 功能,请参阅其他指南或 GitHub 上的示例

后续步骤

为了最大限度地提高 tvOS 平台上的广告收入,请请求应用透明度和跟踪权限以使用 IDFA