借助 IMA SDK,您可以轻松地将多媒体广告集成到网站和应用中。IMA SDK 可以 从任何 符合 VAST 标准的广告服务器请求广告,并管理应用中的广告播放。借助 IMA 客户端 SDK, 您可以控制内容视频播放,而 SDK 则负责处理广告播放。广告会在应用的内容视频播放器上方的单独视频播放器中播放。
本指南演示了如何将 IMA SDK 集成到视频播放器 应用中。如需查看或了解已完成的示例 集成,请从 BasicExample下载 BasicExample。
IMA 客户端概览
植入 IMA 客户端涉及四个主要 SDK 组件。本指南将演示这些组件:
IMAAdDisplayContainer: 一个容器对象,用于指定 IMA 在何处呈现广告界面元素并衡量可见度, 包括 Active View 和 开放式衡量。IMAAdsLoader: 一个对象,用于请求广告并处理广告请求响应中的事件。您应该只实例化一个广告加载程序,该加载程序可以在应用的整个生命周期内重复使用。IMAAdsRequest: 一个用于定义广告请求的对象。广告请求会指定 VAST 广告代码的网址,以及其他参数,例如广告尺寸。IMAAdsManager: 一个对象,用于包含对广告请求的响应、控制广告播放以及监听 SDK 触发的广告 事件。
前提条件
在开始之前,您需要做好以下准备:
- Xcode 13 或更高版本
- 安装 IMA SDK 的方法:
- 首选:Swift Package Manager
- CocoaPods
- IMA SDK for tvOS 的下载副本
1. 创建新的 Xcode 项目
在 Xcode 中,使用 Objective-C 或 Swift 创建新的 tvOS 项目。使用 BasicExample 作为项目名称。
2. 将 IMA SDK 添加到 Xcode 项目
如需安装 IMA SDK,请选择首选方法。
推荐:使用 Swift Package Manager 安装 IMA SDK
互动式媒体广告 SDK 支持 Swift Package Manager 4.8.2 及更高版本。请按照以下步骤导入 Swift 软件包。
在 Xcode 中,依次转到 File > Add Packages... ,安装 IMA SDK Swift 软件包。
在出现的提示中,搜索 IMA SDK Swift 软件包的 GitHub 代码库:
https://github.com/googleads/swift-package-manager-google-interactive-media-ads-tvos选择您要使用的 IMA SDK Swift 软件包版本。 对于新项目,我们建议使用 Up to Next Major Version (更新至下一主要版本前的最新版)规则。
完成之后,Xcode 会解析您的软件包依赖项,并在后台下载它们。如需详细了解如何添加软件包 依赖项,请参阅 Apple 的文章。
使用 CocoaPods 安装 IMA SDK
如需安装 IMA SDK,请使用 CocoaPods。如需详细了解如何安装或使用 CocoaPods,请参阅 CocoaPods 文档。安装 CocoaPods 后,请执行以下操作:
在 BasicExample.xcodeproj 文件所在的同一目录下,创建一个名为 Podfile 的文本 文件,并添加以下配置:
source 'https://github.com/CocoaPods/Specs.git' platform :tvos, '15' target "BasicExample" do pod 'GoogleAds-IMA-tvOS-SDK', '~> 4.16.0' end在包含 Podfile 的目录中,运行
pod install --repo-update打开 BasicExample.xcworkspace 文件,确认其中包含两个项目:BasicExample 和 Pods (由 CocoaPods 安装的依赖项),以验证安装是否成功。
手动下载并安装 IMA SDK
如果您不想使用 Swift Package Manager,请下载 IMA SDK 并手动将其添加到您的项目中。
3. 导入 IMA SDK
使用 import 语句添加 IMA 框架。
Objective-C
#import "ViewController.h"
#import <AVKit/AVKit.h>
@import GoogleInteractiveMediaAds;
Swift
import AVFoundation
import GoogleInteractiveMediaAds
import UIKit
4. 创建视频播放器并集成 IMA SDK
以下示例初始化了 IMA SDK:
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 () <IMAAdsLoaderDelegate, IMAAdsManagerDelegate>
@property(nonatomic) IMAAdsLoader *adsLoader;
@property(nonatomic) IMAAdDisplayContainer *adDisplayContainer;
@property(nonatomic) IMAAdsManager *adsManager;
@property(nonatomic) IMAAVPlayerContentPlayhead *contentPlayhead;
@property(nonatomic) AVPlayerViewController *contentPlayerViewController;
@property(nonatomic, getter=isAdBreakActive) BOOL adBreakActive;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = [UIColor blackColor];
[self setupAdsLoader];
[self setupContentPlayer];
}
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
[self requestAds];
}
// 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 resume events from the
// remote and play content underneath the ad.
[self.contentPlayerViewController willMoveToParentViewController:nil];
[self.contentPlayerViewController.view removeFromSuperview];
[self.contentPlayerViewController removeFromParentViewController];
}
Swift
class ViewController: UIViewController, IMAAdsLoaderDelegate, IMAAdsManagerDelegate {
static let contentURLString =
"https://devstreaming-cdn.apple.com/videos/streaming/examples/"
+ "img_bipbop_adv_example_fmp4/master.m3u8"
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 adDisplayContainer: IMAAdDisplayContainer!
var adsManager: IMAAdsManager!
var contentPlayhead: IMAAVPlayerContentPlayhead?
var playerViewController: AVPlayerViewController!
var adBreakActive = false
deinit {
NotificationCenter.default.removeObserver(self)
}
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = UIColor.black
setUpContentPlayer()
setUpAdsLoader()
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
requestAds()
}
在此示例中,viewDidLoad() 会初始化 IMAAdsLoader,而 viewDidAppear() 会在视图可见后请求广告。辅助方法 showContentPlayer() 和 hideContentPlayer() 会在广告播放期间切换内容可见性。
此示例使用 adTagURLString 常量变量为广告请求定义 VAST 广告代码,并使用以下组件来管理 IMA SDK:
adsLoader:处理广告请求和响应。我们建议在应用的整个生命周期内使用单个实例。adDisplayContainer:指定用于呈现广告的视图。adsManager:管理广告播放并监听广告事件。contentPlayhead:跟踪内容进度以触发中贴片广告插播时间点。adBreakActive:指示广告插播时间点是否正在播放,以防止在广告插播时间点中搜索。
5. 实现内容播放头跟踪器和流结束观察器
如需播放中贴片广告,IMA SDK 必须跟踪视频内容的当前位置。如需将当前位置传递给 IMA,请创建一个实现 IMAContentPlayhead 的类。如果您使用 AVPlayer(如本示例
所示),IMA SDK 会提供 IMAAVPlayerContentPlayhead 类来为您传递当前
位置信息。如果您不使用 AVPlayer,请在您自己的类中实现 IMAContentPlayhead。
Objective-C
- (void)setupContentPlayer {
// Create a content video player. Create a playhead to track content progress so the SDK knows
// when to play ads in a VMAP playlist.
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];
}
Swift
func setUpContentPlayer() {
// Load AVPlayer with path to our content.
let contentURL = URL(string: ViewController.contentURLString)!
let player = AVPlayer(url: contentURL)
playerViewController = AVPlayerViewController()
playerViewController.player = player
// Set up our 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()
}
设置一个监听器,以便在内容结束时使用 AVPlayerItemDidPlayToEndTimeNotification 调用 IMAAdsLoader 上的 contentComplete。调用 contentComplete 可让 IMA SDK 知道您的内容何时播放完毕,以便显示后贴片广告。
Objective-C
- (void)contentDidFinishPlaying:(NSNotification *)notification {
// Notify the SDK that the postrolls should be played.
[self.adsLoader contentComplete];
}
- (void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
Swift
@objc func contentDidFinishPlaying(_ notification: Notification) {
adsLoader.contentComplete()
}
6. 初始化广告加载程序并发出广告请求
如需请求一组广告,请创建一个 IMAAdsLoader 实例。
此加载程序会处理与指定广告代码网址关联的 IMAAdsRequest 对象。
最佳做法是,在应用的整个生命周期内仅维护一个 IMAAdsLoader 实例。如需发出其他广告请求,请创建一个新的 IMAAdsRequest 对象,但重复使用同一个 IMAAdsLoader。如需了解更多
信息,请参阅IMA SDK 常见问题解答。
Objective-C
- (void)setupAdsLoader {
self.adsLoader = [[IMAAdsLoader alloc] init];
self.adsLoader.delegate = self;
}
- (void)requestAds {
// Pass the main view as the container for ad display.
self.adDisplayContainer = [[IMAAdDisplayContainer alloc] initWithAdContainer:self.view
viewController:self];
IMAAdsRequest *request = [[IMAAdsRequest alloc] initWithAdTagUrl:kAdTagURLString
adDisplayContainer:self.adDisplayContainer
contentPlayhead:self.contentPlayhead
userContext:nil];
[self.adsLoader requestAdsWithRequest:request];
}
Swift
func setUpAdsLoader() {
adsLoader = IMAAdsLoader(settings: nil)
adsLoader.delegate = self
}
func requestAds() {
// Create ad display container for ad rendering.
adDisplayContainer = IMAAdDisplayContainer(adContainer: self.view, viewController: self)
// Create an ad request with our ad tag, display container, and optional user context.
let request = IMAAdsRequest(
adTagUrl: ViewController.adTagURLString,
adDisplayContainer: adDisplayContainer,
contentPlayhead: contentPlayhead,
userContext: nil)
adsLoader.requestAds(with: request)
}
7. 设置广告加载程序代理
在成功加载事件时,IMAAdsLoader 会调用其分配的代理的 adsLoadedWithData 方法,并向其传递 IMAAdsManager 的实例。获得 IMAAdsManager 实例后,初始化广告管理器,该管理器会根据广告代码网址的响应加载各个广告。
对于不成功的加载事件,请设置 IMAAdsLoader 代理来处理加载过程中发生的错误。如果广告未加载,请确保媒体播放在没有广告的情况下继续,以便用户查看媒体内容。
Objective-C
#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.delegate = self;
[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];
}
Swift
func adsLoader(_ loader: IMAAdsLoader, adsLoadedWith adsLoadedData: IMAAdsLoadedData) {
// Grab the instance of the IMAAdsManager and set ourselves as the delegate.
adsManager = adsLoadedData.adsManager
adsManager.delegate = self
adsManager.initialize(with: nil)
}
func adsLoader(_ loader: IMAAdsLoader, failedWith adErrorData: IMAAdLoadingErrorData) {
print("Error loading ads: \(adErrorData.adError.message ?? "No error message available.")")
showContentPlayer()
playerViewController.player?.play()
}
8. 设置广告管理器受托人
最后,如需管理事件和状态更改,广告管理器需要自己的委托。IMAAdManagerDelegate 具有用于处理广告事件和错误的方法,以及用于触发视频内容播放和暂停的方法。
开始播放
didReceiveAdEvent 方法会处理所有 IMAAdEvent 事件。对于此基本示例,请监听 LOADED 事件,以告知广告管理器开始播放内容和广告。当用户点按图标后关闭图标回退对话框时,IMA SDK 会触发 ICON_FALLBACK_IMAGE_CLOSED 事件。此操作后,广告播放会恢复。
Objective-C
#pragma mark - IMAAdsManagerDelegate
- (void)adsManager:(IMAAdsManager *)adsManager didReceiveAdEvent:(IMAAdEvent *)event {
switch (event.type) {
case kIMAAdEvent_LOADED: {
// Play each ad once it has loaded.
[adsManager start];
break;
}
case kIMAAdEvent_ICON_FALLBACK_IMAGE_CLOSED: {
// Resume ad after user has closed dialog.
[adsManager resume];
break;
}
default:
break;
}
}
Swift
func adsManager(_ adsManager: IMAAdsManager, didReceive event: IMAAdEvent) {
switch event.type {
case IMAAdEventType.LOADED:
// Play each ad once it has been loaded.
adsManager.start()
case IMAAdEventType.ICON_FALLBACK_IMAGE_CLOSED:
// Resume playback after the user has closed the dialog.
adsManager.resume()
default:
break
}
}
处理错误
同时添加广告错误的处理程序。如果发生错误(如上一步所示),请恢复内容播放。
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];
}
Swift
func adsManager(_ adsManager: IMAAdsManager, didReceive error: IMAAdError) {
// Fall back to playing content
print("AdsManager error: \(error.message ?? "No error message available.")")
showContentPlayer()
playerViewController.player?.play()
}
触发播放和暂停事件
您实现的最后两个代理方法会在 IMA SDK 请求时触发底层视频内容的播放和暂停事件。在 IMA SDK 请求时触发暂停和播放,可防止用户在广告展示时错过部分视频内容。
Objective-C
- (void)adsManagerDidRequestContentPause:(IMAAdsManager *)adsManager {
// Pause the content for the SDK to play ads.
[self.contentPlayerViewController.player pause];
[self hideContentPlayer];
// Trigger an update to send focus to the ad display container.
self.adBreakActive = YES;
[self setNeedsFocusUpdate];
}
- (void)adsManagerDidRequestContentResume:(IMAAdsManager *)adsManager {
// Resume the content since the SDK is done playing ads (at least for now).
[self showContentPlayer];
[self.contentPlayerViewController.player play];
// Trigger an update to send focus to the content player.
self.adBreakActive = NO;
[self setNeedsFocusUpdate];
}
Swift
func adsManagerDidRequestContentPause(_ adsManager: IMAAdsManager) {
// Pause the content for the SDK to play ads.
playerViewController.player?.pause()
hideContentPlayer()
// Trigger an update to send focus to the ad display container.
adBreakActive = true
setNeedsFocusUpdate()
}
func adsManagerDidRequestContentResume(_ adsManager: IMAAdsManager) {
// Resume the content since the SDK is done playing ads (at least for now).
showContentPlayer()
playerViewController.player?.play()
// Trigger an update to send focus to the content player.
adBreakActive = false
setNeedsFocusUpdate()
}
大功告成!您现在可以使用 IMA SDK 请求和展示广告了。如需了解 其他 SDK 功能,请参阅其他指南或 GitHub 上的示例。
后续步骤
如需最大限度地提高 tvOS 平台上的广告收入,请请求应用透明度和跟踪权限以使用 IDFA。