DAI için IMA SDK'sını ayarlama

Platform seçin: HTML5 Android iOS tvOS Cast Roku

IMA SDK'ları, multimedya reklamları web sitelerinize ve uygulamalarınıza entegre etmeyi kolaylaştırır. IMA SDK'ları, herhangi bir VAST uyumlu reklam sunucusundan reklam isteğinde bulunabilir ve uygulamalarınızda reklam oynatmayı yönetebilir. IMA DAI SDK'ları ile uygulamalar, reklam ve içerik videosu için (VOD veya canlı içerik) bir akış isteğinde bulunur. SDK daha sonra birleşik bir video akışı döndürür. Böylece uygulamanızda reklam ve içerik videosu arasında geçiş yapmayı yönetmeniz gerekmez.

İlgilendiğiniz DAI çözümünü seçin

Tam kapsamlı DAI

Bu kılavuzda, IMA DAI SDK'nın basit bir video oynatıcı uygulamasına nasıl entegre edileceği gösterilmektedir. Tamamlanmış bir örnek entegrasyonu görüntülemek veya takip etmek isterseniz GitHub'dan BasicExample'ı indirin.

IMA DAI'ye genel bakış

IMA DAI'nin uygulanması, bu kılavuzda gösterildiği gibi üç ana SDK bileşenini içerir:

  • IMAAdDisplayContainer: Video oynatma öğesinin üzerinde bulunan ve reklam kullanıcı arayüzü öğelerini barındıran bir kapsayıcı nesne.
  • IMAAdsLoader: Akış isteyen ve akış isteği yanıt nesneleri tarafından tetiklenen etkinlikleri işleyen bir nesne. Yalnızca bir reklam yükleyici oluşturmanız gerekir. Bu yükleyici, uygulamanın kullanım ömrü boyunca yeniden kullanılabilir.
  • IMAStreamRequest IMAVODStreamRequest veya IMALiveStreamRequest: Bir akış isteğini tanımlayan nesne. Akış istekleri, seç-izle videolar veya canlı yayınlar için olabilir. Canlı yayın isteklerinde öğe anahtarı belirtilirken VOD isteklerinde CMS kimliği ve video kimliği belirtilir. Her iki istek türü de isteğe bağlı olarak, belirtilen akışlara erişmek için gereken bir API anahtarı ve IMA SDK'nın reklam tanımlayıcılarını Google Ad Manager ayarlarında belirtildiği şekilde işlemesi için bir Google Ad Manager ağ kodu içerebilir.
  • IMAStreamManager: Dinamik reklam ekleme akışlarını ve DAI arka ucuyla etkileşimleri işleyen bir nesne. Yayın yöneticisi, izleme ping'lerini de işler ve yayın ile reklam etkinliklerini yayıncıya yönlendirir.

Ön koşullar

Başlamadan önce aşağıdakilere ihtiyacınız vardır:

Yeni bir Xcode projesi oluşturma

Xcode'da Objective-C kullanarak yeni bir tvOS projesi oluşturun. Proje adı olarak BasicExample'ı kullanın.

IMA DAI SDK'sını Xcode projesine ekleme

IMA DAI SDK'yı yüklemek için bu üç yöntemden birini kullanın.

Swift Package Manager'ı kullanarak SDK'yı yükleme

Interactive Media Ads SDK'sı, 4.8.2 sürümünden itibaren Swift Package Manager'ı desteklemektedir. Swift paketini içe aktarmak için aşağıdaki adımları uygulayın.

  1. Xcode'da File > Add Packages (Dosya > Paket Ekle) seçeneğine giderek GoogleInteractiveMediaAds Swift Paketini yükleyin.

  2. Görüntülenen istemde GoogleInteractiveMediaAds Swift Package GitHub deposunu arayın:

    https://github.com/googleads/swift-package-manager-google-interactive-media-ads-tvos
    
  3. Kullanmak istediğiniz GoogleInteractiveMediaAds Swift Package sürümünü seçin. Yeni projeler için Bir Sonraki Ana Sürüme Kadar'ı kullanmanızı öneririz.

İşlemi tamamladığınızda Xcode, paket bağımlılıklarınıza çözüm bulur ve bunları arka planda indirir. Paket bağımlılıklarını ekleme hakkında daha fazla bilgi için Apple'ın makalesine göz atın.

SDK'yı CocoaPods kullanarak yükleme

