Comienza a usar la extensión de IMA de ExoPlayer

ExoPlayer es un reproductor multimedia a nivel de la aplicación para Android. En esta guía, se muestra cómo puedes usar la extensión de IMA de ExoPlayer, que une el SDK de DAI para Android de IMA, a fin de solicitar y reproducir una transmisión de contenido multimedia con anuncios y contenido.

Estos son algunos de los beneficios de la extensión:

  • Simplifica el código necesario para integrar el IMA con las funciones.
  • Reduce el tiempo de desarrollo necesario para actualizar a nuevas versiones de IMA.

La extensión de IMA de ExoPlayer admite protocolos de transmisión HLS y DASH. A continuación, se incluye un resumen:

Compatibilidad con la transmisión de la extensión de IMA de ExoPlayer
Transmisión en vivo Transmisiones de VOD
HLS Marca de verificación Marca de verificación
DASH Marca de verificación Marca de verificación

Las transmisiones en vivo de DASH son compatibles con la versión 1.1.0 o posterior de ExoPlayer-IMA.

Esta guía se basa en la guía de ExoPlayer y muestra cómo crear una app completa e integrar la extensión. Consulta ExoPlayerExample en GitHub para ver un ejemplo con una app de ejemplo completa.

Requisitos previos

Cómo crear un proyecto nuevo de Android Studio

Para crear tu proyecto de Android Studio, sigue estos pasos:

  • Inicia Android Studio.
  • Selecciona Start a new Android Studio project.
  • En la página Choose your project, selecciona la plantilla No Activity.
  • Haz clic en Siguiente.
  • En la página Configure your project, asígnale un nombre al proyecto y selecciona Java para el lenguaje.

  • Haz clic en Finalizar.

Agrega la extensión de IMA de ExoPlayer a tu proyecto.

Agrega importaciones para la extensión al archivo build.gradle a nivel de la aplicación en la sección dependencies.

Configura tu app para y habilita multidex. Esto es necesario debido al tamaño de la extensión y se requiere para las apps con minSdkVersion configurado en Android 4.4W (nivel de API 20) o versiones anteriores.

Por ejemplo:

app/build.gradle

android {

  ...

  defaultConfig {
      applicationId "com.google.ads.interactivemedia.v3.samples.videoplayerapp"
      minSdkVersion 19
      targetSdkVersion 34
      multiDexEnabled true
      versionCode 1
      versionName "1.0"
  }

    ...
}
dependencies {
    implementation 'androidx.multidex:multidex:2.0.1'
    implementation 'androidx.media3:media3-ui:1.1.1'
    implementation 'androidx.media3:media3-exoplayer:1.1.1'
    implementation 'androidx.media3:media3-exoplayer-hls:1.1.1'
    implementation 'androidx.media3:media3-exoplayer-dash:1.1.1'

    // Adding the ExoPlayer IMA extension for ads will also include the IMA
    // SDK as a dependency.
    implementation 'androidx.media3:media3-exoplayer-ima:1.1.1'
}

Agrega los permisos de usuario que requiere el SDK de IMA para solicitar anuncios:

app/src/main/AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.project name">

    <!-- Required permissions for the IMA SDK -->
    <uses-permission android:name="android.permission.INTERNET"/>
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>

    ...

</manifest>

Agrega declaraciones de intents

Si la app se orienta a Android 11 (nivel de API 30) o versiones posteriores, las versiones actuales y recientes del SDK de IMA requieren una declaración explícita de intención para abrir vínculos web. Agrega el siguiente fragmento al archivo de manifiesto de tu app para habilitar la tasa de clics en el anuncio (los usuarios que hacen clic en el botón Más información).

  <?xml version="1.0" encoding="utf-8"?>
  <manifest xmlns:android="http://schemas.android.com/apk/res/android"
      package="com.example.project name">

      ...

    </application>

    <queries>
      <intent>
          <action android:name="android.intent.action.VIEW" />
          <data android:scheme="https" />
      </intent>
      <intent>
          <action android:name="android.intent.action.VIEW" />
          <data android:scheme="http" />
      </intent>
    </queries>
  </manifest>

