보상형 동영상 어댑터 구현하기

이 가이드는 AdMob 미디에이션 플랫폼을 사용하여 제3자 광고 네트워크의 보상형 동영상 광고를 게재하려는 게시자를 대상으로 작성되었습니다.

AdMob에서 지원하는 광고 네트워크 및 맞춤 이벤트

AdMob 미디에이션 플랫폼에서 직접 지원하는 광고 네트워크는 표준 미디에이션 어댑터를 구현합니다. 맞춤 이벤트 어댑터를 구현하면 AdMob에서 직접 지원하지 않는 광고 네트워크의 보상형 동영상도 요청 및 게재할 수 있습니다. 표준 미디에이션 어댑터와 맞춤 이벤트 어댑터의 차이점은 아래에서 확인할 수 있습니다.

서버 매개변수 정의

AdMob 미디에이션 플랫폼을 통해 미디에이션되는 광고 네트워크에서 게시자를 식별하려면 하나 이상의 식별자가 필요합니다. 이러한 식별자는 서버 매개변수로 표시되며, AdMob UI에서 미디에이션을 위해 제3자 광고 네트워크를 구성할 때 정의됩니다.

맞춤 이벤트 어댑터를 생성하려면 아래에 나온 맞춤 이벤트 생성 과정을 따르세요. 어댑터를 생성하는 경우 광고 네트워크 및 해당 서버 매개변수가 AdMob의 광고 네트워크 온보딩 과정의 일부로 구성됩니다.

맞춤 이벤트 생성

맞춤 이벤트를 정의하려면 먼저 AdMob UI에서 맞춤 이벤트를 만들어야 합니다. 맞춤 이벤트 추가에서 맞춤 이벤트 만들기 방법을 확인하세요. 정의 단계가 완료된 맞춤 이벤트는 앱에서 보상형 동영상을 제공하기 위해 MediationRewardedVideoAdAdapter를 구현하는 클래스를 가리킵니다. 또한 맞춤 이벤트는 보상형 동영상 어댑터로 전달되는 서버 매개변수를 나열합니다.

다음은 샘플 맞춤 이벤트 설정을 보여주는 스크린샷입니다.

스크린샷에 포함된 항목은 다음과 같습니다.

클래스 이름
맞춤 이벤트를 구현하는 클래스의 정규화된 이름입니다.
라벨
이벤트의 고유한 이름입니다.
매개변수
맞춤 이벤트에 전달되는 선택적 인수입니다.

미디에이션 어댑터 구현

이 섹션에서는 어댑터를 구현하는 과정을 설명합니다. 실제로 사용되는 어댑터 코드를 보여주기 위해 샘플 광고 네트워크 SDK를 만들었으며, 이 SDK의 어댑터를 만들려고 합니다.

어댑터 초기화

앱에서 보상형 동영상 광고를 처음 요청할 때 Google 모바일 광고 SDK가 어댑터의 initialize() 메서드를 호출합니다.

어댑터는 이 메서드를 구현하여 제3자 광고 네트워크를 초기화해야 합니다. 이 메서드는 초기화를 완료하는 데 필요할 수 있는 serverParameters 번들을 제공합니다. 미디에이션 매개변수와 맞춤 이벤트 어댑터 중 무엇을 개발하는지에 따라 이러한 매개변수에 액세스할 수 있는 방법이 약간 달라집니다.

미디에이션 어댑터의 경우 서버 매개변수의 키가 사전 구성되며, 서버 매개변수를 개별적으로 추출할 수 있습니다. 맞춤 이벤트의 경우 MediationRewardedVideoAdAdapter.CUSTOM_EVENT_SERVER_PARAMETER_FIELD 키를 통해 액세스할 수 있는 매개변수가 하나 있습니다.

미디에이션 어댑터

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

맞춤 이벤트

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

어댑터는 MediationRewardedVideoAdListener 인스턴스에 대한 참조를 유지해야 광고 이벤트를 Google 모바일 광고 SDK에 전달할 수 있습니다. 초기화에 성공하면 어댑터가 MediationRewardedVideoAdListener.onInitializationSucceeded()를 호출해야 합니다.

어댑터 초기화에 실패하면 어댑터가 MediationRewardedVideoAdListener.onInitializationFailed()를 호출해야 합니다. 초기화에 실패하면 보상형 동영상 광고 요청이 있을 때마다 Google 모바일 광고 SDK가 어댑터 초기화를 다시 시도합니다. 다음은 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));
        }
    }
    

초기화 상태 반환

어댑터의 isInitialized() 메서드는 어댑터에서 MediationRewardedVideoAdListener.onInitializationSucceeded()를 처음 호출하는 시점까지 false를 반환해야 합니다. 이때부터는 이 메서드가 항상 아래와 같이 true를 반환해야 합니다.

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

보상형 동영상 로드

어댑터가 MediationRewardedVideoAdListener.onInitializationSucceeded() 메서드를 호출하면 Google 모바일 광고 SDK가 어댑터의 loadAd() 메서드를 호출할 수 있습니다. 이 메서드는 보상형 동영상을 요청한 후 표시할 보상형 동영상이 확보되면 MediationRewardedVideoAdListener.onAdLoaded()를 호출해야 합니다. 표시 가능한 동영상이 없으면 어댑터가 MediationRewardedVideoAdListener.onAdFailedToLoad()를 호출해야 합니다.

