Implementar adaptadores de vídeos bonificados

Esta guía está dirigida a aquellos usuarios que necesiten usar la plataforma Mediación de AdMob para mostrar anuncios de vídeo bonificados de una red publicitaria de terceros.

Redes publicitarias y eventos personalizados compatibles con AdMob

Las redes publicitarias directamente compatibles con la plataforma Mediación de AdMob implementan adaptadores de mediación estándar. Las que no son directamente compatibles con AdMob se pueden utilizar de todas formas para solicitar y mostrar vídeos bonificados, siempre que se implementen adaptadores de eventos personalizados. A continuación, se detallan las diferencias entre los adaptadores de mediación estándar y los de eventos personalizados.

Definir los parámetros del servidor

Las redes publicitarias mediadas a través de la plataforma de mediación de AdMob necesitan uno o más identificadores para reconocer a un editor. Estos identificadores se representan como parámetros del servidor y, para definirlos, es necesario configurar una red publicitaria de terceros para la mediación en la interfaz de AdMob.

Si vas a crear un adaptador de eventos personalizados, lleva a cabo el paso siguiente para crear un evento personalizado. Si vas a crear un adaptador, tu red publicitaria y los parámetros correspondientes del servidor se configurarán como parte del proceso de incorporación de la red publicitaria a AdMob.

Crear un evento personalizado

Para definir un evento personalizado, primero debes crearlo en la interfaz de AdMob. Encontrarás instrucciones al respecto en Añadir un evento personalizado. Una vez definido, el evento personalizado señalará una clase dentro de la aplicación que implemente MediationRewardedVideoAdAdapter para servir un vídeo bonificado. El evento personalizado también mostrará un parámetro de servidor que se transferirá al adaptador de vídeo bonificado.

En esta captura de pantalla se muestran algunos ejemplos de ajustes de eventos personalizados:

En la captura de pantalla se muestran las siguientes entradas:

Nombre de clase
El nombre completo de la clase que implementa el evento personalizado.
Etiqueta
Un nombre único para el evento.
Parámetro
Un argumento opcional transferido al evento personalizado.

Implementar un adaptador de mediación

En esta sección se describen los pasos necesarios para implementar un adaptador. Para que puedas ver una demostración práctica del código del adaptador, crearemos un adaptador para un SDK de red publicitaria de ejemplo.

Inicializar el adaptador

En la solicitud de anuncio de vídeo bonificado inicial de la aplicación, el SDK de anuncios de Google para móviles invoca el método initialize() de tu adaptador.

El adaptador debe implementar este método para inicializar la red publicitaria de terceros. Este método proporciona un lote de serverParameters, que pueden ser necesarios para completar la inicialización. El método de acceso a estos parámetros puede variar ligeramente, dependiendo de si desarrollas un adaptador de mediación o un adaptador de eventos personalizados.

Para un adaptador de mediación, las claves de los parámetros del servidor están preconfiguradas y puedes extraer los parámetros del servidor de uno en uno. En cuanto a los eventos personalizados, hay un solo parámetro al que se puede acceder mediante la clave MediationRewardedVideoAdAdapter.CUSTOM_EVENT_SERVER_PARAMETER_FIELD:

Adaptador de mediación

String parameter1 = serverParameters.getString("SERVER_PARAMETER_KEY1");
String parameter2 = serverParameters.getString("SERVER_PARAMETER_KEY2");

Eventos personalizados

String parameter = serverParameters.getString(MediationRewardedVideoAdAdapter.CUSTOM_EVENT_SERVER_PARAMETER_FIELD);

El adaptador debería conservar una referencia a la instancia MediationRewardedVideoAdListener para poder remitir eventos de anuncio al SDK de anuncios de Google para móviles. Si la inicialización se lleva a cabo correctamente, el adaptador debe realizar una llamada a MediationRewardedVideoAdListener.onInitializationSucceeded().

