IMA SDK 可讓您輕鬆將多媒體廣告整合至網站和應用程式。IMA SDK 可從任何 符合 VAST 規定的廣告伺服器要求廣告,並管理您應用程式中的廣告播放。使用 IMA 用戶端 SDK 時,您可以控制內容影片播放,而 SDK 會處理廣告播放。廣告會在應用程式內容影片播放器上方的獨立影片播放器中播放。
本指南示範如何將 IMA SDK 整合到簡易的影片播放器應用程式中。如要查看或追蹤完成的整合範例,請從 GitHub 下載 BasicExample。
IMA 用戶端總覽
導入 IMA 用戶端時,共有四個主要 SDK 元件,如本指南所述:
IMAAdDisplayContainer
: 顯示廣告的容器物件。IMAAdsLoader
: 用於請求廣告及處理廣告請求回應事件的物件。您只應執行個體化一個廣告載入器,在應用程式的整個生命週期中都可以重複使用。IMAAdsRequest
: 定義廣告請求的物件。廣告請求會指定 VAST 廣告代碼的網址,以及廣告維度等其他參數。IMAAdsManager
:此物件包含廣告請求的回應、控制廣告播放,以及監聽 SDK 觸發的廣告事件。
必要條件
開始之前,請先備妥以下項目:
- Xcode 13 以上版本
- CocoaPods (建議)、Swift Package Manager,或 iOS 專用 IMA SDK 的下載副本
1. 建立新的 Xcode 專案
在 Xcode 中,使用 Objective-C 或 Swift 建立新的 iOS 專案。使用 BasicExample 做為專案名稱。
2. 在 Xcode 專案中加入 IMA SDK
使用 CocoaPods 安裝 SDK (建議做法)
CocoaPods 是 Xcode 專案的依附元件管理工具,也是安裝 IMA SDK 的建議方法。如要進一步瞭解如何安裝或使用 CocoaPods,請參閱 CocoaPods 說明文件。安裝 CocoaPods 後,請按照下列操作說明安裝 IMA SDK:
在與 BasicExample.xcodeproj 檔案相同的目錄中,建立名為 Podfile 的文字檔案,然後新增下列設定:
source 'https://github.com/CocoaPods/Specs.git' platform :ios, '14' target "BasicExample" do pod 'GoogleAds-IMA-iOS-SDK', '~> 3.19.1' end
從包含 Podfile 的目錄執行
pod install --repo-update
開啟 BasicExample.xcworkspace 檔案,並確認其中包含兩個專案:BasicExample 和 Pod (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 套件版本。 如果是新專案,建議您使用下一個主要版本。
完成後,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
接著,在現有匯入內容下方,使用匯入陳述式新增 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 知道內容播放完畢,才能顯示片尾廣告。方法是使用 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 平台上盡量提高廣告收益,請申請應用程式資訊公開和追蹤權限使用廣告識別碼。