CocoaPods, Xcode projeleri için bir bağımlı yöneticisidir ve IMA DAI SDK'yı yüklemek için önerilen yöntemdir. CocoaPods'u yükleme veya kullanma hakkında daha fazla bilgi için CocoaPods belgelerine bakın. CocoaPods'u yükledikten sonra IMA DAI SDK'yı yüklemek için aşağıdaki talimatları uygulayın:

  1. BasicExample.xcodeproj dosyanızla aynı dizinde Podfile adlı bir metin dosyası oluşturun ve aşağıdaki yapılandırmayı ekleyin:

    source 'https://github.com/CocoaPods/Specs.git'
    platform :tvos, '15'
    target "BasicExample" do
      pod 'GoogleAds-IMA-tvOS-SDK', '~> 4.16.0'
    end
    
  2. Podfile dosyasını içeren dizinden şunu çalıştırın:

    pod install --repo-update
  3. BasicExample.xcworkspace dosyasını açıp BasicExample ve Pods (CocoaPods tarafından yüklenen bağımlılar) olmak üzere iki proje içerdiğini doğrulayarak yüklemenin başarılı olduğunu onaylayın.

SDK'yı manuel olarak indirme ve yükleme

Swift Package Manager veya CocoaPods'u kullanmak istemiyorsanız IMA DAI SDK'yı indirip projenize manuel olarak ekleyebilirsiniz.

IMA SDK'sını içe aktarma

İçe aktarma ifadesini kullanarak IMA çerçevesini ekleyin:

Objective-C

#import "ViewController.h"
#import <AVKit/AVKit.h>

@import GoogleInteractiveMediaAds;

Swift

import AVFoundation
import GoogleInteractiveMediaAds
import UIKit

Video oynatıcı oluşturma ve IMA SDK'yı entegre etme

Aşağıdaki örnekte IMA SDK başlatılıyor:

Objective-C

// Live stream asset key, VOD content source and video IDs, and backup content URL.
static NSString *const kAssetKey = @"c-rArva4ShKVIAkNfy6HUQ";
static NSString *const kContentSourceID = @"2548831";
static NSString *const kVideoID = @"tears-of-steel";
static NSString *const kNetworkCode = @"21775744923";
static NSString *const kBackupStreamURLString =
    @"http://googleimadev-vh.akamaihd.net/i/big_buck_bunny/bbb-,480p,720p,1080p,.mov.csmil/"
    @"master.m3u8";
static const StreamType kDefaultStreamType = StreamTypeLive;

@interface ViewController () <IMAAdsLoaderDelegate,
                              IMAStreamManagerDelegate,
                              AVPlayerViewControllerDelegate>
@property(nonatomic) IMAAdsLoader *adsLoader;
@property(nonatomic) IMAAdDisplayContainer *adDisplayContainer;
@property(nonatomic) UIView *adContainerView;
@property(nonatomic) id<IMAVideoDisplay> videoDisplay;
@property(nonatomic) IMAStreamManager *streamManager;
@property(nonatomic) AVPlayerViewController *playerViewController;
@property(nonatomic, getter=isAdBreakActive) BOOL adBreakActive;
@end

@implementation ViewController

- (void)viewDidLoad {
  [super viewDidLoad];
  self.view.backgroundColor = [UIColor blackColor];
  self.streamType = kDefaultStreamType;
  [self setupAdsLoader];
  [self setupPlayer];
  [self setupAdContainer];
}

- (void)viewDidAppear:(BOOL)animated {
  [super viewDidAppear:animated];
  [self requestStream];
}

- (void)setupPlayer {
  // Create a stream video player.
  AVPlayer *player = [[AVPlayer alloc] init];
  self.playerViewController = [[AVPlayerViewController alloc] init];
  self.playerViewController.player = player;

  // Attach video player to view hierarchy.
  [self addChildViewController:self.playerViewController];
  [self.view addSubview:self.playerViewController.view];
  self.playerViewController.view.frame = self.view.bounds;
  [self.playerViewController didMoveToParentViewController:self];
}

Swift