Si la inicialización falla, el adaptador debe invocar MediationRewardedVideoAdListener.onInitializationFailed(). Si la inicialización no se realiza correctamente, el SDK de anuncios de Google para móviles vuelve a intentar inicializar el adaptador cada vez que se solicita un anuncio de vídeo bonificado. Aquí tienes un ejemplo de implementación del método initialize():

@Override
public void initialize(Context context,
    MediationAdRequest mediationAdRequest,
    String unused,
    MediationRewardedVideoAdListener listener,
    Bundle serverParameters,
    Bundle mediationExtras) {

    // In this method you should initialize your SDK.

    // The sample SDK requires activity context to initialize, so check
    // that the context provided by the app is an activity context before
    // initializing.
    if (!(context instanceof Activity)) {
        // Context not an Activity context, log the reason for failure and
        // fail the initialization.
        Log.d(TAG, "Sample SDK requires an Activity context to initialize");
        listener.onInitializationFailed(
            SampleAdapter.this, AdRequest.ERROR_CODE_INVALID_REQUEST);
        return;
    }

    // Get the Ad Unit ID for the Sample SDK from serverParameters bundle.
    String adUnit = serverParameters.getString(
        MediationRewardedVideoAdAdapter.CUSTOM_EVENT_SERVER_PARAMETER_FIELD);

    if (TextUtils.isEmpty(adUnit)) {
        listener.onAdFailedToLoad(this, AdRequest.ERROR_CODE_INVALID_REQUEST);
        return;
    }

    // Create a rewarded video event forwarder to forward the events from
    // the Sample SDK to the Google Mobile Ads SDK.
    mRewardedVideoEventForwarder =
        new SampleMediationRewardedVideoEventForwarder(listener, SampleAdapter.this);

    // Initialize the Sample SDK.
    SampleRewardedVideo.initialize((Activity) context, adUnit, mRewardedVideoEventForwarder);
}
public class SampleMediationRewardedVideoEventForwarder extends SampleRewardedVideoAdListener {
    ...
    @Override
    public void onRewardedVideoInitialized() {
        super.onRewardedVideoInitialized();
        mIsInitialized = true;
        mMediationRewardedVideoAdListener.onInitializationSucceeded(mSampleAdapter);
    }

    @Override
    public void onRewardedVideoInitializationFailed(SampleErrorCode error) {
        super.onRewardedVideoInitializationFailed(error);
        mIsInitialized = false;
        mMediationRewardedVideoAdListener.onInitializationFailed(
            mSampleAdapter, getAdMobErrorCode(error));
    }
}

Devolver el estado de la inicialización

El método isInitialized() de tu adaptador debe devolver el valor "false" hasta que se produzca la primera llamada del adaptador a MediationRewardedVideoAdListener.onInitializationSucceeded(). A partir de ese momento, el método siempre debe devolver el valor "true", tal como se indica a continuación:

@Override
public boolean isInitialized() {
    return mRewardedVideoEventForwarder != null && mRewardedVideoEventForwarder.isInitialized();
}

Cargar un vídeo bonificado

Después de que el adaptador invoque el método MediationRewardedVideoAdListener.onInitializationSucceeded(), el SDK de anuncios de Google para móviles puede invocar el método loadAd() de tu adaptador. Este método debe solicitar un vídeo bonificado y realizar una llamada a MediationRewardedVideoAdListener.onAdLoaded() cuando tenga un vídeo bonificado que mostrar. Si no hay vídeos disponibles, el adaptador debe realizar una llamada a MediationRewardedVideoAdListener.onAdFailedToLoad().

En el caso de los vídeos bonificados, muchas redes publicitarias utilizan una API independiente de las solicitudes de anuncios. Cuando se inicialice la red publicitaria, podrás comprobar si hay un inventario para el usuario actual y verificar si hay algún anuncio disponible. Si se cumplen estos criterios, podrás mostrar el anuncio al usuario. Aquí tienes una implementación de ejemplo de loadAd() para una red publicitaria de este tipo.

