借助 IMA SDK,您可以轻松地将多媒体广告集成到网站和应用中。IMA SDK 可以从任何 符合 VAST 标准的广告服务器请求广告,并在您的应用中管理广告播放。借助 IMA 客户端 SDK,您可以继续控制内容视频播放,而 SDK 则负责处理广告播放。广告在位于应用内容视频播放器顶部的单独视频播放器中播放。
本指南演示了如何将 IMA SDK 集成到视频播放器应用中。如果您想查看或跟随完成的示例集成,请从 GitHub 下载 BasicExample。
IMA 客户端概览
实现 IMA 客户端涉及四个主要 SDK 组件,本指南将对此进行演示:
IMAAdDisplayContainer:一种容器对象,用于指定 IMA 呈现广告界面元素和衡量可见率(包括 Active View 和 Open Measurement)的位置。IMAAdsLoader: 用于请求广告并处理广告请求响应中的事件的对象。您只需实例化一个广告加载程序,该加载程序可在整个应用生命周期内重复使用。IMAAdsRequest: 用于定义广告请求的对象。广告请求会指定 VAST 广告代码的网址以及其他参数(例如广告尺寸)。IMAAdsManager: 一个包含广告请求响应、控制广告播放并监听 SDK 触发的广告事件的对象。
前提条件
在开始之前,您需要做好以下准备:
- Xcode 13 或更高版本
- Swift Package Manager、CocoaPods 或下载的 IMA SDK for tvOS 副本
1. 创建新的 Xcode 项目
在 Xcode 中,使用 Objective-C 或 Swift 创建新的 tvOS 项目。使用 BasicExample 作为项目名称。
2. 将 IMA SDK 添加到 Xcode 项目
使用 Swift Package Manager 安装 IMA SDK
互动式媒体广告 SDK 支持 4.8.2 及更高版本的 Swift Package Manager。请按照以下步骤导入 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
如果您不想使用 CocoaPods,可以下载 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 需要跟踪视频内容的当前位置。为此,请创建一个实现 IMAContentPlayhead 的类。如果您使用的是 AVPlayer(如本示例所示),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()
}
您还需要告知 SDK 内容何时播放完毕,以便 SDK 可以展示后贴片广告。这是通过使用 AVPlayerItemDidPlayToEndTimeNotification 对 IMAAdsLoader 调用 contentComplete 来实现的。
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 的实例。然后,您可以初始化广告管理器,该管理器会根据广告代码网址的响应加载各个广告。
此外,请务必处理加载过程中可能发生的任何错误。如果广告未加载,请确保媒体播放继续进行(不含广告),以免干扰用户体验。
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 方法可用于处理多种事件。
在此基本示例中,监听 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 请求时触发底层视频内容上的播放和暂停事件。在需要时触发暂停和播放可防止用户在展示广告时错过部分视频内容。
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。