הגדרת IMA SDK ל-DAI

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

בחירת פתרון ה-DAI הרצוי

שירות DAI מלא

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

סקירה כללית על הטמעת מודעות דינמיות (DAI) ב-IMA

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

  • IMAAdDisplayContainer – אובייקט קונטיינר שנמצא מעל אלמנט ההפעלה של הסרטון ומכיל את רכיבי ממשק המשתמש של המודעה.
  • IMAAdsLoader – אובייקט שמבקש שידורים ומטפל באירועים שמופעל על ידי אובייקטים של תגובות לבקשות של שידורים. צריך ליצור רק אובייקט אחד של Ads Loader, שאפשר להשתמש בו שוב במהלך חיי האפליקציה.
  • IMAStreamRequest – הערך יכול להיות IMAVODStreamRequest או IMALiveStreamRequest. אובייקט שמגדיר בקשת סטרימינג. בקשות הסטרימינג יכולות להיות לווידאו על פי דרישה או לשידורים חיים. בבקשות לשידור חי מצוין מפתח נכס, ובבקשות ל-VOD מצוין מזהה מערכת ניהול תוכן ומזהה סרטון. אפשר לכלול בשני סוגי הבקשות מפתח API שנחוץ כדי לגשת לסטרים מסוימים, וקוד רשת של Google Ad Manager כדי ש-IMA SDK יטפל במזהי המודעות כפי שצוין בהגדרות של Google Ad Manager.
  • IMAStreamManager – אובייקט שמטפל בזרמים של הטמעת מודעות דינמיות ובאינטראקציות עם הקצה העורפי של DAI. מנהל הסטרימינג מטפל גם בפניות מעקב (pings) ומעביר אירועי סטרימינג ומודעות לבעלי התוכן הדיגיטלי.

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

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

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

פרמטרים של שידורים חיים
מפתח נכס מפתח הנכס שמזהה את השידור החי ב-Google Ad Manager.
דוגמה: c-rArva4ShKVIAkNfy6HUQ
פרמטרים של שידורי VOD
מזהה של מקור התוכן מזהה מקור התוכן מ-Google Ad Manager.
דוגמה: 2548831
מזהה סרטון מזהה הסרטון מ-Google Ad Manager.
דוגמה: tears-of-steel
פרמטרים נפוצים (VOD ושידור חי)
קוד רשת הקוד של רשת Google Ad Manager.
דוגמה: 21775744923

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

ב-Xcode, יוצרים פרויקט iOS חדש באמצעות Objective-C בשם BasicExample.

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

אפשר להשתמש באחת משלוש השיטות הבאות כדי להתקין את IMA DAI SDK.

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

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

  1. באותה ספרייה שבה נמצא הקובץ BasicExample.xcodeproj, יוצרים קובץ טקסט בשם Podfile ומוסיפים את ההגדרות הבאות:

    source 'https://github.com/CocoaPods/Specs.git'
    
    platform :ios, '14'
    
    target 'BasicExample' do
      pod 'GoogleAds-IMA-iOS-SDK', '~> 3.26.1'
    end
    

  2. בתיקייה שמכילה את Podfile, מריצים את הפקודה:

    pod install --repo-update

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

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

  1. ב-Xcode, מתקינים את חבילת Swift של IMA DAI SDK. לשם כך, עוברים אל File > Add Packages.

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

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

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

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

אם אתם לא רוצים להשתמש ב-Swift Package Manager או ב-CocoaPods, תוכלו להוריד את IMA DAI SDK ולהוסיף אותו לפרויקט באופן ידני.

יצירת נגן וידאו פשוט

הטמעת נגן וידאו ב-View Controller הראשי באמצעות נגן AV שמקובץ בתצוגת UI. IMA SDK משתמש בתצוגת ממשק המשתמש כדי להציג רכיבי ממשק משתמש של מודעות.

Objective-C

#import "ViewController.h"

#import <AVKit/AVKit.h>

/// Content URL.
static NSString *const kBackupContentUrl =
    @"http://devimages.apple.com/iphone/samples/bipbop/bipbopall.m3u8";

@interface ViewController ()
/// Play button.
@property(nonatomic, weak) IBOutlet UIButton *playButton;

@property(nonatomic, weak) IBOutlet UIView *videoView;
/// Video player.
@property(nonatomic, strong) AVPlayer *videoPlayer;
@end

@implementation ViewController

- (void)viewDidLoad {
  [super viewDidLoad];
  self.view.backgroundColor = [UIColor blackColor];

  // Load AVPlayer with the path to your content.
  NSURL *contentURL = [NSURL URLWithString:kBackupContentUrl];
  self.videoPlayer = [AVPlayer playerWithURL:contentURL];

  // Create a player layer for the player.
  AVPlayerLayer *playerLayer = [AVPlayerLayer playerLayerWithPlayer:self.videoPlayer];

  // Size, position, and display the AVPlayer.
  playerLayer.frame = self.videoView.layer.bounds;
  [self.videoView.layer addSublayer:playerLayer];
}

