Configurer avec l'insertion dynamique d'annonces à service complet

Sélectionner une plate-forme : HTML5 Android iOS tvOS Cast Roku

Ce guide explique comment intégrer le SDK IMA DAI dans une application de lecteur vidéo. Si vous souhaitez afficher ou suivre un exemple d'intégration complet, téléchargez BasicExample depuis GitHub.

Présentation de l'IMA DAI

L'implémentation d'IMA DAI implique quatre composants principaux du SDK, comme l'explique ce guide :

  • IMAAdDisplayContainer : objet conteneur qui se trouve au-dessus de l'élément de lecture vidéo et qui héberge les éléments d'interface utilisateur de l'annonce.
  • IMAAdsLoader : objet qui demande des flux et gère les événements déclenchés par les objets de réponse aux demandes de flux. Vous ne devez instancier qu'un seul chargeur d'annonces, qui peut être réutilisé pendant toute la durée de vie de l'application.
  • IMAStreamRequest : IMAVODStreamRequest ou IMALiveStreamRequest. Objet définissant une requête de flux. Les requêtes de flux peuvent concerner des flux de vidéo à la demande ou des flux en direct. Les demandes de diffusion en direct spécifient une clé d'élément, tandis que les demandes de VOD spécifient un ID CMS et un ID vidéo. Les deux types de requêtes peuvent éventuellement inclure une clé API nécessaire pour accéder aux flux spécifiés, ainsi qu'un code de réseau Google Ad Manager permettant au SDK IMA de gérer les identifiants d'annonces comme spécifié dans les paramètres Google Ad Manager.
  • IMAStreamManager : objet qui gère les flux d'insertion dynamique d'annonce et les interactions avec le backend DAI. Le gestionnaire de flux gère également les pings de suivi et transmet les événements de flux et d'annonce à l'éditeur.

Prérequis

Avant de commencer, vous avez besoin des éléments suivants :

Vous avez également besoin des paramètres pour demander votre flux au SDK IMA. Pour obtenir des exemples de paramètres de requête, consultez Exemples de flux.

Paramètres de diffusion en direct
Clé de l'élément La clé d'asset identifiant votre diffusion en direct dans Google Ad Manager.
Exemple : c-rArva4ShKVIAkNfy6HUQ
Paramètres de flux VOD
ID de la source de contenu ID de la source de contenu de Google Ad Manager.
Exemple : 2548831
ID vidéo ID vidéo de Google Ad Manager.
Exemple : tears-of-steel
Paramètres courants (VOD et diffusion en direct)
Code réseau Votre code de réseau Google Ad Manager.
Exemple : 21775744923

Créer un projet Xcode

Dans Xcode, créez un projet iOS nommé "BasicExample" à l'aide d'Objective-C.

Ajouter le SDK IMA DAI au projet Xcode

Pour installer le SDK IMA, choisissez la méthode de votre choix.

Recommandé : Installer le SDK à l'aide de Swift Package Manager

Le SDK Interactive Media Ads est compatible avec Swift Package Manager à partir de la version 3.18.4. Pour importer le package Swift, procédez comme suit :

  1. Dans Xcode, installez le package Swift du SDK IMA DAI : accédez à File > Add Packages (Fichier > Ajouter des packages).

  2. Dans l'invite qui s'affiche, recherchez le dépôt GitHub du package Swift du SDK IMA DAI :

    https://github.com/googleads/swift-package-manager-google-interactive-media-ads-ios
    
  3. Sélectionnez la version du package Swift du SDK IMA DAI que vous souhaitez utiliser. Pour les nouveaux projets, utilisez l'option Jusqu'à la prochaine version majeure.

Une fois que vous avez terminé, Xcode résout les dépendances de votre package et les télécharge en arrière-plan. Pour en savoir plus sur l'ajout de dépendances de package, consultez cet article d'Apple.

Télécharger et installer manuellement le SDK

Si vous ne souhaitez pas utiliser Swift Package Manager, téléchargez et ajoutez manuellement le SDK IMA à votre projet.

Créer un lecteur vidéo

Implémentez un lecteur vidéo dans votre contrôleur de vue principal. Encapsulez un lecteur AV dans une vue d'UI. Le SDK IMA utilise la vue de l'interface utilisateur pour afficher les éléments d'interface utilisateur de l'annonce.

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
  }
}

Initialiser le chargeur d'annonces

Importez le SDK IMA dans votre contrôleur de vue et adoptez les protocoles IMAAdsLoaderDelegate et IMAStreamManagerDelegate pour gérer les événements du chargeur d'annonces et du gestionnaire de flux.

Ajoutez ces propriétés privées pour stocker les composants clés du SDK IMA :

  • IMAAdsLoader
    • Gère les demandes de flux pendant la durée de vie de votre application.
  • IMAAdDisplayContainer
    • Gère l'insertion et la gestion des éléments d'interface utilisateur des annonces.
  • IMAAVPlayerVideoDisplay : communique entre le SDK IMA et votre lecteur multimédia, et gère les métadonnées temporelles.
  • IMAStreamManager : gère la lecture du flux et déclenche des événements liés aux annonces.

Initialisez le chargeur d'annonces, le conteneur d'affichage des annonces et l'affichage vidéo après le chargement de la vue.

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)
  }

Envoyer une requête de flux

Lorsqu'un utilisateur appuie sur le bouton de lecture, envoyez une nouvelle demande de flux. Utilisez la classe IMALiveStreamRequest pour les diffusions en direct. Pour les flux de VOD, utilisez la classe IMAVODStreamRequest.

La demande de flux nécessite vos paramètres de flux, ainsi qu'une référence à votre conteneur d'affichage d'annonces et à votre affichage vidéo.

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)
  }
}

Écouter les événements de chargement de flux

La classe IMAAdsLoader appelle les méthodes IMAAdsLoaderDelegate en cas d'initialisation réussie ou d'échec de la requête de flux.

Dans la méthode déléguée adsLoadedWithData, définissez votre IMAStreamManagerDelegate. Initialisez le gestionnaire de flux. Lors de l'initialisation, le gestionnaire de flux lance la lecture.

Dans la méthode déléguée failedWithErrorData, consignez l'erreur. Vous pouvez également lire le flux de secours. Consultez les bonnes pratiques concernant l'insertion dynamique d'annonce.

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()
}

Écouter les événements d'annonce

IMAStreamManager appelle les méthodes IMAStreamManagerDelegate pour transmettre les événements et les erreurs de flux à votre application.

Pour cet exemple, enregistrez les événements d'annonce principaux dans la console :

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")")
}

Exécutez votre application. Si l'opération réussit, demandez et lisez des flux d'insertion dynamique d'annonce Google avec le SDK IMA. Pour en savoir plus sur les fonctionnalités avancées du SDK, consultez les autres guides listés dans la barre latérale de gauche ou les exemples sur GitHub.