@Override
public void loadAd(MediationAdRequest mediationAdRequest,
    Bundle serverParameters,
    Bundle mediationExtras) {
    if (SampleRewardedVideo.isAdAvailable()) {
        // Ad already available, use the forwarder to send a success callback
        // to AdMob.
        mRewardedVideoEventForwarder.onAdLoaded();
    } else {
        // No ad available, use the forwarder to send a failure callback.
        mRewardedVideoEventForwarder.onAdFailedToLoad();
    }
}

En la primera solicitud de anuncio, se puede llamar a loadAd() en el adaptador inmediatamente después de invocar el método MediationRewardedVideoAdListener.onInitializationSucceeded(). Si una red publicitaria sigue cargando anuncios en ese momento, comunicar inmediatamente un problema al cargar el anuncio puede causar numerosos errores de relleno en la solicitud del anuncio de vídeo bonificado inicial. En este caso, es recomendable que los adaptadores hagan un seguimiento de cuándo se cargan los anuncios y retrasen la respuesta al SDK de anuncios de Google para móviles hasta que se produzca un resultado (ya sea que los anuncios se cargan correctamente o que no pueden hacerlo). El SDK de anuncios de Google para móviles dispone de un tiempo de espera para los casos en los que el adaptador no responde lo suficientemente rápido.

Mostrar el vídeo bonificado

El SDK de anuncios de Google para móviles puede llamar al método showVideo() de tu adaptador en cualquier momento, una vez que el adaptador le haya notificado que el anuncio se ha cargado correctamente. El método showVideo() solo recibe una llamada por retrollamada correcta de loadAd(). Al invocar este método, el adaptador debe reproducir el vídeo bonificado.

@Override
public void showVideo() {
    // Show the rewarded video ad.
    if (SampleRewardedVideo.isAdAvailable()) {
        // Rewarded video ad available, show ad.
        SampleRewardedVideo.showAd();
    } else {
        // Show ad will only be called if the adapter sends back an ad
        // loaded callback in response to a loadAd request. If for any
        // reason the adapter is not ready to show an ad after sending
        // an ad loaded callback, log a warning.
        Log.w(TAG, "No ads to show.");
    }
}

Definir una bonificación

Cuando el adaptador esté listo para bonificar al usuario, debe crear un objeto adaptado a la interfaz de RewardItem. Este es un ejemplo de implementación de RewardItem:

/**
* A {@link RewardItem} that maps the sample reward type and reward amount.
*/
public class SampleRewardItem implements RewardItem {
    private String mRewardType;
    private int mRewardAmount;

    /**
    * Creates a {@link SampleRewardItem}.
    *
    * @param rewardType   the sample reward type.
    * @param rewardAmount the sample reward amount.
    */
    public SampleRewardItem(String rewardType, int rewardAmount) {
        this.mRewardType = rewardType;
        this.mRewardAmount = rewardAmount;
    }

    @Override
    public String getType() {
        return mRewardType;
    }

    @Override
    public int getAmount() {
        return mRewardAmount;
    }
}

Para notificar al SDK de anuncios de Google para móviles que se debe bonificar a un usuario, el adaptador debe invocar el método MediationRewardedVideoAdListener.onRewarded() con una instancia de RewardItem como argumento.

Reenviar eventos de anuncio al SDK de anuncios de Google para móviles

El adaptador debe enviar una notificación al SDK de anuncios de Google para móviles cuando se produzca cualquiera de los siguientes eventos de anuncio:

Método MediationRewardedVideoAdListener Momento de la llamada
onAdOpened() Una superposición en pantalla completa cubre el contenido de la aplicación.
onVideoStarted() Empieza el anuncio de vídeo.
onAdClicked() Se hace clic en el anuncio de vídeo.
onAdLeftApplication() El usuario abandona la aplicación debido al anuncio de vídeo (por ejemplo, para ir al navegador).
onRewarded() El anuncio de vídeo recompensa al usuario.
onAdClosed() El anuncio de vídeo se cierra.

