Configurar o SDK do IMA

Selecione a plataforma: HTML5 Android iOS tvOS

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 do lado do cliente do IMA, você mantém o controle da reprodução de vídeo de conteúdo, enquanto o SDK processa a reprodução de anúncios. Os anúncios são veiculados em um player de vídeo separado, posicionado acima do player de vídeo de conteúdo do app.

Este guia demonstra como integrar o SDK do IMA a um projeto vazio do Android Studio usando o VideoView do Android para mostrar conteúdo e anúncios. Para acompanhar um exemplo de integração concluído, faça o download do BasicExample no GitHub.

Visão geral do lado do cliente da IMA

A implementação do IMA do lado do cliente envolve quatro componentes principais do SDK, que são demonstrados neste guia:

  • AdDisplayContainer: um objeto contêiner que especifica onde a IMA renderiza elementos da interface do anúncio e mede a visibilidade, incluindo o Active View e a Medição aberta.
  • AdsLoader: um objeto que solicita anúncios e processa eventos de respostas de solicitação de anúncios. Você só precisa instanciar um carregador de anúncios, que pode ser reutilizado durante toda a vida útil do aplicativo.
  • AdsRequest: um objeto que define uma solicitação de anúncio. As solicitações de anúncios especificam o URL da tag de anúncio VAST, além de outros parâmetros, como dimensões do anúncio.
  • AdsManager: um objeto que contém a resposta à solicitação de anúncios, controla a reprodução de anúncios e detecta eventos de anúncio acionados pelo SDK.

Pré-requisitos

1. Criar um novo projeto do Android Studio

Para criar seu projeto do Android Studio, siga estas etapas:

  1. Inicie o Android Studio.
  2. Selecione Start a new Android Studio project.
  3. Na página Escolher seu projeto, selecione o modelo Atividade vazia.
  4. Clique em Próxima.
  5. Na página Configurar seu projeto, nomeie o projeto e selecione Java como linguagem.
  6. Clique em Concluir.

2. Adicionar o SDK do IMA ao seu projeto

Primeiro, no arquivo build.gradle no nível do aplicativo, adicione importações do SDK da IMA à seção de dependências. Devido ao tamanho do SDK do IMA, implemente e ative o multidex aqui. Isso é necessário para apps com minSdkVersion definido como 20 ou menos. Adicione também um novo compileOptions para especificar as informações de compatibilidade da versão do Java e ativar o desaçucaramento da biblioteca.

O SDK do IMA exige que a remoção de açúcar 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.

apply plugin: 'com.android.application'

