Configurar o SDK do IMA para DAI

Os SDKs do IMA facilitam a integração de anúncios multimídia aos seus sites e apps. Os SDKs do IMA podem solicitar anúncios de qualquer servidor de anúncios compatível com VAST e gerenciar a reprodução de anúncios nos seus apps. Com os SDKs de DAI do IMA, os apps fazem uma solicitação de stream para anúncios e vídeos de conteúdo, seja VOD ou conteúdo ao vivo. Em seguida, o SDK retorna um stream de vídeo combinado para que você não precise gerenciar a troca entre o anúncio e o vídeo de conteúdo no app.

Selecione a solução de DAI que você quer usar

DAI de serviço completo

Este guia demonstra como integrar o SDK do IMA DAI a um app player de vídeo simples. Se você quiser ver ou acompanhar um exemplo de integração concluída, baixe o BasicExample do GitHub.

Visão geral da DAI da IMA

A implementação da DAI da IMA envolve quatro componentes principais do SDK, conforme demonstrado neste guia:

  • StreamDisplayContainer: um objeto contêiner que fica acima do elemento de reprodução de vídeo e contém os elementos da interface do anúncio.
  • AdsLoader: um objeto que solicita streams e processa eventos acionados por objetos de resposta de solicitação de stream. Você só deve instanciar um carregador de anúncios, que pode ser reutilizado durante toda a vida útil do aplicativo.
  • StreamRequest: Um objeto que define uma solicitação de stream. As solicitações de stream podem ser para vídeo on demand ou transmissões ao vivo. As solicitações de transmissão ao vivo especificam uma chave de recurso, enquanto as de VOD especificam um ID do CMS e um ID do vídeo. Os dois tipos de solicitação podem incluir uma chave de API necessária para acessar streams específicos e um código de rede do Google Ad Manager para que o SDK do IMA processe os identificadores de anúncios conforme especificado nas configurações do Google Ad Manager.
  • StreamManager: um objeto que processa streams de inserção de anúncios dinâmicos e interações com o back-end da DAI. O gerenciador de stream também processa pings de rastreamento e encaminha eventos de stream e de anúncio para o publisher.

Pré-requisitos

  • Android Studio
  • Exemplo de app player de vídeo para a integração do SDK

Baixar e executar o app de exemplo de player de vídeo

O app de exemplo oferece um player de vídeo funcional que reproduz vídeos HLS. Use isso como ponto de partida para integrar os recursos de DAI do SDK DAI do IMA.

  1. Faça o download e extraia o aplicativo de exemplo de player de vídeo.

  2. Inicie o Android Studio e selecione Abrir um projeto do Android Studio. Se o Android Studio já estiver em execução, selecione Arquivo > Novo > Importar projeto. Em seguida, escolha SampleVideoPlayer/build.gradle.

  3. Execute uma sincronização do Gradle selecionando Tools > Android > Sync Project with Gradle Files.

  4. Confira se o app player compila e é executado em um dispositivo Android físico ou em um dispositivo virtual Android usando Executar > Executar "app". É normal que o stream de vídeo leve alguns instantes para carregar antes de começar a ser reproduzido.

Examinar o player de vídeo de exemplo

O player de vídeo de exemplo ainda não contém nenhum código de integração do SDK do IMA DAI. O app de exemplo consiste em duas partes principais:

  1. samplevideoplayer/SampleVideoPlayer.java: um player HLS baseado no ExoPlayer que serve como base para a integração da DAI do IMA.

  2. videoplayerapp/MyActivity.java: essa atividade cria o player de vídeo e transmite um Context e um media3.ui.PlayerView.

Adicionar o SDK do IMA DAI ao app player

Você também precisa incluir uma referência ao SDK de DAI do IMA. No Android Studio, adicione o seguinte ao arquivo build.gradle no nível do aplicativo, localizado em app/build.gradle. O SDK do IMA exige que a remoção de açúcar sintático da biblioteca esteja ativada. Para isso, defina coreLibraryDesugaringEnabled true e adicione coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.1.5' como uma dependência no arquivo build.gradle. Para mais detalhes, consulte APIs Java 11 e mais recentes disponíveis por simplificação com a especificação nio.

repositories {
    google()
    mavenCentral()
}