class ViewController:
  UIViewController,
  IMAAdsLoaderDelegate,
  IMAStreamManagerDelegate,
  AVPlayerViewControllerDelegate
{
  // Live stream asset key, VOD content source and video IDs, Google Ad Manager network code, and
  // backup content URL.
  static let assetKey = "c-rArva4ShKVIAkNfy6HUQ"
  static let contentSourceID = "2548831"
  static let videoID = "tears-of-steel"
  static let networkCode = "21775744923"
  static let backupStreamURLString =
    "http://googleimadev-vh.akamaihd.net/i/big_buck_bunny/bbb-,480p,720p,1080p,.mov.csmil/master.m3u8"

  var adsLoader: IMAAdsLoader?
  var videoDisplay: IMAAVPlayerVideoDisplay!
  var adDisplayContainer: IMAAdDisplayContainer?
  var adContainerView: UIView?
  private var streamManager: IMAStreamManager?
  private var contentPlayhead: IMAAVPlayerContentPlayhead?
  private var playerViewController: AVPlayerViewController!
  private var userSeekTime = 0.0
  private var adBreakActive = false

  private enum StreamType {
    case live
    /// Video on demand.
    case vod
  }

  /// Set the stream type here.
  private let currentStreamType: StreamType = .live

  deinit {
    NotificationCenter.default.removeObserver(self)
  }

  override func viewDidLoad() {
    super.viewDidLoad()
    self.view.backgroundColor = UIColor.black

    setupAdsLoader()
    setupPlayer()
    setupAdContainer()
  }

  override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)
    requestStream()
  }

  func setupPlayer() {
    let player = AVPlayer()
    let playerViewController = AVPlayerViewController()
    playerViewController.delegate = self
    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)

    self.addChild(playerViewController)
    playerViewController.view.frame = self.view.bounds
    self.view.insertSubview(playerViewController.view, at: 0)
    playerViewController.didMove(toParent: self)
    self.playerViewController = playerViewController
  }

viewDidLoad() içinde setupAdsLoader(), IMAAdsLoader öğesini oluşturur, setupPlayer(), AVPlayerViewController öğesini oluşturur ve setupAdContainer(), UIView öğesini reklam gösterimine hazırlar. Görünüm görünür hale geldiğinde, viewDidAppear(), DAI akışını istemek için requestStream() çağrılarını yapar.

Bu örnekte, yayın isteği parametrelerini tanımlamak için sabitler (ör. canlı yayınlar için asset key veya VOD yayınları için content source ID ve video ID) kullanılır. Örnekte, IMA SDK'yı yönetmek için aşağıdaki bileşenler de kullanılmaktadır:

  • adsLoader: Google Ad Manager'a yönelik yayın isteklerini işler. Uygulamanın yaşam döngüsü için tek bir örnek kullanmanızı öneririz.
  • videoDisplay: IMA'nın AVPlayer'ı kullanarak video oynatmayı kontrol etmesine ve oynatma etkinliklerini izlemesine olanak tanıyan bir IMAVideoDisplay uygulaması.
  • adDisplayContainer: Reklam kullanıcı arayüzü öğelerini oluşturmak ve reklam araları sırasında kullanıcı arayüzü odağını yönetmek için kullanılan görünümü yönetir.
  • streamManager: Birleştirilmiş reklam ve içerik akışının oynatılmasını yönetir ve temsilcisini kullanarak reklam yaşam döngüsü etkinliklerini gönderir.
  • playerViewController: IMA SDK tarafından yönetilen video akışını sunmak için kullanılan tvOS oynatıcı.
  • adBreakActive: Bir reklam arasının oynatılıp oynatılmadığını belirten boole işareti. Reklamlarda arama yapılmasını önlemek ve kullanıcı arayüzü odağını yönetmek için kullanılır.

IMAAdsLoader'ı uygulama

Ardından, IMAAdsLoader öğesini oluşturun ve reklam kapsayıcı görünümünü görünüm hiyerarşisine ekleyin.

Objective-C

- (void)setupAdsLoader {
  self.adsLoader = [[IMAAdsLoader alloc] init];
  self.adsLoader.delegate = self;
}

- (void)setupAdContainer {
  // Attach the ad container to the view hierarchy on top of the player.
  self.adContainerView = [[UIView alloc] init];
  [self.view addSubview:self.adContainerView];
  self.adContainerView.frame = self.view.bounds;
  // Keep hidden initially, until an ad break.
  self.adContainerView.hidden = YES;
}

Swift

func setupAdsLoader() {
  let adsLoader = IMAAdsLoader(settings: nil)
  adsLoader.delegate = self
  self.adsLoader = adsLoader
}

func setupAdContainer() {
  // Attach the ad container to the view hierarchy on top of the player.
  let adContainerView = UIView()
  self.view.addSubview(adContainerView)
  adContainerView.frame = self.view.bounds
  // Keep hidden initially, until an ad break.
  adContainerView.isHidden = true
  self.adContainerView = adContainerView
}