Aquí tienes un ejemplo de implementación de reenvío de anuncios al SDK de anuncios de Google para móviles:

/**
* A SampleRewardedVideoAdListener that forwards events to AdMob mediation's
* link.
*/
public class SampleMediationRewardedVideoEventForwarder extends SampleRewardedVideoAdListener {
    private MediationRewardedVideoAdListener mMediationRewardedVideoAdListener;
    private SampleAdapter mSampleAdapter;
    private boolean mIsInitialized;

    /**
    * Creates a new SampleMediationRewardedVideoEventForwarder.
    *
    * @param listener      An AdMob Mediation MediationRewardedVideoAdListener that should
    *                      receive forwarded events.
    * @param sampleAdapter A SampleAdapter mediation adapter.
    */
    public SampleMediationRewardedVideoEventForwarder(MediationRewardedVideoAdListener listener,
    SampleAdapter sampleAdapter) {
        this.mMediationRewardedVideoAdListener = listener;
        this.mSampleAdapter = sampleAdapter;
    }

    /**
    * @return whether or not the Sample SDK is initialized.
    */
    public boolean isInitialized() {
        return mIsInitialized;
    }

    @Override
    public void onRewardedVideoInitialized() {
        super.onRewardedVideoInitialized();
        mIsInitialized = true;
        mMediationRewardedVideoAdListener.onInitializationSucceeded(mSampleAdapter);
    }

    @Override
    public void onRewardedVideoInitializationFailed(SampleErrorCode error) {
        super.onRewardedVideoInitializationFailed(error);
        mIsInitialized = false;
        mMediationRewardedVideoAdListener.onInitializationFailed(
        mSampleAdapter, getAdMobErrorCode(error));
    }

    @Override
    public void onAdRewarded(final String rewardType, final int amount) {
        super.onAdRewarded(rewardType, amount);

        /*
        * AdMob requires a reward item with a reward type and amount to be
        * sent when sending the rewarded callback. If your SDK does not
        * have a reward amount you need to do the following:
        *
        * 1. AdMob provides an ability to override the reward value in the
        * front end. Document this asking the publisher to override the
        * reward value on AdMob's front end.
        *
        * 2. Send a reward item with default values for the type (an empty
        * string "") and reward amount (1).
        */
        mMediationRewardedVideoAdListener.onRewarded(
                mSampleAdapter, new SampleRewardItem(rewardType, amount));
    }

    @Override
    public void onAdClicked() {
        super.onAdClicked();
        mMediationRewardedVideoAdListener.onAdClicked(mSampleAdapter);
    }

    @Override
    public void onAdFullScreen() {
        super.onAdFullScreen();
        mMediationRewardedVideoAdListener.onAdOpened(mSampleAdapter);
        // Only send video started here if your SDK starts video
        // immediately after the ad has been opened/is fullscreen.
        mMediationRewardedVideoAdListener.onVideoStarted(mSampleAdapter);
    }

    @Override
    public void onAdClosed() {
        super.onAdClosed();
        mMediationRewardedVideoAdListener.onAdClosed(mSampleAdapter);
    }

    /**
    * Forwards the ad loaded event to AdMob SDK. The Sample SDK does not
    * have an ad loaded callback, the adapter calls this method if an ad
    * is available when loadAd is called.
    */
    protected void onAdLoaded() {
        mMediationRewardedVideoAdListener.onAdLoaded(mSampleAdapter);
    }

    /**
    * Forwards the ad failed event to AdMob SDK. The Sample SDK does not
    * have an ad failed to load callback, the adapter calls this method
    * to forward the failure callback.
    */
    protected void onAdFailedToLoad() {
        mMediationRewardedVideoAdListener.onAdFailedToLoad(
        mSampleAdapter, AdRequest.ERROR_CODE_NO_FILL);
    }