- (IBAction)onPlayButtonTouch:(id)sender {
  [self.videoPlayer play];
  self.playButton.hidden = YES;
}

@end

Swift

// Copyright 2024 Google LLC. All rights reserved.
//
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this
// file except in compliance with the License. You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software distributed under
// the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
// ANY KIND, either express or implied. See the License for the specific language governing
// permissions and limitations under the License.

import AVFoundation
import UIKit

class ViewController: UIViewController {

  /// Content URL.
  static let backupStreamURLString =
    "http://devimages.apple.com/iphone/samples/bipbop/bipbopall.m3u8"

  /// Play button.
  @IBOutlet private weak var playButton: UIButton!

  @IBOutlet private weak var videoView: UIView!
  /// Video player.
  private var videoPlayer: AVPlayer?

  override func viewDidLoad() {
    super.viewDidLoad()

    playButton.layer.zPosition = CGFloat(MAXFLOAT)

    // Load AVPlayer with path to our content.
    // note: this unwrap is safe because the URL is a constant string.
    let contentURL = URL(string: ViewController.backupStreamURLString)!
    videoPlayer = AVPlayer(url: contentURL)

    // Create a player layer for the player.
    let playerLayer = AVPlayerLayer(player: videoPlayer)

    // Size, position, and display the AVPlayer.
    playerLayer.frame = videoView.layer.bounds
    videoView.layer.addSublayer(playerLayer)
  }

  @IBAction func onPlayButtonTouch(_ sender: Any) {
    videoPlayer?.play()
    playButton.isHidden = true
  }
}

איך מאתחלים את הטעינה של המודעות

מייבאים את IMA SDK למנהל התצוגה ומשתמשים בפרוטוקולים IMAAdsLoaderDelegate ו-IMAStreamManagerDelegate כדי לטפל באירועים של מנהל הסטרימינג ושל מערך המודעות.

מוסיפים את המאפיינים הפרטיים הבאים כדי לאחסן רכיבים מרכזיים של IMA SDK:

  • IMAAdsLoader – ניהול בקשות הסטרימינג במהלך כל תקופת הפעילות של האפליקציה.
  • IMAAdDisplayContainer – הקוד הזה מטפל בהוספה ובניהול של רכיבי ממשק המשתמש של מודעות.
  • IMAAVPlayerVideoDisplay – רכיב שמקשר בין IMA SDK לנגן המדיה ומטפל במטא-נתונים מתוזמנים.
  • IMAStreamManager – ניהול ההפעלה של הסטרימינג והפעלת אירועים שקשורים למודעות.

מאתחלים את מערך הטעינה של המודעות, את מאגר הצגת המודעות ואת תצוגת הסרטון אחרי שהתצוגה נטענת.

Objective-C

@import GoogleInteractiveMediaAds;

// ...

@interface ViewController () <IMAAdsLoaderDelegate, IMAStreamManagerDelegate>
/// The entry point for the IMA DAI SDK to make DAI stream requests.
@property(nonatomic, strong) IMAAdsLoader *adsLoader;
/// The container where the SDK renders each ad's user interface elements and companion slots.
@property(nonatomic, strong) IMAAdDisplayContainer *adDisplayContainer;
/// The reference of your video player for the IMA DAI SDK to monitor playback and handle timed
/// metadata.
@property(nonatomic, strong) IMAAVPlayerVideoDisplay *imaVideoDisplay;
/// References the stream manager from the IMA DAI SDK after successful stream loading.
@property(nonatomic, strong) IMAStreamManager *streamManager;

// ...

@end

@implementation ViewController

- (void)viewDidLoad {
  [super viewDidLoad];

  // ...

  self.adsLoader = [[IMAAdsLoader alloc] initWithSettings:nil];
  self.adsLoader.delegate = self;

  // Create an ad display container for rendering each ad's user interface elements and companion
  // slots.
  self.adDisplayContainer =
      [[IMAAdDisplayContainer alloc] initWithAdContainer:self.videoView
                                          viewController:self
                                          companionSlots:nil];

  // Create an IMAAVPlayerVideoDisplay to give the SDK access to your video player.
  self.imaVideoDisplay = [[IMAAVPlayerVideoDisplay alloc] initWithAVPlayer:self.videoPlayer];
}

Swift

import GoogleInteractiveMediaAds
// ...

class ViewController: UIViewController, IMAAdsLoaderDelegate, IMAStreamManagerDelegate {
  // ...

