Как настроить динамическую вставку объявлений в режиме полного обслуживания

Выберите платформу: HTML5 Android iOS tvOS Cast Roku

В этом руководстве рассказывается, как интегрировать IMA DAI SDK в приложение с видеопроигрывателем. Если вы хотите посмотреть пример интеграции, скачайте BasicExample с GitHub.

Обзор IMA DAI

Внедрение IMA DAI включает четыре основных компонента SDK, как показано в этом руководстве:

  • IMAAdDisplayContainer – объект-контейнер, который находится поверх элемента воспроизведения видео и содержит элементы интерфейса объявления.
  • IMAAdsLoader – объект, который запрашивает потоки и обрабатывает события, инициированные объектами ответов на запросы потоков. Вам нужно создать только один экземпляр загрузчика объявлений, который можно использовать повторно в течение всего жизненного цикла приложения.
  • IMAStreamRequest – IMAVODStreamRequest или IMALiveStreamRequest. Объект, определяющий запрос потока. Запросы потоков могут относиться к видео по запросу или прямым трансляциям. В запросах трансляций указывается ключ объекта, а в запросах видео по запросу – идентификатор CMS и идентификатор видео. В запросы обоих типов можно добавить ключ API, необходимый для доступа к определенным потокам, и код сети Google Менеджера рекламы, который позволит IMA SDK обрабатывать рекламные идентификаторы в соответствии с настройками Менеджера рекламы.
  • IMAStreamManager – объект, который управляет потоками динамической вставки объявлений и взаимодействием с серверной частью динамической вставки объявлений. Менеджер потоков также обрабатывает запросы на отслеживание и пересылает издателю события потока и объявлений.

Требования

Прежде чем начать, вам понадобится следующее:

Кроме того, параметры необходимы для запроса трансляции из IMA SDK. Примеры параметров запроса можно найти в разделе Примеры потоков.

Параметры трансляции
Ключ объекта Ключ объекта, идентифицирующий вашу трансляцию в Google Менеджере рекламы.
Пример: c-rArva4ShKVIAkNfy6HUQ
Параметры трансляции видео по запросу
Идентификатор источника контента Идентификатор источника контента из Google Менеджера рекламы.
Пример: 2548831
Идентификатор видео Идентификатор видео из Google Менеджера рекламы.
Пример: tears-of-steel
Общие параметры (для видео по запросу и прямых трансляций)
Код сети Ваш код сети Google Менеджера рекламы.
Пример: 21775744923

Создайте проект Xcode

В Xcode создайте новый проект iOS на Objective-C с названием BasicExample.

Добавьте IMA DAI SDK в проект Xcode

Выберите способ установки IMA SDK.

Рекомендуемый способ: установка SDK с помощью Swift Package Manager

Interactive Media Ads SDK поддерживает Swift Package Manager начиная с версии 3.18.4. Чтобы импортировать пакет Swift, выполните следующие действия:

  1. В Xcode установите пакет IMA DAI SDK Swift. Для этого выберите 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, которую вы хотите использовать. Для новых проектов используйте Up to Next Major Version (До следующей основной версии).

После этого Xcode распознает зависимости пакета и скачает их в фоновом режиме. Подробную информацию о том, как добавлять зависимости пакетов, можно найти в статье Apple.

Как скачать и установить SDK вручную

Если вы не хотите использовать Swift Package Manager, скачайте IMA SDK и добавьте его в проект вручную.

Как создать видеопроигрыватель

Реализуйте видеопроигрыватель в основном контроллере представления, поместив AV-проигрыватель в представление пользовательского интерфейса. 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)
  }

Как отправить запрос на создание потока

Когда пользователь нажимает кнопку воспроизведения, отправьте новый запрос на трансляцию. Для прямых трансляций используйте класс IMALiveStreamRequest. Для видео по запросу используйте класс 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.
  if (kStreamType == StreamTypeLive) {
    // Live stream request. Replace the asset key with your value.
    IMALiveStreamRequest *request =
        [[IMALiveStreamRequest alloc] initWithAssetKey:kLiveStreamAssetKey
                                           networkCode:kNetworkCode
                                    adDisplayContainer:self.adDisplayContainer
                                          videoDisplay:self.imaVideoDisplay
                                           userContext:nil];
    request.useHLSInterstitials = YES;
    [self.adsLoader requestStreamWithRequest:request];
  } else {
    // VOD request. Replace the content source ID and video ID with your values.
    IMAVODStreamRequest *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)
    request.useHLSInterstitials = true
    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 зарегистрируйте ошибку. При необходимости запустите резервный поток. Ознакомьтесь с рекомендациями по динамической вставке объявлений.

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 с динамической вставкой объявлений, используя IMA SDK. Чтобы узнать больше о расширенных функциях SDK, ознакомьтесь с другими руководствами, перечисленными на боковой панели слева, или примерами на GitHub.