Akış isteğinde bulunma

Akış bilgilerini tutmak için birkaç sabit oluşturun ve ardından isteği göndermek üzere akış isteği işlevini uygulayın.

Objective-C

- (void)requestStream {
  self.videoDisplay =
      [[IMAAVPlayerVideoDisplay alloc] initWithAVPlayer:self.playerViewController.player];
  self.adDisplayContainer = [[IMAAdDisplayContainer alloc] initWithAdContainer:self.adContainerView
                                                                viewController:self];

  // Use the streamType property to determine which request to create.
  IMAStreamRequest *request;

  switch (self.streamType) {
    case StreamTypeLive: {
      request = [[IMALiveStreamRequest alloc] initWithAssetKey:kAssetKey
                                                   networkCode:kNetworkCode
                                            adDisplayContainer:self.adDisplayContainer
                                                  videoDisplay:self.videoDisplay
                                                   userContext:nil];
      NSLog(@"IMA: Requesting Live Stream with Asset Key: %@.", kAssetKey);
      break;
    }
    case StreamTypeVOD: {
      request = [[IMAVODStreamRequest alloc] initWithContentSourceID:kContentSourceID
                                                             videoID:kVideoID
                                                         networkCode:kNetworkCode
                                                  adDisplayContainer:self.adDisplayContainer
                                                        videoDisplay:self.videoDisplay
                                                         userContext:nil];
      NSLog(@"IMA: Requesting VOD Stream with Video ID: %@.", kVideoID);
      break;
    }
  }

  if (request) {
    [self.adsLoader requestStreamWithRequest:request];
  } else {
    // Fallback or error handling if no request object was created
    NSLog(@"IMA Error: Could not create stream request for unknown type.");
    [self playBackupStream];
  }
}

Swift

func requestStream() {
  guard let playerViewController = self.playerViewController else { return }
  guard let adContainerView = self.adContainerView else { return }
  guard let adsLoader = self.adsLoader else { return }

  self.videoDisplay = IMAAVPlayerVideoDisplay(avPlayer: playerViewController.player!)
  let adDisplayContainer = IMAAdDisplayContainer(
    adContainer: adContainerView, viewController: self)
  self.adDisplayContainer = adDisplayContainer

  // Variable to hold the specific stream request object.
  let request: IMAStreamRequest

  switch self.currentStreamType {
  case .live:
    // Create a live stream request.
    request = IMALiveStreamRequest(
      assetKey: ViewController.assetKey,
      networkCode: ViewController.networkCode,
      adDisplayContainer: adDisplayContainer,
      videoDisplay: self.videoDisplay,
      pictureInPictureProxy: nil,
      userContext: nil)
    print("IMA: Requesting Live Stream with asset key \(ViewController.assetKey)")

  case .vod:
    // Create a VOD stream request.
    request = IMAVODStreamRequest(
      contentSourceID: ViewController.contentSourceID,
      videoID: ViewController.videoID,
      networkCode: ViewController.networkCode,
      adDisplayContainer: adDisplayContainer,
      videoDisplay: self.videoDisplay,
      pictureInPictureProxy: nil,
      userContext: nil)
    print(
      "IMA: Requesting VOD Stream with content source ID \(ViewController.contentSourceID) and "
        + "video ID \(ViewController.videoID)")
  }

  adsLoader.requestStream(with: request)
}

Yayın etkinliklerini işleme

IMAAdsLoader ve IMAStreamManager, başlatma, hatalar ve akış durumundaki değişiklikleri işlemek için kullanılan olayları tetikler. Bu etkinlikler IMAAdsLoaderDelegate ve IMAStreamManagerDelegate protokolleri üzerinden tetiklenir. Yüklenen reklam etkinliğini dinleyin ve akışı başlatın. Bir reklam yüklenemezse bunun yerine yedek yayın oynatın.

Objective-C

- (void)playBackupStream {
  NSURL *backupStreamURL = [NSURL URLWithString:kBackupStreamURLString];
  [self.videoDisplay loadStream:backupStreamURL withSubtitles:@[]];
  [self.videoDisplay play];
  [self startMediaSession];
}

- (void)startMediaSession {
  [[AVAudioSession sharedInstance] setActive:YES error:nil];
  [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:nil];
}

#pragma mark - IMAAdsLoaderDelegate