Configura la IU de ExoPlayer

Crea el objeto PlayerView para que ExoPlayer lo use.

Cambia androidx.constraintlayout.widget.ConstraintLayout a LinearLayout, que se recomienda para la extensión de IMA de ExoPlayer.

Por ejemplo:

app/src/main/res/layout/activity_my.xml

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

    <androidx.media3.ui.PlayerView
        android:id="@+id/player_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</LinearLayout>

Agrega tus parámetros de transmisión

Consulta la página de transmisión de muestra de IMA para ver ejemplos de recursos de transmisión para probar el proyecto. Consulta también la sección de Ad Manager sobre la DAI para obtener información sobre la configuración de tus propias transmisiones.

En este paso, se muestra la configuración de una transmisión en vivo, pero la extensión de IMA de ExoPlayer también admite transmisiones de DAI para VOD. Consulta el paso para transmisiones de video on demand (VOD) a fin de ver qué cambios necesita tu app para manejar transmisiones de VOD.

Importa la extensión de IMA de ExoPlayer

Agrega las sentencias de importación para la extensión de ExoPlayer.

Agrega las siguientes variables privadas a MyActivity.java:

Agrega la clave de recursos de HLS de Big Buck Bunny (en vivo) para probarla con esta transmisión. Hay más transmisiones disponibles para probar en la página de transmisiones de muestra de IMA.

Crea una constante KEY_ADS_LOADER_STATE para guardar y recuperar el estado AdsLoader.

Por ejemplo:

app/src/main/java/com/example/project name/MyActivity.java


import static androidx.media3.common.C.CONTENT_TYPE_HLS;

import android.app.Activity;
import android.net.Uri;
import android.os.Bundle;
import androidx.annotation.Nullable;
import androidx.annotation.OptIn;
import androidx.media3.common.MediaItem;
import androidx.media3.common.util.Util;
import androidx.media3.datasource.DataSource;
import androidx.media3.datasource.DefaultDataSource;
import androidx.media3.exoplayer.ExoPlayer;
import androidx.media3.exoplayer.ima.ImaServerSideAdInsertionMediaSource;
import androidx.media3.exoplayer.ima.ImaServerSideAdInsertionUriBuilder;
import androidx.media3.exoplayer.source.DefaultMediaSourceFactory;
import androidx.media3.exoplayer.util.EventLogger;
import androidx.media3.ui.PlayerView;
import androidx.multidex.MultiDex;

...

public class MyActivity extends Activity {

  private static final String KEY_ADS_LOADER_STATE = "ads_loader_state";
  private static final String SAMPLE_ASSET_KEY = "c-rArva4ShKVIAkNfy6HUQ";

  private PlayerView playerView;
  private ExoPlayer player;
  private ImaServerSideAdInsertionMediaSource.AdsLoader adsLoader;
  private ImaServerSideAdInsertionMediaSource.AdsLoader.State adsLoaderState;

}

Crea una instancia de adsLoader

Reemplaza el método onCreate para encontrar el PlayerView y buscar un AdsLoader.State guardado, que se puede usar cuando se inicia el objeto adsLoader.

Además, habilita multidex si lo requiere el recuento de métodos de tu app y minSdkVersion (como se explica en el paso 2).

Por ejemplo:

app/src/main/java/com/example/project name/MyActivity.java

...

public class MyActivity extends Activity {

  private static final String KEY_ADS_LOADER_STATE = "ads_loader_state";
  private static final String SAMPLE_ASSET_KEY = "c-rArva4ShKVIAkNfy6HUQ";

  private PlayerView playerView;
  private ExoPlayer player;
  private ImaServerSideAdInsertionMediaSource.AdsLoader adsLoader;
  private ImaServerSideAdInsertionMediaSource.AdsLoader.State adsLoaderState;