dependencies {
    def media3_version = "1.5.1"
    implementation(platform("org.jetbrains.kotlin:kotlin-bom:1.8.0"))
    implementation 'androidx.appcompat:appcompat:1.7.0'
    implementation "androidx.media3:media3-ui:$media3_version"
    implementation "androidx.media3:media3-exoplayer:$media3_version"
    implementation "androidx.media3:media3-exoplayer-hls:$media3_version"
    implementation "androidx.media3:media3-exoplayer-dash:$media3_version"
    implementation 'androidx.mediarouter:mediarouter:1.7.0'
    implementation 'com.google.ads.interactivemedia.v3:interactivemedia:3.36.0'

Integrar o SDK DAI do IMA

  1. Crie uma classe chamada SampleAdsWrapper no pacote videoplayerapp (em app/java/com.google.ads.interactivemedia.v3.samples/videoplayerapp/) para encapsular o SampleVideoPlayer atual e adicione a lógica que implementa a DAI da IMA. Para fazer isso, primeiro crie um AdsLoader, que é usado para solicitar o stream de DAI.

    Este snippet inclui parâmetros de exemplo para streams HLS e DASH, ao vivo e VOD. Para definir qual stream está sendo reproduzido, atualize a variável CONTENT_TYPE.

    package com.google.ads.interactivemedia.v3.samples.videoplayerapp;
    
    import android.annotation.SuppressLint;
    import android.content.Context;
    import android.view.ViewGroup;
    import android.webkit.WebView;
    import androidx.annotation.Nullable;
    import com.google.ads.interactivemedia.v3.api.AdErrorEvent;
    import com.google.ads.interactivemedia.v3.api.AdEvent;
    import com.google.ads.interactivemedia.v3.api.AdsLoader;
    import com.google.ads.interactivemedia.v3.api.AdsManagerLoadedEvent;
    import com.google.ads.interactivemedia.v3.api.CuePoint;
    import com.google.ads.interactivemedia.v3.api.ImaSdkFactory;
    import com.google.ads.interactivemedia.v3.api.StreamDisplayContainer;
    import com.google.ads.interactivemedia.v3.api.StreamManager;
    import com.google.ads.interactivemedia.v3.api.StreamRequest;
    import com.google.ads.interactivemedia.v3.api.StreamRequest.StreamFormat;
    import com.google.ads.interactivemedia.v3.api.player.VideoProgressUpdate;
    import com.google.ads.interactivemedia.v3.api.player.VideoStreamPlayer;
    import com.google.ads.interactivemedia.v3.samples.samplevideoplayer.SampleVideoPlayer;
    import com.google.ads.interactivemedia.v3.samples.samplevideoplayer.SampleVideoPlayer.SampleVideoPlayerCallback;
    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.List;
    
    /** This class adds ad-serving support to Sample HlsVideoPlayer */
    @SuppressLint("UnsafeOptInUsageError")
    /* @SuppressLint is needed for new media3 APIs. */
    public class SampleAdsWrapper
        implements AdEvent.AdEventListener, AdErrorEvent.AdErrorListener, AdsLoader.AdsLoadedListener {
    
      // Live HLS stream asset key.
      private static final String TEST_HLS_ASSET_KEY = "c-rArva4ShKVIAkNfy6HUQ";
    
      // Live DASH stream asset key.
      private static final String TEST_DASH_ASSET_KEY = "PSzZMzAkSXCmlJOWDmRj8Q";
    
      // VOD HLS content source and video IDs.
      private static final String TEST_HLS_CONTENT_SOURCE_ID = "2548831";
      private static final String TEST_HLS_VIDEO_ID = "tears-of-steel";
    
      // VOD DASH content source and video IDs.
      private static final String TEST_DASH_CONTENT_SOURCE_ID = "2559737";
      private static final String TEST_DASH_VIDEO_ID = "tos-dash";
    
      private static final String NETWORK_CODE = "21775744923";
    
      private static final String PLAYER_TYPE = "DAISamplePlayer";
    
      private enum ContentType {
        LIVE_HLS,
        LIVE_DASH,
        VOD_HLS,
        VOD_DASH,
      }
    
      // Set CONTENT_TYPE to the associated enum for the stream type you would like to test.
      private static final ContentType CONTENT_TYPE = ContentType.VOD_HLS;
    
      /** Log interface, so we can output the log commands to the UI or similar. */
      public interface Logger {
        void log(String logMessage);
      }
    
      private final ImaSdkFactory sdkFactory;
      private AdsLoader adsLoader;
      private StreamManager streamManager;
      private final List<VideoStreamPlayer.VideoStreamPlayerCallback> playerCallbacks;
    
      private final SampleVideoPlayer videoPlayer;
      private final Context context;
      private final ViewGroup adUiContainer;
    
      private String fallbackUrl;
      private Logger logger;
    
      /**
       * Creates a new SampleAdsWrapper that implements IMA direct-ad-insertion.
       *
       * @param context the app's context.
       * @param videoPlayer underlying HLS video player.
       * @param adUiContainer ViewGroup in which to display the ad's UI.
       */
      public SampleAdsWrapper(Context context, SampleVideoPlayer videoPlayer, ViewGroup adUiContainer) {
        this.videoPlayer = videoPlayer;
        this.context = context;
        this.adUiContainer = adUiContainer;
        sdkFactory = ImaSdkFactory.getInstance();
        playerCallbacks = new ArrayList<>();
        createAdsLoader();
      }
    
      private void enableWebViewDebugging() {
        WebView.setWebContentsDebuggingEnabled(true);
      }
    
      private void createAdsLoader() {
        enableWebViewDebugging();
        VideoStreamPlayer videoStreamPlayer = createVideoStreamPlayer();
        StreamDisplayContainer displayContainer =
            ImaSdkFactory.createStreamDisplayContainer(adUiContainer, videoStreamPlayer);
        videoPlayer.setSampleVideoPlayerCallback(createSampleVideoPlayerCallback());
        adsLoader =
            sdkFactory.createAdsLoader(context, MyActivity.getImaSdkSettings(), displayContainer);
      }
    
      public void requestAndPlayAds() {
        adsLoader.addAdErrorListener(this);
        adsLoader.addAdsLoadedListener(this);
        adsLoader.requestStream(buildStreamRequest());
      }
    
  2. Crie um método auxiliar createSampleVideoPlayerCallback() para processar a criação de uma instância de interface SampleVideoPlayerCallback que estende VideoStreamPlayer.VideoStreamPlayerCallback.

    Para trabalhar com a DAI, o player precisa transmitir eventos ID3 de transmissões ao vivo para o SDK da DAI do IMA. O método callback.onUserTextReceived() faz isso no exemplo de código a seguir.

    private SampleVideoPlayerCallback createSampleVideoPlayerCallback() {
      return new SampleVideoPlayerCallback() {
        @Override
        public void onUserTextReceived(String userText) {
          for (VideoStreamPlayer.VideoStreamPlayerCallback callback : playerCallbacks) {
            callback.onUserTextReceived(userText);
          }
        }
    
        @Override
        public void onSeek(int windowIndex, long positionMs) {
          // See if we would seek past an ad, and if so, jump back to it.
          long newSeekPositionMs = positionMs;
          if (streamManager != null) {
            CuePoint prevCuePoint = streamManager.getPreviousCuePointForStreamTimeMs(positionMs);
            if (prevCuePoint != null && !prevCuePoint.isPlayed()) {
              newSeekPositionMs = prevCuePoint.getStartTimeMs();
            }
          }
          videoPlayer.seekTo(windowIndex, newSeekPositionMs);
        }
    
        @Override
        public void onContentComplete() {
          for (VideoStreamPlayer.VideoStreamPlayerCallback callback : playerCallbacks) {
            callback.onContentComplete();
          }
        }
    
        @Override
        public void onPause() {
          for (VideoStreamPlayer.VideoStreamPlayerCallback callback : playerCallbacks) {
            callback.onPause();
          }
        }
    
        @Override
        public void onResume() {
          for (VideoStreamPlayer.VideoStreamPlayerCallback callback : playerCallbacks) {
            callback.onResume();
          }
        }
    
        @Override
        public void onVolumeChanged(int percentage) {
          for (VideoStreamPlayer.VideoStreamPlayerCallback callback : playerCallbacks) {
            callback.onVolumeChanged(percentage);
          }
        }
      };
    }
    
  3. Adicione um método buildStreamRequest() para criar o SteamRequest. Esse método alterna entre diferentes streams com base em como você define a variável CONTENT_TYPE. O fluxo padrão usado neste guia é o fluxo HLS VOD de amostra do IMA.

    @Nullable
    private StreamRequest buildStreamRequest() {
      StreamRequest request;
      switch (CONTENT_TYPE) {
        case LIVE_HLS:
          // Live HLS stream request.
          return sdkFactory.createLiveStreamRequest(TEST_HLS_ASSET_KEY, null, NETWORK_CODE);
        case LIVE_DASH:
          // Live DASH stream request.
          return sdkFactory.createLiveStreamRequest(TEST_DASH_ASSET_KEY, null, NETWORK_CODE);
        case VOD_HLS:
          // VOD HLS request.
          request =
              sdkFactory.createVodStreamRequest(
                  TEST_HLS_CONTENT_SOURCE_ID, TEST_HLS_VIDEO_ID, null, NETWORK_CODE);
          request.setFormat(StreamFormat.HLS);
          return request;
        case VOD_DASH:
          // VOD DASH request.
          request =
              sdkFactory.createVodStreamRequest(
                  TEST_DASH_CONTENT_SOURCE_ID, TEST_DASH_VIDEO_ID, null, NETWORK_CODE);
          request.setFormat(StreamFormat.DASH);
          return request;
      }
      // Content type not selected.
      return null;
    }
    
  4. Você também precisa de um VideoStreamPlayer para reproduzir o stream. Portanto, adicione um método createVideoStreamPlayer(), que cria uma classe anônima que implementa VideoStreamPlayer.

    private VideoStreamPlayer createVideoStreamPlayer() {
      return new VideoStreamPlayer() {
        @Override
        public void loadUrl(String url, List<HashMap<String, String>> subtitles) {
          videoPlayer.setStreamUrl(url);
          videoPlayer.play();
        }
    
        @Override
        public void pause() {
          // Pause player.
          videoPlayer.pause();
        }
    
        @Override
        public void resume() {
          // Resume player.
          videoPlayer.play();
        }
    
        @Override
        public int getVolume() {
          // Make the video player play at the current device volume.
          return 100;
        }
    
        @Override
        public void addCallback(VideoStreamPlayerCallback videoStreamPlayerCallback) {
          playerCallbacks.add(videoStreamPlayerCallback);
        }
    
        @Override
        public void removeCallback(VideoStreamPlayerCallback videoStreamPlayerCallback) {
          playerCallbacks.remove(videoStreamPlayerCallback);
        }
    
        @Override
        public void onAdBreakStarted() {
          // Disable player controls.
          videoPlayer.enableControls(false);
          log("Ad Break Started\n");
        }
    
        @Override
        public void onAdBreakEnded() {
          // Re-enable player controls.
          if (videoPlayer != null) {
            videoPlayer.enableControls(true);
          }
          log("Ad Break Ended\n");
        }
    
        @Override
        public void onAdPeriodStarted() {
          log("Ad Period Started\n");
        }
    
        @Override
        public void onAdPeriodEnded() {
          log("Ad Period Ended\n");
        }
    
        @Override
        public void seek(long timeMs) {
          // An ad was skipped. Skip to the content time.
          videoPlayer.seekTo(timeMs);
          log("seek");
        }
    
        @Override
        public VideoProgressUpdate getContentProgress() {
          return new VideoProgressUpdate(
              videoPlayer.getCurrentPositionMs(), videoPlayer.getDuration());
        }
      };
    }
    
  5. Implemente os listeners necessários e adicione suporte para tratamento de erros.

    Observe a implementação de AdErrorListener, já que ela chama um URL de fallback se os anúncios não forem veiculados. Como o conteúdo e os anúncios estão em um stream, você precisa estar pronto para chamar um stream alternativo se o stream da DAI encontrar um erro.

    /** AdErrorListener implementation */
    @Override
    public void onAdError(AdErrorEvent event) {
      log(String.format("Error: %s\n", event.getError().getMessage()));
      // play fallback URL.
      log("Playing fallback Url\n");
      videoPlayer.setStreamUrl(fallbackUrl);
      videoPlayer.enableControls(true);
      videoPlayer.play();
    }
    
    /** AdEventListener implementation */
    @Override
    public void onAdEvent(AdEvent event) {
      switch (event.getType()) {
        case AD_PROGRESS:
          // Do nothing or else log will be filled by these messages.
          break;
        default:
          log(String.format("Event: %s\n", event.getType()));
          break;
      }
    }
    
    /** AdsLoadedListener implementation */
    @Override
    public void onAdsManagerLoaded(AdsManagerLoadedEvent event) {
      streamManager = event.getStreamManager();
      streamManager.addAdErrorListener(this);
      streamManager.addAdEventListener(this);
      streamManager.init();
    }
    
    /** Sets fallback URL in case ads stream fails. */
    void setFallbackUrl(String url) {
      fallbackUrl = url;
    }
    
  6. Adicione código para geração de registros.

    /** Sets logger for displaying events to screen. Optional. */
    void setLogger(Logger logger) {
      this.logger = logger;
    }
    
    private void log(String message) {
      if (logger != null) {
        logger.log(message);
      }
    }
  7. Modifique MyActivity em videoplayerapp para instanciar e chamar SampleAdsWrapper. Além disso, faça uma chamada para ImaSdkFactory.initialize() aqui usando um método auxiliar para criar uma instância ImaSdkSettings.

    package com.google.ads.interactivemedia.v3.samples.videoplayerapp;
    
    import android.annotation.SuppressLint;
    import android.app.Activity;
    import android.content.res.Configuration;
    import android.os.Bundle;
    import android.util.Log;
    import android.view.View;
    import android.widget.ImageButton;
    import android.widget.ScrollView;
    import android.widget.TextView;
    import com.google.ads.interactivemedia.v3.api.ImaSdkFactory;
    import com.google.ads.interactivemedia.v3.api.ImaSdkSettings;
    import com.google.ads.interactivemedia.v3.samples.samplevideoplayer.SampleVideoPlayer;
    
    /** Main Activity that plays media using {@link SampleVideoPlayer}. */
    @SuppressLint("UnsafeOptInUsageError")
    /* @SuppressLint is needed for new media3 APIs. */
    public class MyActivity extends Activity {
    
      private static final String DEFAULT_STREAM_URL =
          "https://storage.googleapis.com/interactive-media-ads/media/bbb.m3u8";
      private static final String APP_LOG_TAG = "ImaDaiExample";
      private static final String PLAYER_TYPE = "DAISamplePlayer";
      private static ImaSdkSettings imaSdkSettings;
    
      protected SampleVideoPlayer sampleVideoPlayer;
      protected ImageButton playButton;
    
      private boolean contentHasStarted = false;
    
      @Override
      protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_my);
    
        // Initialize the IMA SDK as early as possible when the app starts. If your app already
        // overrides Application.onCreate(), call this method inside the onCreate() method.
        // https://developer.android.com/topic/performance/vitals/launch-time#app-creation
        ImaSdkFactory.getInstance().initialize(this, getImaSdkSettings());
    
        View rootView = findViewById(R.id.videoLayout);
        sampleVideoPlayer =
            new SampleVideoPlayer(rootView.getContext(), rootView.findViewById(R.id.playerView));
        sampleVideoPlayer.enableControls(false);
        playButton = rootView.findViewById(R.id.playButton);
        final SampleAdsWrapper sampleAdsWrapper =
            new SampleAdsWrapper(this, sampleVideoPlayer, rootView.findViewById(R.id.adUiContainer));
        sampleAdsWrapper.setFallbackUrl(DEFAULT_STREAM_URL);
    
        final ScrollView scrollView = findViewById(R.id.logScroll);
        final TextView textView = findViewById(R.id.logText);
    
        sampleAdsWrapper.setLogger(
            logMessage -> {
              Log.i(APP_LOG_TAG, logMessage);
              if (textView != null) {
                textView.append(logMessage);
              }
              if (scrollView != null) {
                scrollView.post(() -> scrollView.fullScroll(View.FOCUS_DOWN));
              }
            });
    
        // Set up play button listener to play video then hide play button.
        playButton.setOnClickListener(
            view -> {
              if (contentHasStarted) {
                sampleVideoPlayer.play();
              } else {
                contentHasStarted = true;
                sampleVideoPlayer.enableControls(true);
                sampleAdsWrapper.requestAndPlayAds();
              }
              playButton.setVisibility(View.GONE);
            });
        orientVideoDescription(getResources().getConfiguration().orientation);
      }
    
  8. Adicione o método auxiliar getImaSdkSettings() para criar uma instância de ImaSdkSettings.

    public static ImaSdkSettings getImaSdkSettings() {
      if (imaSdkSettings == null) {
        imaSdkSettings = ImaSdkFactory.getInstance().createImaSdkSettings();
        imaSdkSettings.setPlayerType(PLAYER_TYPE);
        // Set any additional IMA SDK settings here.
      }
      return imaSdkSettings;
    }
  9. Modifique o arquivo de layout da atividade activity_my.xml para adicionar elementos de interface para registro.

    <!-- UI element for viewing SDK event log -->
    <ScrollView
        android:id="@+id/logScroll"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="0.5"
        android:padding="5dp"
        android:background="#DDDDDD">
    
        <TextView
            android:id="@+id/logText"
            android:layout_width="match_parent"
            android:layout_height="wrap_content">
        </TextView>
    </ScrollView>

Parabéns! Agora você está solicitando e mostrando anúncios em vídeo no seu app Android. Para ajustar a implementação, consulte Favoritos, Snapback e a documentação da API.

Solução de problemas

Se você estiver com problemas para reproduzir um anúncio em vídeo, faça o download do BasicExample concluído. Se ele funcionar corretamente no BasicExample, provavelmente há um problema com o código de integração do IMA do seu app.

Se você ainda estiver com problemas, acesse o fórum do SDK IMA.