Reproducción de anuncios personalizados con el SDK de IMA para Android

La forma más rápida y sencilla de integrar el SDK de IMA para Android en tu app es hacer que el SDK controle toda la lógica de reproducción de anuncios mientras la app se enfoca en reproducir videos de contenido. Este enfoque, llamado "Reproducción de anuncios del SDK", es la opción predeterminada en Comenzar.

Sin embargo, si también quieres reproducir anuncios en tu reproductor de video, el SDK proporciona una interfaz para eso. Nos referimos a este enfoque como "reproducción de anuncios personalizados" y, en el resto de esta guía, se explica su implementación.

Requisitos previos

  • Una integración básica de IMA

Te recomendamos que consultes el Ejemplo avanzado en GitHub como punto de partida si actualmente no tienes una integración básica de IMA. En este ejemplo, ya se implementa la reproducción de anuncios personalizados. En el resto de esta guía, se describirán las funciones necesarias para la reproducción de anuncios personalizados con anuncios de IMA.

Interfaz con VideoAdPlayer

La reproducción de anuncios personalizados requiere que tu app implemente la interfaz VideoAdPlayer. El SDK usa esta interfaz para notificar a tu app a fin de que reproduzca videos de anuncios. Tu app también usa esta interfaz para informar al SDK sobre eventos importantes de anuncios de video. Sigue estos pasos para implementar la interfaz.

Cómo crear un VideoAdPlayer

El primer paso es crear una clase VideoAdPlayer anónima en requestAds():

private VideoAdPlayer videoAdPlayer;
...

private void requestAds(String adTagUrl) {
    videoAdPlayer = new VideoAdPlayer() {
    };
}

Cómo agregar métodos de video

A continuación, agrega métodos que le indiquen a tu reproductor de video que reproduzca, cargue, detenga y pause videos publicitarios. También agregamos los métodos para liberar el reproductor y obtener el volumen aquí:

videoAdPlayer = new VideoAdPlayer() {
        @Override
        public void playAd() {
            if (mIsAdDisplayed) {
                videoPlayer.resume();
            } else {
                isAdDisplayed = true;
                videoPlayer.play();
            }
        }

        @Override
        public void loadAd(String url) {
            isAdDisplayed = true;
            videoPlayer.setVideoPath(url);
        }
        @Override
        public void stopAd() {
            videoPlayer.stopPlayback();
        }
        @Override
        public void pauseAd() {
            videoPlayer.pause();
        }

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

        @Override
        public int getVolume() {
            return videoPlayer.getVolume();
        }
};

Estos métodos son wrappers finos para los métodos similares propios de tu reproductor de video. Ten en cuenta que estos métodos establecen una variable interna que se usa para hacer un seguimiento de si se muestra un anuncio. En la reproducción de anuncios personalizados, el reproductor de video reproduce videos de contenido y anuncios de video, por lo que debes hacer un seguimiento de qué se muestra en el momento.

Progreso de la reproducción de anuncios

La interfaz VideoAdPlayer implementa otra interfaz, AdProgressProvider, por lo que también debes implementarla. Solo tiene un método, getAdProgress(), que el SDK usa para obtener información de reproducción de anuncios. Agrégala a tu clase VideoAdPlayer anónima, debajo de los otros métodos:

VideoAdPlayer videoAdPlayer = new VideoAdPlayer() {
        ...
        @Override
        public VideoProgressUpdate getAdProgress() {
            if (!isAdDisplayed || videoPlayer.getDuration() <= 0) {
                return VideoProgressUpdate.VIDEO_TIME_NOT_READY;
            }
            return new VideoProgressUpdate(videoPlayer.getCurrentPosition(),
                    videoPlayer.getDuration());
        }
};

getAdProgress() muestra un tipo VideoProgressUpdate, que debe consistir en la posición y duración actuales del video. Si el reproductor no reproduce un anuncio o la duración no está disponible, haz que muestre VideoProgressUpdate.VIDEO_TIME_NOT_READY como se ve en el ejemplo.

Administra las devoluciones de llamada de video

La reproducción de anuncios personalizados requiere que tu app informe al SDK sobre eventos de video importantes. Desde la vista del SDK, estas son devoluciones de llamada que se describe en la interfaz VideoAdPlayer.VideoAdPlayerCallback. Antes de entrar en los métodos de devolución de llamada, debes poder agregar y quitar las devoluciones de llamada a la solicitud del SDK. Esto se hace dentro de VideoAdPlayer con addCallback() y removeCallback():

private List<VideoAdPlayerCallback> adCallbacks = new ArrayList<>(1);

