Los SDK de IMA facilitan la integración de los anuncios multimedia en sus sitios web y aplicaciones. Los SDK de IMA pueden solicitar anuncios de cualquier servidor de anuncios compatible con VAST y administrar la reproducción de anuncios en sus aplicaciones. Con los SDK del cliente de IMA, usted controla la reproducción del contenido de video, mientras que el SDK controla la reproducción de anuncios. Los anuncios se reproducen en un reproductor de video independiente ubicado encima del reproductor de video de contenido de la app.
En esta guía, se muestra cómo integrar el SDK de IMA en un proyecto de Android Studio vacío con Android VideoView para mostrar contenido y anuncios. Para continuar con una integración de muestra completa, descarga el BasicExample de GitHub.
Descripción general del cliente de IMA
La implementación del cliente de IMA implica cuatro componentes principales del SDK, que se muestran en esta guía:
AdDisplayContainer
: Un objeto de contenedor en el que se renderizan los anuncios.AdsLoader
: Un objeto que solicita anuncios y controla eventos de respuestas de solicitud de anuncios. Solo debes crear una instancia de cargador de anuncios, que puedes volver a usar durante la vida útil de la aplicación.AdsRequest
: un objeto que define una solicitud de anuncios. Las solicitudes de anuncios especifican la URL de la etiqueta de anuncio de VAST y parámetros adicionales, como las dimensiones del anuncio.AdsManager
: Un objeto que contiene la respuesta a la solicitud de anuncios, controla la reproducción de anuncios y detecta eventos de anuncios que activa el SDK.
Requisitos previos
1. 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 Empty Activity.
- Haz clic en Siguiente.
- En la página Configure your project, asígnale un nombre y selecciona Java para el lenguaje.
- Haz clic en Finalizar.
2. Agregue el SDK de IMA a su proyecto
Primero, en el archivo build.gradle de nivel de aplicación, agregue importaciones para el SDK de IMA a la sección de dependencias. Debido al tamaño del SDK de IMA, implemente y habilite multidex aquí. Esto es necesario para las apps con minSdkVersion
establecido en 20 o una versión anterior. Además, agrega un objeto compileOptions
nuevo para especificar la información de compatibilidad de la versión de Java.
android { compileSdkVersion 32 compileOptions { sourceCompatibility JavaVersion.VERSION_11 targetCompatibility JavaVersion.VERSION_11 } } defaultConfig { applicationId "com.google.ads.interactivemedia.v3.samples.videoplayerapp" minSdkVersion 16 targetSdkVersion 32 multiDexEnabled true versionCode 1 versionName "1.0" } ... } dependencies { implementation 'androidx.appcompat:appcompat:1.4.1' implementation 'androidx.multidex:multidex:2.0.1' implementation 'androidx.browser:browser:1.4.0' implementation 'androidx.media:media:1.6.0' implementation 'com.google.ads.interactivemedia.v3:interactivemedia:3.29.0' ... }
3. Agregue los permisos requeridos del SDK de IMA
Agregue 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>
4. Actualiza el diseño de la app
Actualiza el diseño de la app de modo que incluya un VideoView
para reproducir contenido y anuncios.
<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: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:textSize="@dimen/font_size" /> </FrameLayout> </LinearLayout>
5. Importe IMA en la actividad principal
Agregue las instrucciones de importación para el SDK de IMA. Luego, actualiza la clase MyActivity
para extender AppCompatActivity
. La clase AppCompatActivity
permite usar las funciones más recientes de la plataforma en dispositivos Android anteriores. Luego, agrega un conjunto de variables privadas que se usarán en la app.
import android.content.Context; import android.media.AudioManager; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.util.Log; import android.view.View; import android.view.ViewGroup; import android.widget.MediaController; import android.widget.VideoView; 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.AdsManagerLoadedEvent; 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; ... 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&impl=s&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 View playButton; private VideoAdPlayerAdapter videoAdPlayerAdapter; }
6. Cómo crear la clase VideoAdPlayerAdapter
Crear una clase VideoAdPlayerAdapter
con la VideoView
y adaptarla a la interfaz VideoAdPlayer
de IMA Esta clase controlará el contenido y la reproducción de anuncios, y contendrá el conjunto de métodos que un reproductor de video debe implementar para que lo use el SDK de 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; } }
7. Cómo anular los métodos VideoAdPlayer
Anula los siguientes métodos VideoAdPlayer
:
El método playAd()
establece el contenido o la URL del anuncio y un objeto de escucha para iniciar la reproducción una vez que se carga el contenido multimedia.
/** Example implementation of IMA's VideoAdPlayer interface. */ public class VideoAdPlayerAdapter implements VideoAdPlayer { ... @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); }
8. Cómo configurar el seguimiento de anuncios
Para que se puedan registrar eventos de anuncios,
se debe llamar a VideoAdPlayerCallback.onAdProgress
a medida que avanza el contenido y los anuncios. Para admitir esta función, configura un temporizador para llamar a onAdProgress()
en un intervalo establecido.
/** Example implementation of IMA's VideoAdPlayer interface. */ public class VideoAdPlayerAdapter implements VideoAdPlayer { ... 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); } }
9. Inicie IMA en el método onCreate
.
Reemplace el método onCreate
y agregue las asignaciones de variables requeridas para iniciar IMA. En este paso, crea lo siguiente:
ImaSdkSettings
AdsLoader
En este paso, también se crea un VideoAdPlayerAdapter
, una clase que crearás más adelante en esta guía.
Por último, configura el botón de reproducción para solicitar anuncios y, luego, ocúltalo cuando hagas clic.
app/src/main/java/com/example/project name/MyActivity.java... public class MyActivity extends AppCompatActivity { ... private VideoView videoPlayer; private MediaController mediaController; private View playButton; private VideoAdPlayerAdapter videoAdPlayerAdapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_my); // 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. ViewGroup videoPlayerContainer = findViewById(R.id.videoPlayerContainer); AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE); videoAdPlayerAdapter = new VideoAdPlayerAdapter(videoPlayer, audioManager); sdkFactory = ImaSdkFactory.getInstance(); AdDisplayContainer adDisplayContainer = ImaSdkFactory.createAdDisplayContainer(videoPlayerContainer, videoAdPlayerAdapter); // Create an AdsLoader. ImaSdkSettings settings = sdkFactory.createImaSdkSettings(); adsLoader = sdkFactory.createAdsLoader(this, settings, adDisplayContainer); // When the play button is clicked, request ads and hide the button. playButton = findViewById(R.id.playButton); playButton.setOnClickListener( view -> { videoPlayer.setVideoPath(SAMPLE_VIDEO_URL); requestAds(SAMPLE_VAST_TAG_URL); view.setVisibility(View.GONE); }); } }
10. Cómo agregar objetos de escucha de AdsLoader
Agrega objetos de escucha para addAdErrorListener
y addAdsLoadedListener
. En AdsLoadedListener
, crea el AdsManager
y configura el objeto de escucha de error AdsManager
.
@Override protected void onCreate(Bundle savedInstanceState) { ... // Create an AdsLoader. ImaSdkSettings settings = sdkFactory.createImaSdkSettings(); adsLoader = sdkFactory.createAdsLoader(this, settings, adDisplayContainer); // 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( new AdsLoader.AdsLoadedListener() { @Override public void onAdsManagerLoaded(AdsManagerLoadedEvent 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(); } }); } });
11. Cómo controlar eventos de anuncios de IMA
Detectar eventos de anuncios de IMA con AdsManager.addAdEventListener
Con una instrucción de cambio, configure acciones para los siguientes eventos de IMA:
El fragmento de código incluye comentarios con más información sobre cómo usar los eventos. Una vez que se configuren los eventos, podrás llamar a AdsManager.init()
.
adsLoader.addAdsLoadedListener( new AdsLoader.AdsLoadedListener() { @Override public void onAdsManagerLoaded(AdsManagerLoadedEvent adsManagerLoadedEvent) { ... 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(); break; case CONTENT_PAUSE_REQUESTED: // AdEventType.CONTENT_PAUSE_REQUESTED is fired when you // should pause your content and start playing an ad. pauseContentForAds(); break; case CONTENT_RESUME_REQUESTED: // AdEventType.CONTENT_RESUME_REQUESTED is fired when the ad // you should play your content. resumeContent(); break; case ALL_ADS_COMPLETED: // Calling adsManager.destroy() triggers the function // VideoAdPlayer.release(). adsManager.destroy(); adsManager = null; break; 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. break; default: break; } } }); AdsRenderingSettings adsRenderingSettings = ImaSdkFactory.getInstance().createAdsRenderingSettings(); adsManager.init(adsRenderingSettings); }
12. Controla el cambio entre anuncios y contenido
En esta sección, crea los métodos pauseContentForAds
y resumeContent
a los que se hace referencia en los pasos anteriores. Estos métodos reutilizarán el reproductor para reproducir contenido y anuncios. Tendrás que hacer un seguimiento de la posición del contenido para reanudar la reproducción después de la pausa publicitaria.
/** Main activity. */ public class MyActivity extends AppCompatActivity { ... 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()); } }
13. Solicitar anuncios
Ahora agrega el método requestAds
para compilar un AdsRequest
y usarlo a fin de llamar a AdsLoader.requestAds()
.
/** Main activity. */ public class MyActivity extends AppCompatActivity { ... 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); } }
Listo. Ahora está solicitando y mostrando anuncios con el SDK de IMA. Para obtener información sobre las funciones adicionales del SDK, consulta las otras guías o las muestras en GitHub.