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 de IMA, para 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 IMA con funciones.
- Reduce el tiempo de desarrollo necesario para actualizar a versiones nuevas de IMA.
La extensión IMA de ExoPlayer admite los protocolos de transmisión HLS y DASH. Aquí tienes un resumen:
Compatibilidad con la transmisión de extensiones de ExoPlayer-IMA | ||
---|---|---|
Transmisión en vivo | Transmisiones de VOD | |
HLS | ||
DASH |
Las transmisiones en vivo de DASH son compatibles con la versión 1.1.0 y versiones posteriores de ExoPlayer-IMA.
Esta guía se basa en la guía de ExoPlayer y muestra cómo crear una app completa y, luego, integrar la extensión. Consulta ExoPlayerExample
de GitHub para ver un ejemplo con una app de ejemplo completa.
Requisitos previos
- Android Studio
- ExoPlayer de AndroidX Media3 versión 1.0.0 o una posterior para la compatibilidad con DAI
Cómo crear un nuevo proyecto 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 Elige tu proyecto, selecciona la plantilla No Activity.
- Haz clic en Siguiente.
En la página Configura tu proyecto, asigna un nombre a tu proyecto y selecciona Java para el lenguaje.
Haz clic en Finalizar.
Agrega la extensión IMA de ExoPlayer a tu proyecto
Agrega importaciones para la extensión al archivo build.gradle de nivel de la aplicación en la sección dependencies
.
Configura tu app y habilita multidex. Esto es necesario debido al tamaño de la extensión y es obligatorio 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 21 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 del usuario que requiere el SDK de DAI 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 DAI SDK --> <uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/> ... </manifest>
Cómo agregar declaraciones de intents
Si tu app se orienta a Android 11 (nivel de API 30) o versiones posteriores, las versiones actuales y recientes del SDK de IMA DAI requieren una declaración explícita de la intención de abrir vínculos web. Agrega el siguiente fragmento al archivo de manifiesto de tu app para habilitar los clics en el anuncio (cuando los usuarios 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
que usará ExoPlayer.
Cambia el androidx.constraintlayout.widget.ConstraintLayout
a un 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 flujo de muestras de IMA para obtener recursos de flujo de muestras con los que probar tu proyecto. Consulta también la sección de Ad Manager sobre la DAI para obtener información sobre cómo configurar tus propios flujos.
En este paso, se muestra cómo configurar una transmisión en vivo, pero la extensión IMA de ExoPlayer también admite transmisiones de VOD de DAI. Consulta el paso para las transmisiones de video on demand (VOD) para ver qué cambios debe realizar tu app para controlar las transmisiones de VOD.
Importa la extensión IMA de ExoPlayer
Agrega las instrucciones de importación para la extensión de ExoPlayer.
Agrega las siguientes variables privadas a MyActivity.java
:
PlayerView
ExoPlayer
ImaServerSideAdInsertionMediaSource.AdsLoader
ImaServerSideAdInsertionMediaSource.AdsLoader.State
Agrega la clave de recurso de la transmisión 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 comprobar si hay un AdsLoader.State
guardado, que se puede usar cuando se inicia el objeto adsLoader
.
Además, habilita multidex si el recuento de métodos y minSdkVersion
de tu app lo requieren (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.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
MediaItem
con la clave del activo de la transmisión en vivo. - Establece el
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 al jugador en esta secuencia:
- Establece las referencias del reproductor como 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(); }
Controla eventos del jugador
Por último, crea devoluciones de llamada para los eventos del ciclo de vida de la actividad para controlar la reproducción de transmisiones.
Para admitir la versión 24 o posterior del SDK de Android, 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 el 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 del flujo de VOD (opcional)
Si tu app debe reproducir contenido de VOD con anuncios, deberás hacer lo siguiente:
- Agrega un
CMS ID
y unVideo ID
para una transmisión de prueba de VOD. - Crea un URI de VOD de SSAI con
ImaServerSideAdInsertionUriBuilder()
. - Usa este nuevo URI como el 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 = "2548831"; 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); }
Eso es todo. Ahora, solicitas y reproduces una transmisión de contenido multimedia con la extensión IMA de ExoPlayer. Consulta los ejemplos de DAI de Android en GitHub para ver el código completo.