VideoAdPlayer videoAdPlayer = new VideoAdPlayer() {
        ...
        @Override
        public void addCallback(VideoAdPlayerCallback videoAdPlayerCallback) {
            adCallbacks.add(videoAdPlayerCallback);
        }

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

Esta implementación usa un List<> para las devoluciones de llamada en las que se llama a los métodos List<>.add() y remove().

Llama a las devoluciones de llamada

Ahora que el SDK tiene una manera de indicarle a tu app que agregue y quite devoluciones de llamada, define los lugares en los que se llama a la devolución de llamada. Tu app necesita llamar a estas devoluciones de llamada cuando ocurren eventos de video importantes, como reproducir, pausar o reanudar un video, o bien cuando un video finaliza o experimenta un error.

Para ello, expande SampleVideoPlayer a fin de tener un objeto de escucha de estos eventos de video que se agregan desde VideoFragment. El motivo para crear un objeto de escucha independiente en SampleVideoPlayer para llamar a estas devoluciones de llamada de anuncios es que SampleVideoPlayer no sabe nada sobre los anuncios, por lo que debes reenviar sus eventos de video a algo que pueda manejar anuncios.

public interface OnVideoEventsListener {
    void onPlay();
    void onResume();
    void onPause();
    void onError();
}

private final List<OnVideoEventsListener> onVideoEventsListeners = new ArrayList<>(1);

public void addVideoEventsListener(OnVideoEventsListener listener) {
    onVideoEventsListeners.add(listener);
}

Iniciar, detener y reanudar

Crea una enumeración nueva para realizar un seguimiento del estado de la reproducción y agrega anulaciones nuevas para los métodos start() y pause() en SampleVideoPlayer:

private enum PlaybackState {
    STOPPED, PAUSED, PLAYING
}

private PlaybackState playbackState = PlaybackState.STOPPED;

@Override
public void start() {
    super.start();
    switch (playbackState) {
        case STOPPED:
            for (OnVideoEventsListener listener : onVideoEventsListeners) {
                listener.onPlay();
            }
            break;
        case PAUSED:
            for (OnVideoEventsListener listener : onVideoEventsListeners) {
                listener.onResume();
            }
            break;
        default:
            // Already playing; do nothing.
            break;
    }
    playbackState = PlaybackState.PLAYING;
}

@Override
public void pause() {
    super.pause();
    playbackState = PlaybackState.PAUSED;
    for (OnVideoEventsListener listener : onVideoEventsListeners) {
        listener.onPause();
    }
}

Cómo solucionar errores

Anula el objeto de escucha de errores anónimo del reproductor de video que configuraste en init():

@Override
public boolean onError(MediaPlayer mp, int what, int extra) {
    playbackState = PlaybackState.STOPPED;
    for (OnVideoEventsListener listener : onVideoEventsListeners) {
        listener.onError();
    }

    // Returning true signals to MediaPlayer that the error was handled.
    // This  prevents the completion handler from being called.
    return true;
}

Implementa el objeto de escucha

Vuelve a VideoFragment y agrega un OnVideoEventsListener anónimo a tu instancia de SampleVideoPlayer:

mVideoPlayer.addVideoEventsListener(new OnVideoEventsListener() {
    @Override
    public void onPlay() {
        if (isAdDisplayed) {
            for (VideoAdPlayerCallback callback : adCallbacks) {
                callback.onPlay();
            }
        }
    }

    @Override
    public void onResume() {
        if (isAdDisplayed) {
            for (VideoAdPlayerCallback callback : adCallbacks) {
                callback.onResume();
            }
        }
    }

    @Override
    public void onPause() {
        if (isAdDisplayed) {
            for (VideoAdPlayerCallback callback : adCallbacks) {
                callback.onPause();
            }
        }
    }

    @Override
    public void onError() {
        if (isAdDisplayed) {
            for (VideoAdPlayerCallback callback : adCallbacks) {
                callback.onError();
            }
        }
    }
});

Cambia el método onVideoCompleted() de OnVideoCompletedListener para controlar el caso de que finalizó un video de anuncio:

public void onVideoCompleted() {
    // Handle completed event for playing post-rolls.
    if (isAdDisplayed) {
        for (VideoAdPlayerCallback callback : adCallbacks) {
            callback.onEnded();
        }
    } else {
        if (adsLoader != null) {
            adsLoader.contentComplete();
    }
}

Cómo alternar entre el contenido y los anuncios

En este ejemplo, se usa la misma instancia del reproductor de video para reproducir contenido y anuncios, por lo que debes agregar lógica para alternar entre el contenido y los anuncios en tu reproductor. Luego, puedes volver a cargar y buscar el video de contenido para volver al punto en el que comenzó el anuncio. Para ello, agrega dos funciones:

private int savedContentPosition = 0;

private void pauseContent() {
    savedContentPosition = videoPlayer.getCurrentPosition();
    videoPlayer.stopPlayback();
    isAdDisplayed = true;
}

private void resumeContent() {
    videoPlayer.setVideoPath(getString(R.string.content_url));
    videoPlayer.seekTo(mSavedContentPosition);
    videoPlayer.play();
    isAdDisplayed = false;
}

Se llama a estos cuando se reciben los eventos CONTENT_PAUSE_REQUESTED y CONTENT_RESUME_REQUESTED, en VideoFragment.onAdEvent(), respectivamente:

case CONTENT_PAUSE_REQUESTED:
    pauseContent();
    break;
case CONTENT_RESUME_REQUESTED:
    resumeContent();
    break;

Habilitar la reproducción de anuncios personalizados

El último paso es indicarle al SDK que estás usando la reproducción de anuncios personalizados. Para ello, se debe pasar un VideoAdPlayer a tu AdDisplayContainer:

adDisplayContainer.setPlayer(videoAdPlayer);

Es necesario pasar tu jugador a setPlayer(). De lo contrario, el SDK usa la reproducción que pertenece al SDK.

Eso es todo. Esos son todos los pasos necesarios para agregar la reproducción de anuncios personalizados a tu implementación de IMA. Puedes comparar tu propia implementación con el ejemplo avanzado en GitHub si tienes problemas.