보상형 동영상의 경우 광고 요청이라는 개념이 없는 API를 채택한 광고 네트워크가 많습니다. 광고 네트워크가 초기화되면 현재 사용자를 위한 인벤토리가 있고 광고가 준비되었는지를 확인할 수 있습니다. 이 조건이 충족되면 사용자에게 광고를 게재할 수 있습니다. 다음은 이러한 광고 네트워크에 대한 loadAd() 구현의 예입니다.

@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();
        }
    }
    

첫 번째 광고 요청 시에는 MediationRewardedVideoAdListener.onInitializationSucceeded() 메서드를 호출한 직후에 어댑터에서 loadAd()를 호출할 수 있습니다. 이 시점에 광고 네트워크에서 아직 광고를 로드하고 있는 경우 광고 로드 실패를 즉시 보고하면 보상형 동영상 광고에 대한 최초 요청이 대부분 처리되지 못할 수 있습니다. 이러한 경우에는 광고 로드에 성공하거나 실패할 때까지 어댑터에서 광고 로드 시점을 추적하고 Google 모바일 광고 SDK에 보내는 응답을 미루는 것이 좋습니다. Google 모바일 광고 SDK에서는 어댑터의 응답이 늦어지는 경우를 대비해 제한시간을 적용합니다.

보상형 동영상 표시

어댑터가 Google 모바일 광고 SDK에 광고 로드 성공을 알린 후 언제든지 Google 모바일 광고 SDK가 어댑터의 showVideo() 메서드를 호출할 수 있습니다. showVideo() 메서드는 loadAd() 콜백이 성공할 때마다 한 번씩만 호출됩니다. 이 메서드가 호출될 때 어댑터가 보상형 동영상을 재생해야 합니다.

@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.");
        }
    }
    

보상 정의

어댑터에서 사용자에게 보상을 제공할 준비가 되었으면 RewardItem 인터페이스를 준수하는 객체를 만들어야 합니다. 다음은 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;
        }
    }
    

사용자에게 보상을 제공해야 함을 Google 모바일 광고 SDK에 알리려면 어댑터가 RewardItem 인스턴스를 인수로 사용하여 MediationRewardedVideoAdListener.onRewarded() 메서드를 호출해야 합니다.

Google 모바일 광고 SDK에 광고 이벤트 전달

어댑터는 다음과 같은 광고 이벤트가 발생할 때 Google 모바일 광고 SDK에 알려야 합니다.

MediationRewardedVideoAdListener 메서드 호출 시점
onAdOpened() 전체 화면 오버레이가 앱 콘텐츠를 덮을 때
onVideoStarted() 동영상 광고가 시작할 때
onAdClicked() 동영상 광고를 클릭할 때
onAdLeftApplication() 사용자가 동영상 광고 때문에 애플리케이션에서 나갈 때(예: 브라우저로 이동)
onRewarded() 동영상 광고에서 사용자에게 보상할 때
onAdClosed() 동영상 광고가 닫힐 때

다음은 Google 모바일 광고 SDK에 광고를 전달하는 구현의 예입니다.

/**
    * 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;
            }
        }
    }
    

제3자 광고 네트워크에는 광고 네트워크에 대한 광고 이벤트 리스너가 있을 수 있습니다. 제3자 SDK의 광고 이벤트는 어댑터의 initialize() 메서드에서 제공되고 적절한 시간에 호출되는 MediationRewardedVideoAdListener에 해당하는 광고 이벤트에 매핑될 수 있습니다.

컨텍스트 변경 알림

어댑터는 선택적으로 OnContextChangedListener를 구현하여 현재 컨텍스트의 변경에 대한 알림을 받을 수 있습니다. RewardedVideoAd 객체의 현재 컨텍스트가 업데이트되면 onContextChanged() 메서드가 호출됩니다. 업데이트된 활동 컨텍스트에 다음과 같이 액세스할 수 있습니다.

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

추가 타겟팅 매개변수

MediationAdRequest에는 광고 타겟팅에서 일반적으로 사용할 수 있는 다음과 같은 타겟팅 정보가 포함되어 있습니다.

어댑터에 맞춤 매개변수 허용

어댑터의 미디에이션 대상인 광고 네트워크는 MediationAdRequest에서 제공되는 정보에 포함되지 않는 추가 타겟팅 매개변수 또는 입력을 지원할 수 있습니다. 이 경우 네트워크에 일련의 정보를 제공하도록 게시자에게 요청할 수 있습니다. 이 정보 번들은 initialize()loadAd() 메서드에서 어댑터에 전달됩니다.

다음은 게시자가 SampleAdapter 어댑터에 정보 번들을 제공하는 방법의 예입니다.

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

어댑터에 편의 클래스를 추가하여 게시자가 어댑터 번들을 쉽게 구성할 수 있게 하면 개발자가 이 번들을 더욱 쉽게 생성할 수 있습니다.

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;
        }
    }
    

이러한 편의 클래스는 개발자가 사용자 네트워크의 번들을 생성할 수 있도록 간편한 API를 제공합니다.

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