- (void)adsLoader:(IMAAdsLoader *)loader adsLoadedWithData:(IMAAdsLoadedData *)adsLoadedData {
  // Initialize and listen to stream manager's events.
  self.streamManager = adsLoadedData.streamManager;
  self.streamManager.delegate = self;
  [self.streamManager initializeWithAdsRenderingSettings:nil];
  NSLog(@"Stream created with: %@.", self.streamManager.streamId);
}

- (void)adsLoader:(IMAAdsLoader *)loader failedWithErrorData:(IMAAdLoadingErrorData *)adErrorData {
  // Fall back to playing the backup stream.
  NSLog(@"Error loading ads: %@", adErrorData.adError.message);
  [self playBackupStream];
}

Swift

@objc func contentDidFinishPlaying(_ notification: Notification) {
  guard let adsLoader = self.adsLoader else { return }
  adsLoader.contentComplete()
}

func startMediaSession() {
  try? AVAudioSession.sharedInstance().setActive(true, options: [])
  try? AVAudioSession.sharedInstance().setCategory(.playback)
}

// MARK: - IMAAdsLoaderDelegate

func adsLoader(_ loader: IMAAdsLoader, adsLoadedWith adsLoadedData: IMAAdsLoadedData) {
  let streamManager = adsLoadedData.streamManager!
  streamManager.delegate = self
  streamManager.initialize(with: nil)
  self.streamManager = streamManager
}

func adsLoader(_ loader: IMAAdsLoader, failedWith adErrorData: IMAAdLoadingErrorData) {
  print("Error loading ads: \(adErrorData.adError.message)")
  let streamUrl = URL(string: ViewController.backupStreamURLString)
  self.videoDisplay.loadStream(streamUrl!, withSubtitles: [])
  self.videoDisplay.play()
  playerViewController.player?.play()
}

Günlüğe kaydetme ve hata olaylarını işleme

Akış yöneticisi temsilcisi tarafından işlenebilecek çeşitli etkinlikler vardır ancak temel uygulamalarda en önemli kullanımları etkinlik günlüğü oluşturmak, reklamlar oynatılırken arama işlemlerini önlemek ve hataları işlemek için kullanılır.

Objective-C

#pragma mark - IMAStreamManagerDelegate

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

      NSLog(@"%@", extendedAdPodInfo);
      break;
    }
    case kIMAAdEvent_AD_BREAK_STARTED: {
      self.adContainerView.hidden = NO;
      // Trigger an update to send focus to the ad display container.
      self.adBreakActive = YES;
      [self setNeedsFocusUpdate];
      break;
    }
    case kIMAAdEvent_AD_BREAK_ENDED: {
      self.adContainerView.hidden = YES;
      // Trigger an update to send focus to the content player.
      self.adBreakActive = NO;
      [self setNeedsFocusUpdate];
      break;
    }
    case kIMAAdEvent_ICON_FALLBACK_IMAGE_CLOSED: {
      // Resume playback after the user has closed the dialog.
      [self.videoDisplay play];
      break;
    }
    default:
      break;
  }
}

- (void)streamManager:(IMAStreamManager *)streamManager didReceiveAdError:(IMAAdError *)error {
  // Fall back to playing the backup stream.
  NSLog(@"StreamManager error: %@", error.message);
  [self playBackupStream];
}

Swift

// MARK: - IMAStreamManagerDelegate
func streamManager(_ streamManager: IMAStreamManager, didReceive event: IMAAdEvent) {
  print("StreamManager event \(event.typeString).")
  switch event.type {
  case IMAAdEventType.STREAM_STARTED:
    self.startMediaSession()
  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:
    if let adContainerView = self.adContainerView {
      adContainerView.isHidden = false
    }
    // Trigger an update to send focus to the ad display container.
    adBreakActive = true
    setNeedsFocusUpdate()
    break
  case IMAAdEventType.AD_BREAK_ENDED:
    if let adContainerView = self.adContainerView {
      adContainerView.isHidden = true
    }
    // Trigger an update to send focus to the content player.
    adBreakActive = false
    setNeedsFocusUpdate()
    break
  case IMAAdEventType.ICON_FALLBACK_IMAGE_CLOSED:
    // Resume playback after the user has closed the dialog.
    self.videoDisplay.play()
    break
  default:
    break
  }
}

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

İşte bu kadar. Artık IMA DAI SDK ile reklam isteğinde bulunup reklam görüntüleyebilirsiniz. Daha gelişmiş SDK özellikleri hakkında bilgi edinmek için diğer kılavuzlara veya GitHub'daki örneklere göz atın.