  @Override
  protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_my);
    MultiDex.install(this);

    playerView = findViewById(R.id.player_view);

    // Checks if there is a saved AdsLoader state to be used later when
    // initiating the AdsLoader.
    if (savedInstanceState != null) {
      Bundle adsLoaderStateBundle = savedInstanceState.getBundle(KEY_ADS_LOADER_STATE);
      if (adsLoaderStateBundle != null) {
        adsLoaderState =
            ImaServerSideAdInsertionMediaSource.AdsLoader.State.CREATOR.fromBundle(
                adsLoaderStateBundle);
      }
    }
  }

}

Agrega métodos para inicializar el reproductor

Agrega un método para inicializar el reproductor y haz lo siguiente:

  • Crea una instancia de AdsLoader.
  • Crea el ExoPlayer:
  • Crea un elemento MediaItem con la clave del activo de la transmisión en vivo.
  • Configura MediaItem en tu reproductor.

Por ejemplo:

app/src/main/java/com/example/project name/MyActivity.java

public class MyActivity extends Activity {

  ...

  
  // Create a server side ad insertion (SSAI) AdsLoader.
  private ImaServerSideAdInsertionMediaSource.AdsLoader createAdsLoader() {
    ImaServerSideAdInsertionMediaSource.AdsLoader.Builder adsLoaderBuilder =
        new ImaServerSideAdInsertionMediaSource.AdsLoader.Builder(this, playerView);

    // Attempt to set the AdsLoader state if available from a previous session.
    if (adsLoaderState != null) {
      adsLoaderBuilder.setAdsLoaderState(adsLoaderState);
    }

    return adsLoaderBuilder.build();
  }

  private void initializePlayer() {
    adsLoader = createAdsLoader();

    // Set up the factory for media sources, passing the ads loader.
    DataSource.Factory dataSourceFactory = new DefaultDataSource.Factory(this);
    DefaultMediaSourceFactory mediaSourceFactory = new DefaultMediaSourceFactory(dataSourceFactory);

    // MediaSource.Factory to create the ad sources for the current player.
    ImaServerSideAdInsertionMediaSource.Factory adsMediaSourceFactory =
        new ImaServerSideAdInsertionMediaSource.Factory(adsLoader, mediaSourceFactory);

    // 'mediaSourceFactory' is an ExoPlayer component for the DefaultMediaSourceFactory.
    // 'adsMediaSourceFactory' is an ExoPlayer component for a MediaSource factory for IMA server
    // side inserted ad streams.
    mediaSourceFactory.setServerSideAdInsertionMediaSourceFactory(adsMediaSourceFactory);

    // Create an ExoPlayer and set it as the player for content and ads.
    player = new ExoPlayer.Builder(this).setMediaSourceFactory(mediaSourceFactory).build();
    playerView.setPlayer(player);
    adsLoader.setPlayer(player);

    // Build an IMA SSAI media item to prepare the player with.
    Uri ssaiLiveUri =
        new ImaServerSideAdInsertionUriBuilder()
            .setAssetKey(SAMPLE_ASSET_KEY)
            .setFormat(CONTENT_TYPE_HLS) // Use CONTENT_TYPE_DASH for dash streams.
            .build();

    // Create the MediaItem to play, specifying the stream URI.
    MediaItem ssaiMediaItem = MediaItem.fromUri(ssaiLiveUri);

    // Prepare the content and ad to be played with the ExoPlayer.
    player.setMediaItem(ssaiMediaItem);
    player.prepare();

    // Set PlayWhenReady. If true, content and ads will autoplay.
    player.setPlayWhenReady(false);
  }
}

Agrega un método para liberar el reproductor

Agrega un método para liberar el reproductor en esta secuencia:

  • Establece las referencias del reproductor en nulas y libera sus recursos.
  • Libera el estado de adsLoader.