    /**
    * Converts SampleErrorCode into an AdMob SDK's AdRequest error code.
    *
    * @param errorCode a Sample SDK error code.
    * @return an AdMob SDK readable error code.
    */
    private int getAdMobErrorCode(SampleErrorCode errorCode) {
        switch (errorCode) {
            case BAD_REQUEST:
            return AdRequest.ERROR_CODE_INVALID_REQUEST;
        case NETWORK_ERROR:
            return AdRequest.ERROR_CODE_NETWORK_ERROR;
        case NO_INVENTORY:
            return AdRequest.ERROR_CODE_NO_FILL;
        case UNKNOWN:
        default:
            return AdRequest.ERROR_CODE_INTERNAL_ERROR;
        }
    }
}

Es probable que las redes publicitarias de terceros utilicen procesadores de eventos de anuncio. Se pueden asignar eventos de anuncio de SDKs de terceros a los eventos de anuncio correspondientes al MediationRewardedVideoAdListener proporcionado en el método initialize() del adaptador para, así, invocarlos en el momento oportuno.

Notificación de cambios de contexto

De forma opcional, tu adaptador puede implementar el objeto OnContextChangedListener para recibir notificaciones de cambios en el contexto actual. El método onContextChanged() se invoca cuando se produce una actualización en el contexto del objeto RewardedVideoAd. Se puede acceder al contexto actualizado de la actividad de esta manera:

@Override
public void onContextChanged(Context context) {
    if (context instanceof Activity) {
        SampleRewardedVideo.setCurrentActivity((Activity) context);
    }
}

Otros parámetros de segmentación

MediationAdRequest contiene otros tipos de datos de segmentación habituales que puedes usar para la segmentación publicitaria, por ejemplo:

Aceptar parámetros personalizados en el adaptador

Puede que la red publicitaria en la que tu adaptador realiza la mediación admita otros parámetros de segmentación o entradas que no estén cubiertas por las opciones que ofrece MediationAdRequest. Si es el caso de tu adaptador, puedes pedir a los editores que proporcionen un paquete de información a tu red. El paquete se transfiere a tu adaptador a través de los métodos initialize() y loadAd().

Este es un ejemplo de cómo podría proporcionar el editor un paquete para el adaptador SampleAdapter:

Bundle bundle = new Bundle();
bundle.putBoolean("ShouldAddAwesomeSauce", true);
AdRequest adRequest = new AdRequest.Builder()
        .addNetworkExtrasBundle(SampleAdapter.class, bundle)
        .build();

Para que a los desarrolladores les resulte más fácil crear este paquete, pueden añadir una clase al adaptador para que los editores puedan crearlo cómodamente:

public static final class MediationExtrasBundleBuilder {

    // Keys to add and obtain the extra parameters from the bundle.
    private static final String KEY_AWESOME_SAUCE = "awesome_sauce";

    /**
    * An extra value used to populate the "ShouldAddAwesomeSauce" property
    * of the Sample SDK's ad request.
    */
    private boolean mShouldAddAwesomeSauce;

    public MediationExtrasBundleBuilder setShouldAddAwesomeSauce(
            boolean shouldAddAwesomeSauce) {
        this.mShouldAddAwesomeSauce = shouldAddAwesomeSauce;
        return MediationExtrasBundleBuilder.this;
    }

    public MediationExtrasBundleBuilder setIncome(int income) {
        this.mIncome = income;
        return MediationExtrasBundleBuilder.this;
    }

    public Bundle build() {
        Bundle extras = new Bundle();
        extras.putInt(KEY_INCOME, mIncome);
        return extras;
    }
}

Esta clase ofrece una API más limpia para que el desarrollador genere un paquete para tu red:

Bundle sampleAdNetworkBundle =
        new SampleAdapter.MediationExtrasBundleBuilder().setShouldAddAwesomeSauce(true).build();