利用 IMA SDK,您可以轻松地将多媒体广告集成到您的网站和应用中。IMA SDK 可以从任何 符合 VAST 标准的广告服务器请求广告,并管理您应用中的广告播放。使用 IMA 客户端 SDK 时,您可以控制内容视频播放,而由 SDK 处理广告播放。广告会在位于应用内容视频播放器之上的独立视频播放器中播放。
本指南演示了如何将 IMA SDK 集成到简单的视频播放器应用中。如果您想查看或遵循已完成的示例集成,请从 GitHub 下载 BasicExample。
IMA 客户端概览
实现 IMA 客户端涉及 4 个主要 SDK 组件,本指南对此进行了演示:
IMAAdDisplayContainer
:用于呈现广告的容器对象。IMAAdsLoader
: 用于请求广告并处理广告请求响应中的事件的对象。您应仅实例化一个广告加载器,该加载器可在应用的整个生命周期中重复使用。IMAAdsRequest
: 用于定义广告请求的对象。广告请求会指定 VAST 广告代码的网址以及其他参数,例如广告尺寸。IMAAdsManager
:一个对象,包含对广告请求的响应、控制广告播放以及监听 SDK 触发的广告事件。
前提条件
在开始之前,您需要做好以下准备:
- Xcode 13 或更高版本
- CocoaPods(首选)、Swift Package Manager,或已下载 IMA SDK for iOS 的副本
1. 创建一个新的 Xcode 项目
在 Xcode 中,使用 Objective-C 或 Swift 创建一个新的 iOS 项目。使用 BasicExample 作为项目名称。
2. 将 IMA SDK 添加到 Xcode 项目
使用 CocoaPods 安装 SDK(推荐)
CocoaPods 是 Xcode 项目的依赖项管理器,建议用来安装 IMA SDK。如需详细了解如何安装或使用 CocoaPods,请参阅 CocoaPods 文档。安装 CocoaPods 后,请按照以下说明安装 IMA SDK:
在 BasicExample.xcodeproj 文件所在的同一目录中,创建一个名为 Podfile 的文本文件,并添加以下配置:
source 'https://github.com/CocoaPods/Specs.git' platform :ios, '10' target "BasicExample" do pod 'GoogleAds-IMA-iOS-SDK', '~> 3.19.1' end
从包含 Podfile 的目录中,运行
pod install --repo-update
打开 BasicExample.xcworkspace 文件并确认其中包含两个项目,即 BasicExample 和 Pods(由 CocoaPods 安装的依赖项),验证安装是否成功。
使用 Swift Package Manager 安装 SDK
从版本 3.18.4 开始,互动式媒体广告 SDK 支持 Swift Package Manager。请按照以下步骤导入 Swift 软件包。
在 Xcode 中,依次点击 File(文件)> Add Packages...(添加软件包...)以安装 IMA SDK Swift 软件包。
在显示的提示中,搜索 IMA SDK Swift Package GitHub 代码库:
https://github.com/googleads/swift-package-manager-google-interactive-media-ads-ios
选择您要使用的 IMA SDK Swift 软件包版本。 对于新项目,我们建议使用 Up to Next Major Version。
完成之后,Xcode 会解析您的软件包依赖项,并在后台下载它们。如需详细了解如何添加软件包依赖项,请参阅 Apple 的文章。
手动下载并安装 SDK
如果您不想使用 Swift Package Manager 或 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/bipbop.m3u8"; @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/bipbop.m3u8" 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 语句添加 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/bipbop.m3u8";
Swift
import AVFoundation import GoogleInteractiveMediaAds import UIKit class ViewController: UIViewController { static let ContentURLString = "https://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/master.m3u8"
5. 实现内容进度条指针跟踪器和流式传输结束观察器
要播放中贴片广告,IMA SDK 需要跟踪视频内容的当前位置。为此,请创建一个实现 IMAContentPlayhead
的类。如果您使用的是 AVPlayer
(如本例所示),则 SDK 提供了 IMAAVPlayerContentPlayhead
类来为您执行此操作。如果您未使用 AVPlayer
,则需要在您自己的类上实现 IMAContentPlayhead
。
您还需要告知 SDK 内容播放完毕的时间,以便 SDK 可以展示后贴片广告。使用 AVPlayerItemDidPlayToEndTimeNotification
对 IMAAdsLoader
调用 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://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/master.m3u8" 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://devstreaming-cdn.apple.com/videos/streaming/examples/img_bipbop_adv_example_fmp4/" @"master.m3u8"; 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&impl=s&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://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&impl=s&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 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) } @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 上的示例。
后续步骤
若要最大限度提高 iOS 平台上的广告收入,您需要申请应用透明度和跟踪权限,以便使用 IDFA。