android {
    namespace 'com.google.ads.interactivemedia.v3.samples.videoplayerapp'
    compileSdk 36

    // Java 17 required by Gradle 8+
    compileOptions {
        // Required by IMA SDK v3.37.0+
        coreLibraryDesugaringEnabled true

        // Java 17 required by Gradle 8+
        sourceCompatibility JavaVersion.VERSION_17
        targetCompatibility JavaVersion.VERSION_17
    }

    defaultConfig {
        applicationId "com.google.ads.interactivemedia.v3.samples.videoplayerapp"
        minSdkVersion 21
        targetSdkVersion 36
        multiDexEnabled true
        versionCode 1
        versionName "1.0"
    }
    buildTypes {
        release {
            minifyEnabled true
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

repositories {
    google()
    mavenCentral()
}

dependencies {
    coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.1.5'
    implementation(platform("org.jetbrains.kotlin:kotlin-bom:1.8.0"))
    implementation 'androidx.appcompat:appcompat:1.7.1'
    implementation 'androidx.browser:browser:1.9.0'
    implementation 'androidx.media:media:1.7.0'
    implementation 'com.google.ads.interactivemedia.v3:interactivemedia:3.37.0'
}

3. Atualizar o layout do app

Atualize o layout do app para incluir um VideoView que reproduza conteúdo e anúncios:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/container"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MyActivity"
    tools:ignore="MergeRootFrame">

    <RelativeLayout
        android:background="#000000"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="0.4"
        android:orientation="vertical"
        android:id="@+id/videoPlayerContainer" >

        <VideoView
            android:id="@+id/videoView"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />

        <ImageButton
            android:id="@+id/playButton"
            android:contentDescription="@string/play_description"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:src="@drawable/ic_action_play_over_video"
            android:background="@null" />

    </RelativeLayout>

    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="0.6"
        android:id="@+id/videoDescription" >

        <TextView
            android:id="@+id/playerDescription"
            android:text="@string/app_name"
            android:textAlignment="center"
            android:gravity="center_horizontal"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:paddingVertical="@dimen/font_size"
            android:textSize="@dimen/font_size" />
    </FrameLayout>

</LinearLayout>

4. Importar a IMA para a atividade principal

Adicione as instruções de importação do SDK do IMA:

import android.content.Context;
import android.content.res.Configuration;
import android.media.AudioManager;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.MediaController;
import android.widget.VideoView;
import androidx.appcompat.app.AppCompatActivity;
import com.google.ads.interactivemedia.v3.api.AdDisplayContainer;
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.AdsManager;
import com.google.ads.interactivemedia.v3.api.AdsRenderingSettings;
import com.google.ads.interactivemedia.v3.api.AdsRequest;
import com.google.ads.interactivemedia.v3.api.ImaSdkFactory;
import com.google.ads.interactivemedia.v3.api.ImaSdkSettings;
import com.google.ads.interactivemedia.v3.api.player.VideoProgressUpdate;
import java.util.Arrays;

Atualize a classe MyActivity para estender AppCompatActivity. A classe AppCompatActivity permite a compatibilidade com recursos mais recentes da plataforma em dispositivos Android mais antigos. Em seguida, adicione um conjunto de variáveis particulares que serão usadas no app:

/** Main activity. */
public class MyActivity extends AppCompatActivity {

  private static final String LOGTAG = "IMABasicSample";
  private static final String SAMPLE_VIDEO_URL =
      "https://storage.googleapis.com/gvabox/media/samples/stock.mp4";

  /**
   * IMA sample tag for a single skippable inline video ad. See more IMA sample tags at
   * https://developers.google.com/interactive-media-ads/docs/sdks/html5/client-side/tags
   */
  private static final String SAMPLE_VAST_TAG_URL =
      "https://pubads.g.doubleclick.net/gampad/ads?iu=/21775744923/external/"
          + "single_preroll_skippable&sz=640x480&ciu_szs=300x250%2C728x90&gdfp_req=1&output=vast"
          + "&unviewed_position_start=1&env=vp&correlator=";

  // Factory class for creating SDK objects.
  private ImaSdkFactory sdkFactory;

  // The AdsLoader instance exposes the requestAds method.
  private AdsLoader adsLoader;

  // AdsManager exposes methods to control ad playback and listen to ad events.
  private AdsManager adsManager;

  // The saved content position, used to resumed content following an ad break.
  private int savedPosition = 0;

  // This sample uses a VideoView for content and ad playback. For production
  // apps, Android's Exoplayer offers a more fully featured player compared to
  // the VideoView.
  private VideoView videoPlayer;
  private MediaController mediaController;
  private VideoAdPlayerAdapter videoAdPlayerAdapter;
  private ImaSdkSettings imaSdkSettings;

5. Criar a classe VideoAdPlayerAdapter

Crie uma classe VideoAdPlayerAdapter com o VideoView e adapte-a à interface VideoAdPlayer da IMA. Essa classe vai processar a reprodução de conteúdo e anúncios e conter o conjunto de métodos que um player de vídeo precisa implementar para ser usado pelo SDK do IMA:

import android.media.AudioManager;
import android.media.MediaPlayer;
import android.net.Uri;
import android.util.Log;
import android.widget.VideoView;
import com.google.ads.interactivemedia.v3.api.AdPodInfo;
import com.google.ads.interactivemedia.v3.api.player.AdMediaInfo;
import com.google.ads.interactivemedia.v3.api.player.VideoAdPlayer;
import com.google.ads.interactivemedia.v3.api.player.VideoProgressUpdate;
import java.util.ArrayList;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;

/** Example implementation of IMA's VideoAdPlayer interface. */
public class VideoAdPlayerAdapter implements VideoAdPlayer {

  private static final String LOGTAG = "IMABasicSample";
  private static final long POLLING_TIME_MS = 250;
  private static final long INITIAL_DELAY_MS = 250;
  private final VideoView videoPlayer;
  private final AudioManager audioManager;
  private final List<VideoAdPlayerCallback> videoAdPlayerCallbacks = new ArrayList<>();
  private Timer timer;
  private int adDuration;

  // The saved ad position, used to resumed ad playback following an ad click-through.
  private int savedAdPosition;
  private AdMediaInfo loadedAdMediaInfo;

  public VideoAdPlayerAdapter(VideoView videoPlayer, AudioManager audioManager) {
    this.videoPlayer = videoPlayer;
    this.videoPlayer.setOnCompletionListener(
        (MediaPlayer mediaPlayer) -> notifyImaOnContentCompleted());
    this.audioManager = audioManager;
  }

6. Substituir os métodos VideoAdPlayer

Substitua os seguintes métodos VideoAdPlayer:

O método playAd() define o URL do conteúdo ou do anúncio e um listener para iniciar a reprodução assim que a mídia for carregada.

@Override
public void addCallback(VideoAdPlayerCallback videoAdPlayerCallback) {
  videoAdPlayerCallbacks.add(videoAdPlayerCallback);
}

@Override
public void loadAd(AdMediaInfo adMediaInfo, AdPodInfo adPodInfo) {
  // This simple ad loading logic works because preloading is disabled. To support
  // preloading ads your app must maintain state for the currently playing ad
  // while handling upcoming ad downloading and buffering at the same time.
  // See the IMA Android preloading guide for more info:
  // https://developers.google.com/interactive-media-ads/docs/sdks/android/client-side/preload
  loadedAdMediaInfo = adMediaInfo;
}

@Override
public void pauseAd(AdMediaInfo adMediaInfo) {
  Log.i(LOGTAG, "pauseAd");
  savedAdPosition = videoPlayer.getCurrentPosition();
  stopAdTracking();
}

@Override
public void playAd(AdMediaInfo adMediaInfo) {
  videoPlayer.setVideoURI(Uri.parse(adMediaInfo.getUrl()));

  videoPlayer.setOnPreparedListener(
      mediaPlayer -> {
        adDuration = mediaPlayer.getDuration();
        if (savedAdPosition > 0) {
          mediaPlayer.seekTo(savedAdPosition);
        }
        mediaPlayer.start();
        startAdTracking();
      });
  videoPlayer.setOnErrorListener(
      (mediaPlayer, errorType, extra) -> notifyImaSdkAboutAdError(errorType));
  videoPlayer.setOnCompletionListener(
      mediaPlayer -> {
        savedAdPosition = 0;
        notifyImaSdkAboutAdEnded();
      });
}

@Override
public void release() {
  // any clean up that needs to be done.
}

@Override
public void removeCallback(VideoAdPlayerCallback videoAdPlayerCallback) {
  videoAdPlayerCallbacks.remove(videoAdPlayerCallback);
}

@Override
public void stopAd(AdMediaInfo adMediaInfo) {
  Log.i(LOGTAG, "stopAd");
  stopAdTracking();
}

/** Returns current volume as a percent of max volume. */
@Override
public int getVolume() {
  return audioManager.getStreamVolume(AudioManager.STREAM_MUSIC)
      / audioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
}

7. Configurar o acompanhamento de anúncios

Para que os eventos de anúncio sejam registrados, VideoAdPlayerCallback.onAdProgress precisa ser chamado à medida que o conteúdo e os anúncios avançam. Para isso, configure um timer para chamar onAdProgress() em um intervalo definido.

private void startAdTracking() {
  Log.i(LOGTAG, "startAdTracking");
  if (timer != null) {
    return;
  }
  timer = new Timer();
  TimerTask updateTimerTask =
      new TimerTask() {
        @Override
        public void run() {
          VideoProgressUpdate progressUpdate = getAdProgress();
          notifyImaSdkAboutAdProgress(progressUpdate);
        }
      };
  timer.schedule(updateTimerTask, POLLING_TIME_MS, INITIAL_DELAY_MS);
}

private void notifyImaSdkAboutAdEnded() {
  Log.i(LOGTAG, "notifyImaSdkAboutAdEnded");
  savedAdPosition = 0;
  for (VideoAdPlayer.VideoAdPlayerCallback callback : videoAdPlayerCallbacks) {
    callback.onEnded(loadedAdMediaInfo);
  }
}

private void notifyImaSdkAboutAdProgress(VideoProgressUpdate adProgress) {
  for (VideoAdPlayer.VideoAdPlayerCallback callback : videoAdPlayerCallbacks) {
    callback.onAdProgress(loadedAdMediaInfo, adProgress);
  }
}

/**
 * @param errorType Media player's error type as defined at
 *     https://cs.android.com/android/platform/superproject/+/master:frameworks/base/media/java/android/media/MediaPlayer.java;l=4335
 * @return True to stop the current ad playback.
 */
private boolean notifyImaSdkAboutAdError(int errorType) {
  Log.i(LOGTAG, "notifyImaSdkAboutAdError");

  switch (errorType) {
    case MediaPlayer.MEDIA_ERROR_UNSUPPORTED:
      Log.e(LOGTAG, "notifyImaSdkAboutAdError: MEDIA_ERROR_UNSUPPORTED");
      break;
    case MediaPlayer.MEDIA_ERROR_TIMED_OUT:
      Log.e(LOGTAG, "notifyImaSdkAboutAdError: MEDIA_ERROR_TIMED_OUT");
      break;
    default:
      break;
  }
  for (VideoAdPlayer.VideoAdPlayerCallback callback : videoAdPlayerCallbacks) {
    callback.onError(loadedAdMediaInfo);
  }
  return true;
}

public void notifyImaOnContentCompleted() {
  Log.i(LOGTAG, "notifyImaOnContentCompleted");
  for (VideoAdPlayer.VideoAdPlayerCallback callback : videoAdPlayerCallbacks) {
    callback.onContentComplete();
  }
}

private void stopAdTracking() {
  Log.i(LOGTAG, "stopAdTracking");
  if (timer != null) {
    timer.cancel();
    timer = null;
  }
}

@Override
public VideoProgressUpdate getAdProgress() {
  long adPosition = videoPlayer.getCurrentPosition();
  return new VideoProgressUpdate(adPosition, adDuration);
}

8. Iniciar a IMA no método onCreate

Substitua o método onCreate e adicione as atribuições de variáveis necessárias para iniciar a IMA. Nesta etapa, crie as instâncias do seguinte:

  • ImaSdkSettings
  • AdsLoader
  • VideoAdPlayerAdapter
@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
  sdkFactory = ImaSdkFactory.getInstance();
  sdkFactory.initialize(this, getImaSdkSettings());

  // Create the UI for controlling the video view.
  mediaController = new MediaController(this);
  videoPlayer = findViewById(R.id.videoView);
  mediaController.setAnchorView(videoPlayer);
  videoPlayer.setMediaController(mediaController);

  // Create an ad display container that uses a ViewGroup to listen to taps.
  AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
  videoAdPlayerAdapter = new VideoAdPlayerAdapter(videoPlayer, audioManager);

  AdDisplayContainer adDisplayContainer =
      ImaSdkFactory.createAdDisplayContainer(
          findViewById(R.id.videoPlayerContainer), videoAdPlayerAdapter);

  // Create an AdsLoader.
  adsLoader = sdkFactory.createAdsLoader(this, getImaSdkSettings(), adDisplayContainer);

Configure o botão de reprodução para solicitar anúncios e oculte-o quando clicado:

// When the play button is clicked, request ads and hide the button.
View playButton = findViewById(R.id.playButton);
playButton.setOnClickListener(
    view -> {
      videoPlayer.setVideoPath(SAMPLE_VIDEO_URL);
      requestAds(SAMPLE_VAST_TAG_URL);
      view.setVisibility(View.GONE);
    });
Por fim, adicione um método auxiliar para receber o ImaSdkSettings:
private ImaSdkSettings getImaSdkSettings() {
  if (imaSdkSettings == null) {
    imaSdkSettings = ImaSdkFactory.getInstance().createImaSdkSettings();
    // Set any IMA SDK settings here.
  }
  return imaSdkSettings;
}

9. Adicionar listeners do AdsLoader

Adicione listeners para addAdErrorListener e addAdsLoadedListener. Na AdsLoadedListener, crie o AdsManager e configure o listener de erros AdsManager:

// Add listeners for when ads are loaded and for errors.
adsLoader.addAdErrorListener(
    new AdErrorEvent.AdErrorListener() {
      /** An event raised when there is an error loading or playing ads. */
      @Override
      public void onAdError(AdErrorEvent adErrorEvent) {
        Log.i(LOGTAG, "Ad Error: " + adErrorEvent.getError().getMessage());
        resumeContent();
      }
    });
adsLoader.addAdsLoadedListener(
    adsManagerLoadedEvent -> {
      // Ads were successfully loaded, so get the AdsManager instance. AdsManager has
      // events for ad playback and errors.
      adsManager = adsManagerLoadedEvent.getAdsManager();

      // Attach event and error event listeners.
      adsManager.addAdErrorListener(
          new AdErrorEvent.AdErrorListener() {
            /** An event raised when there is an error loading or playing ads. */
            @Override
            public void onAdError(AdErrorEvent adErrorEvent) {
              Log.e(LOGTAG, "Ad Error: " + adErrorEvent.getError().getMessage());
              String universalAdIds =
                  Arrays.toString(adsManager.getCurrentAd().getUniversalAdIds());
              Log.i(
                  LOGTAG,
                  "Discarding the current ad break with universal "
                      + "ad Ids: "
                      + universalAdIds);
              adsManager.discardAdBreak();
            }
          });

10. Processar eventos de anúncios da IMA

Detecte eventos de anúncio do IMA com AdsManager.addAdEventListener. Usando uma instrução switch, configure ações para os seguintes eventos da IMA:

O snippet de código inclui comentários com mais informações sobre como usar os eventos. Depois que os eventos forem configurados, chame AdsManager.init():

  adsManager.addAdEventListener(
      new AdEvent.AdEventListener() {
        /** Responds to AdEvents. */
        @Override
        public void onAdEvent(AdEvent adEvent) {
          if (adEvent.getType() != AdEvent.AdEventType.AD_PROGRESS) {
            Log.i(LOGTAG, "Event: " + adEvent.getType());
          }
          // These are the suggested event types to handle. For full list of
          // all ad event types, see AdEvent.AdEventType documentation.
          switch (adEvent.getType()) {
            case LOADED ->
                // AdEventType.LOADED is fired when ads are ready to play.
                // This sample app uses the sample tag
                // single_preroll_skippable_ad_tag_url that requires calling
                // AdsManager.start() to start ad playback.
                // If you use a different ad tag URL that returns a VMAP or
                // an ad rules playlist, the adsManager.init() function will
                // trigger ad playback automatically and the IMA SDK will
                // ignore the adsManager.start().
                // It is safe to always call adsManager.start() in the
                // LOADED event.
                adsManager.start();
            case CONTENT_PAUSE_REQUESTED ->
                // AdEventType.CONTENT_PAUSE_REQUESTED is fired when you
                // should pause your content and start playing an ad.
                pauseContentForAds();
            case CONTENT_RESUME_REQUESTED ->
                // AdEventType.CONTENT_RESUME_REQUESTED is fired when the ad
                // you should play your content.
                resumeContent();
            case ALL_ADS_COMPLETED -> {
              // Calling adsManager.destroy() triggers the function
              // VideoAdPlayer.release().
              adsManager.destroy();
              adsManager = null;
            }
            case CLICKED -> {
              // When the user clicks on the Learn More button, the IMA SDK fires
              // this event, pauses the ad, and opens the ad's click-through URL.
              // When the user returns to the app, the IMA SDK calls the
              // VideoAdPlayer.playAd() function automatically.
            }
            default -> {}
          }
        }
      });
  AdsRenderingSettings adsRenderingSettings =
      ImaSdkFactory.getInstance().createAdsRenderingSettings();
  // Add any ads rendering settings here.
  // This init() only loads the UI rendering settings locally.
  adsManager.init(adsRenderingSettings);
});

11. Processar a troca entre anúncios e conteúdo

Nesta seção, crie os métodos pauseContentForAds e resumeContent referenciados nas etapas anteriores. Esses métodos reutilizam o player para veicular conteúdo e anúncios. Você precisa acompanhar a posição do conteúdo para retomar a reprodução após o intervalo de anúncio.

private void pauseContentForAds() {
  Log.i(LOGTAG, "pauseContentForAds");
  savedPosition = videoPlayer.getCurrentPosition();
  videoPlayer.stopPlayback();
  // Hide the buttons and seek bar controlling the video view.
  videoPlayer.setMediaController(null);
}

private void resumeContent() {
  Log.i(LOGTAG, "resumeContent");

  // Show the buttons and seek bar controlling the video view.
  videoPlayer.setVideoPath(SAMPLE_VIDEO_URL);
  videoPlayer.setMediaController(mediaController);
  videoPlayer.setOnPreparedListener(
      mediaPlayer -> {
        if (savedPosition > 0) {
          mediaPlayer.seekTo(savedPosition);
        }
        mediaPlayer.start();
      });
  videoPlayer.setOnCompletionListener(
      mediaPlayer -> videoAdPlayerAdapter.notifyImaOnContentCompleted());
}

12. Solicitar anúncios

Agora, adicione o método requestAds para criar um AdsRequest e use-o para chamar AdsLoader.requestAds():

private void requestAds(String adTagUrl) {
  // Create the ads request.
  AdsRequest request = sdkFactory.createAdsRequest();
  request.setAdTagUrl(adTagUrl);
  request.setContentProgressProvider(
      () -> {
        if (videoPlayer.getDuration() <= 0) {
          return VideoProgressUpdate.VIDEO_TIME_NOT_READY;
        }
        return new VideoProgressUpdate(
            videoPlayer.getCurrentPosition(), videoPlayer.getDuration());
      });

  // Request the ad. After the ad is loaded, onAdsManagerLoaded() will be called.
  adsLoader.requestAds(request);
}

Agora você está solicitando e mostrando anúncios com o SDK do IMA. Para saber mais sobre recursos avançados, consulte os outros guias ou os exemplos no GitHub.