開始使用 IMA DAI SDK

使用 IMA SDK,您就能輕鬆地將多媒體廣告整合至網站和應用程式。IMA SDK 可以 向任何 符合 VAST 規定的廣告伺服器請求廣告,並管理應用程式中的廣告播放情形。透過 IMA DAI SDK,應用程式會針對 VOD 或直播內容,對廣告和內容影片發出串流請求。接著,SDK 會傳回合併的影片串流,這樣您無須管理應用程式內的廣告和內容影片切換作業。

選取感興趣的 DAI 解決方案

完整服務 DAI

本指南說明如何將 IMA DAI SDK 整合至簡易的影片播放器應用程式。如果您想查看或執行完整的整合範例,請從 GitHub 下載 BasicExample

IMA DAI 總覽

導入 IMA DAI 涉及四個主要 SDK 元件,如本指南所示:

  • IMAAdDisplayContainer: 位於影片播放元素上方的容器物件,且包含廣告 UI 元素。
  • IMAAdsLoader:這個物件會要求串流及處理串流要求回應物件觸發的事件。您只能將一個廣告載入器例項化,以便在應用程式的整個生命週期中重複使用。
  • IMAStreamRequest IMAVODStreamRequest IMALiveStreamRequest:定義串流要求的物件。串流要求可以是隨選影片或直播。要求會指定內容 ID、API 金鑰或驗證權杖和其他參數。
  • IMAStreamManager:這個物件會處理動態廣告插播串流,以及與 DAI 後端的互動。串流管理員也會處理追蹤連線偵測 (ping),並將串流和廣告事件轉送至發布商。

必要條件

開始之前,您需要擁有下列項目:

建立新的 Xcode 專案

在 Xcode 中,使用 Objective-C 建立新的 iOS 專案。使用 BasicExample 做為專案名稱。

在 Xcode 專案中加入 IMA DAI SDK

使用這三種方法之一安裝 IMA DAI SDK。

使用 CocoaPods 安裝 SDK (建議做法)

CocoaPods 是 Xcode 專案的依附元件管理工具,也是安裝 IMA DAI SDK 的建議方法。如要進一步瞭解如何安裝或使用 CocoaPods,請參閱 CocoaPods 說明文件。安裝 CocoaPods 後,請按照下列操作說明安裝 IMA DAI SDK:

  1. 在與 BasicExample.xcodeproj 檔案相同的目錄中,建立名為 Podfile 的文字檔案,然後新增下列設定:

    source 'https://github.com/CocoaPods/Specs.git'
    platform :ios, '14'
    target "BasicExample" do
      pod 'GoogleAds-IMA-iOS-SDK', '~> 3.22.1'
    end
    
  2. 從包含 Podfile 的目錄執行下列指令:

    pod install --repo-update`
    
  3. 開啟 BasicExample.xcworkspace 檔案,並確認其包含兩個專案,確認安裝成功:BasicExamplePods (CocoaPods 安裝的依附元件)。

使用 Swift Package Manager 安裝 SDK

自 3.18.4 版起,互動式媒體廣告 SDK 支援 Swift Package Manager。請按照下列步驟匯入 Swift 套件。

  1. 在 Xcode 中依序前往「File」>「Add Packages」,安裝 IMA DAI SDK Swift 套件。

  2. 在出現的提示中,搜尋 IMA DAI SDK Swift 套件 GitHub 存放區:

    https://github.com/googleads/swift-package-manager-google-interactive-media-ads-ios
    
  3. 選取您要使用的 IMA DAI SDK Swift 套件版本。如果是新專案,建議使用「最高到下一個主要版本」。

完成後,Xcode 會解析套件依附元件,並在背景下載依附元件。如要進一步瞭解如何新增套件依附元件,請參閱 Apple 的文章

手動下載並安裝 SDK

如果不想使用 Swift Package Manager 或 CocoaPods,可以下載 IMA DAI SDK,並手動將其新增至專案中。

建立簡易的影片播放器

首先,導入基本影片播放器一開始,這個播放器不會使用 IMA DAI SDK,也不含任何觸發播放方法。

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

匯入 SDK 並新增 IMA 互動虛設常式

在專案中加入 IMA DAI SDK 後,請匯入 SDK 並新增虛設常式的 IMA 互動點。

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

導入 IMAAdsLoader

接著,將 IMAAdsLoader 例項化,並將廣告容器檢視畫面附加到檢視區塊階層。

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;
}

建立串流要求

建立幾個常數來保留串流資訊,然後實作串流要求函式發出要求。

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];
}

處理串流事件

用於處理串流狀態的初始化、錯誤和變更的 IMAAdsLoaderIMAStreamManager 觸發事件。這些事件會透過 IMAAdsLoaderDelegateIMAStreamManagerDelegate 通訊協定觸發。監聽已載入的廣告事件,並初始化串流。如果廣告無法載入,請改為播放備份串流。

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

處理記錄和錯誤事件

串流管理員委派項目可處理多個事件,但就基本實作而言,最重要的用途是執行事件記錄、避免在廣告播放時執行搜尋動作,以及處理錯誤。

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

大功告成!您正在使用 IMA DAI SDK 請求及顯示廣告。如要進一步瞭解更進階的 SDK 功能,請參閱其他指南或 GitHub 範例