app/src/main/java/com/example/project name/MyActivity.java

public class MyActivity extends Activity {

  ...

  private void releasePlayer() {
    // Set the player references to null and release the player's resources.
    playerView.setPlayer(null);
    player.release();
    player = null;

    // Release the adsLoader state so that it can be initiated again.
    adsLoaderState = adsLoader.release();
  }

Cómo controlar eventos del reproductor

Por último, crea devoluciones de llamada para los eventos del ciclo de vida de la actividad a fin de controlar la reproducción de la transmisión.

Para admitir el SDK de Android 24 y versiones posteriores, haz lo siguiente:

Para admitir versiones del SDK de Android anteriores a la 24, haz lo siguiente: - onResume() - onPause()

onStart() y onResume() se asignan a playerView.onResume(), y onStop() y onPause() se asignan a playerView.onPause().

En este paso, también se usa el evento onSaveInstanceState() para intentar guardar los adsLoaderState.

app/src/main/java/com/example/project name/MyActivity.java

public class MyActivity extends Activity {

  ...

  @Override
  public void onStart() {
    super.onStart();
    if (Util.SDK_INT > 23) {
      initializePlayer();
      if (playerView != null) {
        playerView.onResume();
      }
    }
  }

  @Override
  public void onResume() {
    super.onResume();
    if (Util.SDK_INT <= 23 || player == null) {
      initializePlayer();
      if (playerView != null) {
        playerView.onResume();
      }
    }
  }

  @Override
  public void onPause() {
    super.onPause();
    if (Util.SDK_INT <= 23) {
      if (playerView != null) {
        playerView.onPause();
      }
      releasePlayer();
    }
  }

  @Override
  public void onStop() {
    super.onStop();
    if (Util.SDK_INT > 23) {
      if (playerView != null) {
        playerView.onPause();
      }
      releasePlayer();
    }
  }

  @Override
  public void onSaveInstanceState(Bundle outState) {
    // Attempts to save the AdsLoader state to handle app backgrounding.
    if (adsLoaderState != null) {
      outState.putBundle(KEY_ADS_LOADER_STATE, adsLoaderState.toBundle());
    }
  }

  ...

}

Configuración de la transmisión de VOD (opcional)

Si es necesario que tu app reproduzca contenido de VOD con anuncios, deberás hacer lo siguiente:

  1. Agrega un CMS ID y un Video ID para una transmisión de prueba de VOD.
  2. Crea un URI de SSAI para VOD mediante ImaServerSideAdInsertionUriBuilder().
  3. Usa este URI nuevo como elemento multimedia de tu reproductor.

app/src/main/java/com/example/project name/MyActivity.java

public class MyActivity extends Activity {

  private static final String KEY_ADS_LOADER_STATE = "ads_loader_state";
  private static final String SAMPLE_ASSET_KEY = "c-rArva4ShKVIAkNfy6HUQ";
  private static final String SAMPLE_CMS_ID = "2528370";
  private static final String SAMPLE_VIDEO_ID = "tears-of-steel";

  ...

  private void initializePlayer() {

     ...

    Uri ssaiVodUri =
        new ImaServerSideAdInsertionUriBuilder()
            .setContentSourceId(SAMPLE_CMS_ID)
            .setVideoId(SAMPLE_VIDEO_ID)
            .setFormat(CONTENT_TYPE_HLS)
            .build();

    // Create the MediaItem to play, specifying the stream URI.
    MediaItem ssaiMediaItem = MediaItem.fromUri(ssaiVodUri);

    // Prepare the content and ad to be played with the ExoPlayer.
    player.setMediaItem(ssaiMediaItem);
    player.prepare();

    // Set PlayWhenReady. If true, content and ads will autoplay.
    player.setPlayWhenReady(false);
  }

Listo. Ahora solicitas y reproduces una transmisión multimedia con la extensión de IMA de ExoPlayer. Consulta las muestras de Android DAI en GitHub para obtener el código completo.