借助 IMA SDK,您可以轻松将多媒体广告集成到您的网站和应用中。IMA SDK 可以从任何 与 VAST 兼容的广告服务器请求广告,并管理应用中的广告播放。借助 IMA DAI SDK,应用可以针对广告和内容视频(VOD 或直播内容)发出流式传输请求。然后,SDK 会返回一个合并的视频串流,这样您就不必在应用中管理广告视频和内容视频之间的切换。
选择您感兴趣的 DAI 解决方案
全方位 DAI
本指南介绍了如何将 IMA DAI SDK 集成到简单的视频播放器应用中。如果您想查看或跟随已完成的集成示例,请从 GitHub 下载 BasicExample。
IMA DAI 概览
实现 IMA DAI 涉及三个主要 SDK 组件,如本指南中所示:
IMAAdDisplayContainer
:位于视频播放元素之上并包含广告界面元素的容器对象。IMAAdsLoader
:请求数据流并处理由数据流请求响应对象触发的事件的对象。您应仅实例化一个广告加载器,该加载器可在应用的整个生命周期内重复使用。IMAStreamRequest
-IMAVODStreamRequest
或IMALiveStreamRequest
:用于定义数据流请求的对象。流式传输请求可以是视频点播或直播。请求中会指定内容 ID,以及 API 密钥或身份验证令牌和其他参数。IMAStreamManager
:一种对象,用于处理动态广告插播数据流以及与 DAI 后端的互动。直播管理器还会处理跟踪 ping,并将直播和广告事件转发给发布商。
前提条件
在开始之前,您需要做好以下准备:
- Xcode 13 或更高版本
- CocoaPods(首选)、Swift Package Manager 或适用于 tvOS 的 IMA DAI SDK 的下载副本
创建新的 Xcode 项目
在 Xcode 中,使用 Objective-C 创建一个新的 tvOS 项目。使用 BasicExample 作为项目名称。
将 IMA DAI SDK 添加到 Xcode 项目
您可以使用以下三种方法之一安装 IMA DAI SDK。
使用 CocoaPods 安装 SDK(首选)
CocoaPods 是 Xcode 项目的依赖项管理器,是安装 IMA DAI SDK 的推荐方法。如需详细了解如何安装或使用 CocoaPods,请参阅 CocoaPods 文档。安装 CocoaPods 后,请按照以下说明安装 IMA DAI SDK:
在 BasicExample.xcodeproj 文件所在的目录中,创建一个名为 Podfile 的文本文件,并添加以下配置:
source 'https://github.com/CocoaPods/Specs.git' platform :tvos, '14' target "BasicExample" do pod 'GoogleAds-IMA-tvOS-SDK', '~> 4.13.0' end
在包含 Podfile 的目录中,运行以下命令:
pod install --repo-update`
打开 BasicExample.xcworkspace 文件,并确认其中包含两个项目:BasicExample 和 Pods(CocoaPods 安装的依赖项),以验证安装是否成功。
使用 Swift Package Manager 安装 SDK
互动式媒体广告 SDK 4.8.2 及更高版本支持 Swift Package Manager。请按照以下步骤导入 Swift 软件包。
在 Xcode 中,依次前往 File(文件)> Add Packages(添加软件包),安装 GoogleInteractiveMediaAds Swift 软件包。
在显示的提示中,搜索 GoogleInteractiveMediaAds Swift 软件包的 GitHub 代码库:
https://github.com/googleads/swift-package-manager-google-interactive-media-ads-tvos
选择您要使用的 GoogleInteractiveMediaAds Swift 软件包版本。对于新项目,我们建议使用 Up to Next Major Version。
完成后,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];
}
处理数据流事件
IMAAdsLoader
和 IMAStreamManager
会触发事件,用于处理初始化、错误和串流状态变化。这些事件通过 IMAAdsLoaderDelegate
和 IMAStreamManagerDelegate
协议触发。监听广告加载事件并初始化数据流。如果广告加载失败,则改为播放备用直播。
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 上的示例。