  /// The entry point for the IMA DAI SDK to make DAI stream requests.
  private var adsLoader: IMAAdsLoader?
  /// The container where the SDK renders each ad's user interface elements and companion slots.
  private var adDisplayContainer: IMAAdDisplayContainer?
  /// The reference of your video player for the IMA DAI SDK to monitor playback and handle timed
  /// metadata.
  private var imaVideoDisplay: IMAAVPlayerVideoDisplay!
  /// References the stream manager from the IMA DAI SDK after successfully loading the DAI stream.
  private var streamManager: IMAStreamManager?

  // ...

  override func viewDidLoad() {
    super.viewDidLoad()

    // ...

    adsLoader = IMAAdsLoader(settings: nil)
    adsLoader?.delegate = self

    // Create an ad display container for rendering ad UI elements and the companion ad.
    adDisplayContainer = IMAAdDisplayContainer(
      adContainer: videoView,
      viewController: self,
      companionSlots: nil)

    // Create an IMAAVPlayerVideoDisplay to give the SDK access to your video player.
    imaVideoDisplay = IMAAVPlayerVideoDisplay(avPlayer: videoPlayer)
  }

שליחת בקשה להעברת נתונים

כשמשתמש לוחץ על לחצן ההפעלה, שולחים בקשה חדשה לשידור. משתמשים ב-class‏ IMALiveStreamRequest לשידורים חיים. להעברות VOD, משתמשים במחלקה IMAVODStreamRequest.

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

Objective-C

- (IBAction)onPlayButtonTouch:(id)sender {
  [self requestStream];
  self.playButton.hidden = YES;
}

- (void)requestStream {
  // Create a stream request. Use one of "Live stream request" or "VOD request", depending on your
  // type of stream.
  IMAStreamRequest *request;
  if (kStreamType == StreamTypeLive) {
    // Live stream request. Replace the asset key with your value.
    request = [[IMALiveStreamRequest alloc] initWithAssetKey:kLiveStreamAssetKey
                                                 networkCode:kNetworkCode
                                          adDisplayContainer:self.adDisplayContainer
                                                videoDisplay:self.imaVideoDisplay
                                                 userContext:nil];
  } else {
    // VOD request. Replace the content source ID and video ID with your values.
    request = [[IMAVODStreamRequest alloc] initWithContentSourceID:kVODContentSourceID
                                                           videoID:kVODVideoID
                                                       networkCode:kNetworkCode
                                                adDisplayContainer:self.adDisplayContainer
                                                      videoDisplay:self.imaVideoDisplay
                                                       userContext:nil];
  }
  [self.adsLoader requestStreamWithRequest:request];
}

Swift

@IBAction func onPlayButtonTouch(_ sender: Any) {
  requestStream()
  playButton.isHidden = true
}

func requestStream() {
  // Create a stream request. Use one of "Livestream request" or "VOD request".
  if ViewController.requestType == StreamType.live {
    // Livestream request.
    let request = IMALiveStreamRequest(
      assetKey: ViewController.assetKey,
      networkCode: ViewController.networkCode,
      adDisplayContainer: adDisplayContainer!,
      videoDisplay: imaVideoDisplay,
      userContext: nil)
    adsLoader?.requestStream(with: request)
  } else {
    // VOD stream request.
    let request = IMAVODStreamRequest(
      contentSourceID: ViewController.contentSourceID,
      videoID: ViewController.videoID,
      networkCode: ViewController.networkCode,
      adDisplayContainer: adDisplayContainer!,
      videoDisplay: imaVideoDisplay,
      userContext: nil)
    adsLoader?.requestStream(with: request)
  }
}

האזנה לאירועי טעינה של שידורים

הכיתה IMAAdsLoader קורא לשיטות IMAAdsLoaderDelegate אם האתחול של בקשת הסטרימינג הצליח או נכשל.

בשיטת הענקת הגישה adsLoadedWithData, מגדירים את IMAStreamManagerDelegate. מאתחלים את מנהל הסטרימינג. בזמן האתחול, מנהל הסטרימינג מתחיל את ההפעלה.

מתעדים את השגיאה ביומן של שיטת הענקת הגישה failedWithErrorData. אפשר גם להפעיל את סטרימינג הגיבוי. שיטות מומלצות ל-DAI

Objective-C

- (void)adsLoader:(IMAAdsLoader *)loader adsLoadedWithData:(IMAAdsLoadedData *)adsLoadedData {
  NSLog(@"Stream created with: %@.", adsLoadedData.streamManager.streamId);
  self.streamManager = adsLoadedData.streamManager;
  self.streamManager.delegate = self;
  [self.streamManager initializeWithAdsRenderingSettings:nil];
}

- (void)adsLoader:(IMAAdsLoader *)loader failedWithErrorData:(IMAAdLoadingErrorData *)adErrorData {
  // Log the error and play the content.
  NSLog(@"AdsLoader error, code:%ld, message: %@", adErrorData.adError.code,
        adErrorData.adError.message);
  [self.videoPlayer play];
}

Swift

func adsLoader(_ loader: IMAAdsLoader, adsLoadedWith adsLoadedData: IMAAdsLoadedData) {
  print("DAI stream loaded. Stream session ID: \(adsLoadedData.streamManager!.streamId!)")
  streamManager = adsLoadedData.streamManager!
  streamManager!.delegate = self
  streamManager!.initialize(with: nil)
}

func adsLoader(_ loader: IMAAdsLoader, failedWith adErrorData: IMAAdLoadingErrorData) {
  print("Error loading DAI stream. Error message: \(adErrorData.adError.message!)")
  // Play the backup stream.
  videoPlayer.play()
}

האזנה לאירועים של מודעות

ה-IMAStreamManager קורא לשיטות IMAStreamManagerDelegate כדי להעביר לאפליקציה אירועים ושגיאות של סטרימינג.

בדוגמה הזו, מתעדים ביומן במסוף את אירועי המודעות הראשיים:

Objective-C

- (void)streamManager:(IMAStreamManager *)streamManager didReceiveAdEvent:(IMAAdEvent *)event {
  NSLog(@"Ad event (%@).", event.typeString);
  switch (event.type) {
    case kIMAAdEvent_STARTED: {
      // Log extended data.
      NSString *extendedAdPodInfo = [[NSString alloc]
          initWithFormat:@"Showing ad %ld/%ld, bumper: %@, title: %@, description: %@, contentType:"
                         @"%@, pod index: %ld, time offset: %lf, max duration: %lf.",
                         (long)event.ad.adPodInfo.adPosition, (long)event.ad.adPodInfo.totalAds,
                         event.ad.adPodInfo.isBumper ? @"YES" : @"NO", event.ad.adTitle,
                         event.ad.adDescription, event.ad.contentType,
                         (long)event.ad.adPodInfo.podIndex, event.ad.adPodInfo.timeOffset,
                         event.ad.adPodInfo.maxDuration];

      NSLog(@"%@", extendedAdPodInfo);
      break;
    }
    case kIMAAdEvent_AD_BREAK_STARTED: {
      NSLog(@"Ad break started");
      break;
    }
    case kIMAAdEvent_AD_BREAK_ENDED: {
      NSLog(@"Ad break ended");
      break;
    }
    case kIMAAdEvent_AD_PERIOD_STARTED: {
      NSLog(@"Ad period started");
      break;
    }
    case kIMAAdEvent_AD_PERIOD_ENDED: {
      NSLog(@"Ad period ended");
      break;
    }
    default:
      break;
  }
}

- (void)streamManager:(IMAStreamManager *)streamManager didReceiveAdError:(IMAAdError *)error {
  NSLog(@"StreamManager error with type: %ld\ncode: %ld\nmessage: %@", error.type, error.code,
        error.message);
  [self.videoPlayer play];
}

Swift

func streamManager(_ streamManager: IMAStreamManager, didReceive event: IMAAdEvent) {
  print("Ad event \(event.typeString).")
  switch event.type {
  case IMAAdEventType.STARTED:
    // Log extended data.
    if let ad = event.ad {
      let extendedAdPodInfo = String(
        format: "Showing ad %zd/%zd, bumper: %@, title: %@, "
          + "description: %@, contentType:%@, pod index: %zd, "
          + "time offset: %lf, max duration: %lf.",
        ad.adPodInfo.adPosition,
        ad.adPodInfo.totalAds,
        ad.adPodInfo.isBumper ? "YES" : "NO",
        ad.adTitle,
        ad.adDescription,
        ad.contentType,
        ad.adPodInfo.podIndex,
        ad.adPodInfo.timeOffset,
        ad.adPodInfo.maxDuration)

      print("\(extendedAdPodInfo)")
    }
    break
  case IMAAdEventType.AD_BREAK_STARTED:
    print("Ad break started.")
    break
  case IMAAdEventType.AD_BREAK_ENDED:
    print("Ad break ended.")
    break
  case IMAAdEventType.AD_PERIOD_STARTED:
    print("Ad period started.")
    break
  case IMAAdEventType.AD_PERIOD_ENDED:
    print("Ad period ended.")
    break
  default:
    break
  }
}

func streamManager(_ streamManager: IMAStreamManager, didReceive error: IMAAdError) {
  print("StreamManager error with type: \(error.type)")
  print("code: \(error.code)")
  print("message: \(error.message ?? "Unknown Error")")
}

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