מתחילים

ערכות ה-SDK של IMA מאפשרות לשלב בקלות מודעות מולטימדיה באתרים ובאפליקציות. ערכות ה-SDK של IMA יכולות לבקש מודעות מכל שרת מודעות שתואם ל-VAST ולנהל את ההפעלה של המודעות באפליקציות. באמצעות ערכות SDK של IMA בצד הלקוח, אתם שומרים על השליטה בהפעלת הסרטונים של התוכן, בעוד ש-SDK מטפל בהפעלת המודעות. המודעות מופעלות בנגן וידאו נפרד שממוקם מעל נגן הווידאו של התוכן באפליקציה.

המדריך הזה מראה איך לשלב את IMA SDK באפליקציית נגן וידאו פשוטה. אם אתם רוצים לראות או להיעזר בשילוב לדוגמה שכבר הושלם, תוכלו להוריד את BasicExample מ-GitHub.

סקירה כללית על IMA מצד הלקוח

הטמעת IMA בצד הלקוח כוללת ארבעה רכיבים עיקריים של SDK, שמתוארים במדריך הזה:

  • IMAAdDisplayContainer: אובייקט מאגר שבו המודעות מוצגות.
  • IMAAdsLoader: אובייקט שמבקש מודעות ומטפל באירועים מתשובות לבקשות להצגת מודעות. צריך ליצור רק אובייקט אחד של Ads Loader, שאפשר להשתמש בו שוב במהלך חיי האפליקציה.
  • IMAAdsRequest: אובייקט שמגדיר בקשת מודעות. בבקשות להצגת מודעות מצוינות כתובת ה-URL של תג המודעה מסוג VAST, וגם פרמטרים נוספים, כמו המאפיינים של המודעה.
  • IMAAdsManager: אובייקט שמכיל את התגובה לבקשת המודעות, שולט בהפעלת המודעות ומקשיב לאירועי מודעות שמופעל על ידי ה-SDK.

דרישות מוקדמות

לפני שמתחילים, צריך את הדברים הבאים:

  • Xcode מגרסה 13 ואילך
  • CocoaPods (מועדף), Swift Package Manager או עותק שהורדתם של IMA SDK for tvOS

1. יצירת פרויקט חדש ב-Xcode

יוצרים פרויקט tvOS חדש ב-Xcode באמצעות Objective-C או Swift. נותנים לפרויקט את השם BasicExample.

2. הוספת IMA SDK לפרויקט Xcode

התקנת ה-SDK באמצעות CocoaPods (האפשרות המועדפת)

CocoaPods הוא מנהל יחסי תלות לפרויקטים ב-Xcode, והוא השיטה המומלצת להתקנת IMA SDK. מידע נוסף על התקנה או שימוש ב-CocoaPods זמין במסמכי העזרה של CocoaPods. אחרי שתתקינו את CocoaPods, תוכלו להשתמש בהוראות הבאות כדי להתקין את IMA SDK:

  1. באותה ספרייה שבה נמצא הקובץ 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
    
  2. בספרייה שמכילה את Podfile, מריצים את הפקודה pod install --repo-update

  3. כדי לוודא שההתקנה בוצעה בהצלחה, פותחים את הקובץ BasicExample.xcworkspace ומוודאים שהוא מכיל שני פרויקטים: BasicExample ו-Pods (היחסי התלות שהותקנו על ידי CocoaPods).

התקנת ה-SDK באמצעות Swift Package Manager

‏Interactive Media Ads SDK תומך ב-Swift Package Manager החל מגרסה 4.8.2. כדי לייבא את חבילת Swift, פועלים לפי השלבים הבאים.

  1. ב-Xcode, מתקינים את חבילת Swift של IMA SDK. לשם כך, עוברים אל File (קובץ) > Add Packages (הוספת חבילות)….

  2. בהנחיה שמופיעה, מחפשים את המאגר של IMA SDK Swift Package ב-GitHub:

    https://github.com/googleads/swift-package-manager-google-interactive-media-ads-tvos
    
  3. בוחרים את הגרסה של חבילת Swift של IMA SDK שבה רוצים להשתמש. בפרויקטים חדשים, מומלץ להשתמש באפשרות עד לגרסה הראשית הבאה.

בסיום, Xcode פותר את יחסי התלות בחבילות ומוריד אותן ברקע. למידע נוסף על הוספת יחסי תלות לחבילות, אפשר לעיין במאמר של Apple.

הורדה והתקנה ידניות של ה-SDK

אם אתם לא רוצים להשתמש ב-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/stock.mp4";

@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/stock.mp4"

  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/stock.mp4";
      

Swift

import AVFoundation
import GoogleInteractiveMediaAds
import UIKit

class ViewController: UIViewController {
  static let ContentURLString = "https://storage.googleapis.com/interactive-media-ads/media/stock.mp4"
      

5. הטמעת מעקב אחר פס ההפעלה של התוכן ומעקב אחר סיום הסטרימינג

כדי להציג מודעות באמצע הסרטון (mid-roll), מערכת IMA SDK צריכה לעקוב אחרי המיקום הנוכחי של תוכן הווידאו. כדי לעשות זאת, יוצרים כיתה שמטמיעה את IMAContentPlayhead. אם אתם משתמשים ב-AVPlayer, כפי שמוצג בדוגמה הזו, ה-SDK מספק את הכיתה IMAAVPlayerContentPlayhead שמבצעת את הפעולה הזו בשבילכם. אם אתם לא משתמשים ב-AVPlayer, תצטרכו להטמיע את IMAContentPlayhead בכיתה משלכם.

בנוסף, צריך להודיע ל-SDK מתי הסתיים הפעלת התוכן כדי שהוא יוכל להציג מודעות פוסט-רול. כדי לעשות זאת, קוראים ל-contentComplete ב-IMAAdsLoader באמצעות AVPlayerItemDidPlayToEndTimeNotification.

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://storage.googleapis.com/interactive-media-ads/media/stock.mp4"

  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 שמשויכים לכתובת URL של תג מודעה שצוינה.

מומלץ לשמור רק על מופע אחד של IMAAdsLoader לכל מחזור החיים של האפליקציה. כדי לשלוח בקשות נוספות להצגת מודעות, צריך ליצור אובייקט IMAAdsRequest חדש, אבל להשתמש שוב באותו IMAAdsLoader. מידע נוסף זמין בשאלות הנפוצות בנושא IMA SDK.

ViewController.m

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&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://storage.googleapis.com/interactive-media-ads/media/stock.mp4"
  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 your 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. לאחר מכן תוכלו לאתחל את מנהל המודעות, שיטמיע את המודעות הנפרדות, כפי שהוגדר בתגובה לכתובת ה-URL של תג המודעה.

בנוסף, חשוב לטפל בכל שגיאה שעלולה להתרחש במהלך תהליך הטעינה. אם המודעות לא נטענות, חשוב לוודא שההפעלה של המדיה ממשיכה, ללא מודעות, כדי לא להפריע לחוויית המשתמש.

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.

השלבים הבאים

כדי למקסם את ההכנסות מפרסום בפלטפורמת tvOS, צריך לבקש הרשאה לשימוש ב-IDFA במסגרת App Tracking Transparency.