네이티브 맞춤 이벤트

본 가이드는 AdMob 미디에이션을 사용하여 AdMob에서 지원하는 광고 네트워크가 아닌 네트워크에서 네이티브 광고를 로드 및 게재하려는 게시자를 대상으로 작성되었습니다. AdMob 미디에이션을 사용하여 배너 또는 전면 광고를 로드하고 게재하는 데 대한 정보는 맞춤 이벤트를 참고하세요. 맞춤 이벤트는 다른 네트워크의 광고를 요청할 수 있는 미디에이션 어댑터 클래스입니다. 광고 단위의 미디에이션 설정에 이러한 클래스 중 하나의 이름을 추가하면 Google 모바일 광고 SDK에서 클래스를 인스턴스화하여 광고를 검색하는 데 사용할 수 있습니다. 네이티브 맞춤 이벤트 클래스는 다음과 같은 기능을 제공해야 합니다.

  • 미디에이션 대상 네트워크의 네이티브 광고 요청
  • 미디에이션 대상 네트워크의 SDK에서 Google 모바일 광고 SDK로 이벤트 전달
  • UnifiedNativeAdMapper를 사용하여 미디에이션 대상인 네이티브 광고를 AdMob의 네이티브 광고 인터페이스에 매핑

위의 작업에 대한 설명이 아래에 나와 있습니다. 샘플 맞춤 이벤트 프로젝트의 전체 소스는 GitHub 저장소에서도 확인할 수 있습니다.

기본 요건

AdMob 맞춤 이벤트를 구현하려면 먼저 모바일 광고 SDK를 프로젝트에 통합해야 합니다. 먼저 AdRequest 작성미디에이션의 작동 방식에 대해 알아보세요.

샘플 SDK

본 가이드의 코드 스니펫은 '샘플 SDK'가 포함된 샘플 맞춤 이벤트 프로젝트에서 가져온 것입니다. 다른 광고 네트워크의 SDK를 미디에이션하는 맞춤 이벤트를 만드는 방법을 보여주는 예에서 이 모의 SDK가 사용됩니다.

샘플 SDK에는 광고 네트워크의 프로덕션 SDK에 있는 것과 유사한 클래스가 포함됩니다. 이 클래스는 SampleNativeAdRequest와 같은 요청 객체, SampleNativeAdLoader와 같은 광고 로더 및 기타 실제 네트워크의 SDK를 시뮬레이션하기 위해 사용되는 클래스, 상수 및 인터페이스입니다. 하지만 샘플 SDK에서 제작되는 광고는 모의 광고이며 추가 네트워크 트래픽이 생성되지 않습니다.

네이티브 광고 요청

requestNativeAd() 메서드

맞춤 이벤트 클래스는 CustomEventNative 프로토콜을 구현해야 합니다. 이 프로토콜은 Google 모바일 광고 SDK가 맞춤 이벤트에서 네이티브 광고를 요청하는 데 사용하는 메서드를 포함합니다.

자바

    void requestNativeAd(Context context,
            CustomEventNativeListener listener,
            String serverParameter,
            NativeMediationAdRequest mediationAdRequest,
            Bundle customEventExtras);
    

Kotlin

    override fun requestNativeAd(context: Context,
            listener: CustomEventNativeListener,
            serverParameter: String,
            mediationAdRequest: NativeMediationAdRequest,
            customEventExtras: Bundle?)
    

이 메서드가 호출되면 맞춤 이벤트는 미디에이션 대상 네트워크에서 비동기식으로 네이티브 광고를 요청해야 합니다. requestNativeAd()의 다음 매개변수는 맞춤 이벤트에서 요청을 작성할 때 사용할 수 있는 정보를 전달합니다.

  • serverParameter: 광고 단위의 미디에이션 구성에 맞춤 이벤트를 추가할 때 각 요청과 함께 전달할 문자열 값을 입력할 수 있습니다. 이 매개변수에 이 값(일반적으로는 미디에이션 대상 네트워크에서 제공하는 다른 광고 단위 ID)이 포함됩니다.
  • mediationAdRequest: 각 요청의 속성(예: 요청한 네이티브 형식)이 포함된 NativeMediationAdRequest 객체입니다. NativeMediationAdRequestMediationAdRequest의 하위 클래스이므로 요청 시 게시자가 제공한 다른 타겟팅 정보의 속성도 포함됩니다.
  • customEventExtras: 게시자가 제공한 요청과 관련된 추가 정보가 포함된 Bundle입니다. 광고 요청을 만들 때 게시자가 addNetworkExtrasBundle() 메서드를 사용하여 특정 네이티브 미디에이션 어댑터와 맞춤 이벤트에 대한 정보를 포함할 수 있습니다. 특정 맞춤 이벤트 클래스에 대해 게시자가 포함한 추가 정보가 이 매개변수에 포함됩니다.

요청 정보를 전달하는 매개변수 외에 2가지 매개변수가 더 있습니다.

  • context: 맞춤 이벤트에 필요한 경우 사용할 수 있는 Context 객체
  • listener: 맞춤 이벤트에서 이벤트를 전달하기 위해 사용해야 하는 CustomEventNativeListener 객체

리스너 객체는 이벤트를 Google 모바일 광고 SDK에 보고하는 데 사용되므로 특히 중요합니다. 본 가이드의 모바일 광고 SDK에 이벤트 전달에 이러한 보고 방법이 나와 있습니다.

다음은 맞춤 이벤트 프로젝트 예에서 구현한 requestNativeAd() 메서드를 보여주는 코드 스니펫입니다.

SampleCustomEvent(발췌)

자바

    @Override
    public void requestNativeAd(Context context,
                                CustomEventNativeListener customEventNativeListener,
                                String serverParameter,
                                NativeMediationAdRequest nativeMediationAdRequest,
                                Bundle extras) {
        // Create one of the Sample SDK's ad loaders from which to request ads.
        SampleNativeAdLoader loader = new SampleNativeAdLoader(context);
        loader.setAdUnit(serverParameter);

        // Create a native request to give to the SampleNativeAdLoader.
        SampleNativeAdRequest request = new SampleNativeAdRequest();
        NativeAdOptions options = nativeMediationAdRequest.getNativeAdOptions();
        if (options != null) {
            // If the NativeAdOptions' shouldReturnUrlsForImageAssets is true, the adapter should
            // send just the URLs for the images.
            request.setShouldDownloadImages(!options.shouldReturnUrlsForImageAssets());

            // If your network does not support any of the following options, please make sure
            // that it is documented in your adapter's documentation.
            request.setShouldDownloadMultipleImages(options.shouldRequestMultipleImages());
            switch (options.getImageOrientation()) {
                case NativeAdOptions.ORIENTATION_LANDSCAPE:
                    request.setPreferredImageOrientation(
                            SampleNativeAdRequest.IMAGE_ORIENTATION_LANDSCAPE);
                    break;
                case NativeAdOptions.ORIENTATION_PORTRAIT:
                    request.setPreferredImageOrientation(
                            SampleNativeAdRequest.IMAGE_ORIENTATION_PORTRAIT);
                    break;
                case NativeAdOptions.ORIENTATION_ANY:
                default:
                    request.setPreferredImageOrientation(
                            SampleNativeAdRequest.IMAGE_ORIENTATION_ANY);
            }
        }

        if (!nativeMediationAdRequest.isUnifiedNativeAdRequested()) {
            Log.e(TAG, "Failed to load ad. Request must be for unified native ads.");
            customEventNativeListener.onAdFailedToLoad(AdRequest.ERROR_CODE_INVALID_REQUEST);
            return;
        }

        loader.setNativeAdListener(
                new SampleCustomNativeEventForwarder(customEventNativeListener, options));

        // Begin a request.
        loader.fetchAd(request);
    }
    

Kotlin

    override fun requestNativeAd(context: Context,
                                 customEventNativeListener: CustomEventNativeListener,
                                 serverParameter: String,
                                 nativeMediationAdRequest: NativeMediationAdRequest,
                                 extras: Bundle) {
        // Create one of the Sample SDK's ad loaders from which to request ads.
        val loader = SampleNativeAdLoader(context)
        loader.setAdUnit(serverParameter)

        // Create a native request to give to the SampleNativeAdLoader.
        val request = SampleNativeAdRequest()
        val options = nativeMediationAdRequest.nativeAdOptions
        if (options != null) {
            // If the NativeAdOptions' shouldReturnUrlsForImageAssets is true, the adapter should
            // send just the URLs for the images.
            request.shouldDownloadImages = !options.shouldReturnUrlsForImageAssets()

            // If your network does not support any of the following options, please make sure
            // that it is documented in your adapter's documentation.
            request.setShouldDownloadMultipleImages(options.shouldRequestMultipleImages())
            when (options.imageOrientation) {
                NativeAdOptions.ORIENTATION_LANDSCAPE -> request.setPreferredImageOrientation(
                        SampleNativeAdRequest.IMAGE_ORIENTATION_LANDSCAPE)
                NativeAdOptions.ORIENTATION_PORTRAIT -> request.setPreferredImageOrientation(
                        SampleNativeAdRequest.IMAGE_ORIENTATION_PORTRAIT)
                NativeAdOptions.ORIENTATION_ANY -> request.setPreferredImageOrientation(
                        SampleNativeAdRequest.IMAGE_ORIENTATION_ANY)
                else -> request.setPreferredImageOrientation(SampleNativeAdRequest.IMAGE_ORIENTATION_ANY)
            }
        }

        if (!nativeMediationAdRequest.isUnifiedNativeAdRequested) {
            Log.e(TAG, "Failed to load ad. Request must be for unified native ads.")
            customEventNativeListener.onAdFailedToLoad(AdRequest.ERROR_CODE_INVALID_REQUEST)
            return
        }

        loader.setNativeAdListener(
                SampleCustomNativeEventForwarder(customEventNativeListener, options))

        // Begin a request.
        loader.fetchAd(request)
    }

모의 샘플 SDK를 통해 가상의 광고 네트워크로 미디에이션되는 샘플 맞춤 이벤트입니다. 맞춤 이벤트에서는 requestNativeAd()의 매개변수에 제공된 정보를 사용하여 SampleNativeAdRequest(샘플 SDK에서 제공한 클래스)를 만든 다음 이 클래스를 사용하여 샘플 SDK의 SampleNativeAdLoader에 광고를 요청합니다. 또한 이벤트를 Google 모바일 광고 SDK에 다시 전달하기 위해 SampleCustomEventNativeForwarder를 생성합니다.

NativeAdOptions

네이티브 광고를 요청할 때 게시자는 NativeAdOptions 객체를 사용하여 해당 요청의 환경설정(예: 이미지 애셋 반환 방법)을 지정합니다. 맞춤 이벤트는 지정된 환경설정을 검토하고 준수해야 합니다. 맞춤 이벤트는 NativeMediationAdRequest 객체에서 제공하는 getNativeAdOptions() 메서드를 사용하여 요청의 NativeAdOptions 객체를 검색할 수 있습니다.

자바

    NativeAdOptions options = mediationAdRequest.getNativeAdOptions();
    

Kotlin

    val options = mediationAdRequest.nativeAdOptions
    

맞춤 이벤트는 NativeAdOptions를 검색한 후 이 객체의 속성을 읽고 적절히 처리할 수 있습니다. 예를 들어 NativeAdOptionsshouldReturnUrlsForImageAssets 값이 기본값인 false로 설정된 경우 맞춤 이벤트는 URL뿐 아니라 실제 이미지 애셋을 반환해야 합니다. 이러한 경우 미디에이션 대상 SDK가 이미지의 URL만 제공하면 맞춤 이벤트는 해당 URL을 사용하여 이미지 파일을 다운로드하고 매핑된 네이티브 광고에서 해당 데이터를 게시자에게 제공해야 합니다.

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

맞춤 이벤트에서 미디에이션 대상 네트워크의 네이티브 광고를 로드하려고 할 때 다음과 같은 결과가 나올 수 있습니다. SDK가 네이티브 광고를 성공적으로 반환할 수도 있고, 오류가 발생할 수도 있으며, 게재 가능한 광고가 없다고 보고할 수도 있습니다. 마찬가지로 사용자가 광고를 탭하면 미디에이션 대상 SDK가 오버레이를 열 수도 있고 애플리케이션에서 벗어나 외부 브라우저를 시작할 수도 있습니다. Google 모바일 광고 SDK는 이러한 이벤트를 인식할 수 있어야 하므로 requestNativeAd() 메서드에 CustomEventNativeListener 객체를 매개변수로 제공합니다.

미디에이션 대상 SDK에서 이벤트를 수신하여 적절한 CustomEventNativeListener 콜백에 매핑하는 것은 맞춤 이벤트의 기능의 일부입니다. 맞춤 이벤트에서는 다음과 같은 CustomEventNativeListener 콜백을 인식해야 합니다.

  • onAdLoaded(): 맞춤 이벤트가 네이티브 광고 로드에 성공할 때 이 메서드를 호출해야 합니다. 이때 광고 네트워크 SDK의 네이티브 광고를 Google 모바일 광고 SDK가 인식하는 객체로 매핑하는 UnifiedNativeAdMapper가 사용됩니다. 네이티브 광고 매핑에서는 UnifiedNativeAdMapper를 만드는 방법을 설명합니다.
  • onAdFailedToLoad(): 맞춤 이벤트에서 네이티브 광고를 로드하려는 시도가 실패하면 이 메서드를 사용하여 실패를 보고해야 합니다. 정수 매개변수 1개가 필요하며, 이를 오류 상수 중 하나로 설정해야 합니다.

  • onAdLeftApplication(): 미디에이션 대상 SDK로 인해 사용자 커서가 게시자의 애플리케이션을 벗어나게 되는 경우(외부 브라우저를 여는 경우가 가장 많음), 이 메서드를 호출합니다.

  • onAdOpened(): 사용자가 탭하면 네이티브 광고가 인터페이스를 가리는 오버레이 또는 별도의 활동을 여는 경우 이 메서드를 호출합니다. 여기에는 외부 브라우저가 포함됩니다. 이러한 경우 맞춤 이벤트가 onAdLeftApplication 직전에 onAdOpened를 호출해야 합니다.

  • onAdClosed(): 인터페이스를 가리는 오버레이 또는 별도의 활동이 닫히면 이 메서드를 호출하여 해당 컨트롤이 네이티브 광고를 포함하는 앱으로 다시 전송되고 있음을 나타냅니다.

리스너는 자체적으로 클릭 또는 노출을 추적하는 맞춤 이벤트에서 클릭 및 노출을 보고할 수 있는 메서드도 제공합니다. 자세한 내용은 기본 클릭 처리 및 노출 기록 재정의를 참고하세요. Google 모바일 광고 SDK에 클릭을 보고하는 메서드도 있고, 노출을 보고하는 메서드도 있습니다.

  • onAdClicked(): 사용자가 네이티브 광고를 클릭할 때 이 메서드를 호출합니다.
  • onAdImpression(): 마찬가지로 미디에이션 대상 SDK의 광고 노출을 기록할 때 이 메서드를 호출해야 합니다.

이벤트를 올바르게 전달하는 방법에는 여러 가지가 있지만 가장 간단한 방법 중 하나는 전달자 역할을 하는 전용 클래스를 만드는 것입니다. 다음은 맞춤 이벤트 샘플 프로젝트의 예입니다.

SampleCustomNativeEventForwarder

자바

    public class SampleCustomNativeEventForwarder extends SampleNativeAdListener {
        private CustomEventNativeListener nativeListener;
        private NativeAdOptions nativeAdOptions;

        public SampleCustomNativeEventForwarder(
                CustomEventNativeListener listener, NativeAdOptions options) {
            this.nativeListener = listener;
            this.nativeAdOptions = options;
        }

        @Override
        public void onNativeAdFetched(SampleNativeAd ad) {
            SampleUnifiedNativeAdMapper mapper =
                    new SampleUnifiedNativeAdMapper(ad, nativeAdOptions);
            nativeListener.onAdLoaded(mapper);
        }

        @Override
        public void onAdFetchFailed(SampleErrorCode errorCode) {
            switch (errorCode) {
                case UNKNOWN:
                    nativeListener.onAdFailedToLoad(AdRequest.ERROR_CODE_INTERNAL_ERROR);
                    break;
                case BAD_REQUEST:
                    nativeListener.onAdFailedToLoad(AdRequest.ERROR_CODE_INVALID_REQUEST);
                    break;
                case NETWORK_ERROR:
                    nativeListener.onAdFailedToLoad(AdRequest.ERROR_CODE_NETWORK_ERROR);
                    break;
                case NO_INVENTORY:
                    nativeListener.onAdFailedToLoad(AdRequest.ERROR_CODE_NO_FILL);
                    break;
            }
        }
    }
    

Kotlin

    class SampleCustomNativeEventForwarder(
            private val nativeListener: CustomEventNativeListener,
            private val nativeAdOptions: NativeAdOptions) : SampleNativeAdListener() {

        fun onNativeAdFetched(ad: SampleNativeAd) {
            val mapper = SampleUnifiedNativeAdMapper(ad, nativeAdOptions)
            nativeListener.onAdLoaded(mapper)
        }

        fun onAdFetchFailed(errorCode: SampleErrorCode) {
            when (errorCode) {
                UNKNOWN -> nativeListener.onAdFailedToLoad(AdRequest.ERROR_CODE_INTERNAL_ERROR)
                BAD_REQUEST -> nativeListener.onAdFailedToLoad(AdRequest.ERROR_CODE_INVALID_REQUEST)
                NETWORK_ERROR -> nativeListener.onAdFailedToLoad(AdRequest.ERROR_CODE_NETWORK_ERROR)
                NO_INVENTORY -> nativeListener.onAdFailedToLoad(AdRequest.ERROR_CODE_NO_FILL)
            }
        }
    }
    

클래스에서 샘플 SDK의 SampleNativeAdListener 인터페이스를 구현하고 있습니다. SampleCustomEvent(발췌)에서 이 전달자 클래스의 인스턴스가 SampleNativeAdLoader( setNativeAdListener() 메서드)에 전달되었습니다.

자바

    loader.setNativeAdListener(new SampleCustomNativeEventForwarder(customEventNativeListener, options));
    

Kotlin

    loader.setNativeAdListener(SampleCustomNativeEventForwarder(customEventNativeListener, options))
    

이렇게 하면 보고할 이벤트가 발생할 때 SampleCustomNativeEventForwarder 객체의 리스너 메서드(onNativeAdFetched(), onAdFetchFailed())를 샘플 SDK가 호출합니다. 그런 다음 전달자가 Google 모바일 광고 SDK의 CustomEventNativeListener에서 적절한 메서드를 호출하여 이벤트를 전달합니다. 즉, Google 모바일 광고 SDK는 전달자를 수신하며, 전달자는 미디에이션 대상 SDK를 수신합니다.

위의 onAdFetchFailed() 메서드에 작동 방식의 예가 자세히 나와 있습니다. 샘플 SDK는 광고 로드에 실패하면 전달자의 onAdFetchFailed() 메서드를 호출하고 오류 코드를 제공합니다. 전달자가 오류 코드를 검토하고 Google 모바일 광고 SDK에서 사용하는 오류 코드 중 하나를 사용하여 CustomEventNativeListeneronAdFailedToLoad() 메서드를 호출합니다. 이 방법으로 샘플 SDK 이벤트를 Google 모바일 광고 SDK 이벤트로 변환합니다. 이와 같이 샘플 SDK 이벤트가 Google 모바일 광고 SDK 이벤트로 변환됩니다.

네이티브 광고 매핑

SDK마다 고유한 네이티브 광고 형식이 있습니다. 예를 들어 '제목' 필드가 포함된 객체를 반환하는 SDK와 '제목' 필드가 있는 SDK가 있을 수 있습니다. 또한 노출을 추적하고 클릭을 처리하는 데 사용되는 메서드가 SDK마다 다를 수 있습니다. 이러한 차이를 조정하고 미디에이션 대상 SDK의 네이티브 광고 객체를 Google 모바일 광고 SDK에서 기대하는 인터페이스와 일치하도록 조정하는 것이 UnifiedNativeAdMapper의 기능입니다. 맞춤 이벤트에서 이 클래스를 확장하여 미디에이션 대상 SDK에 해당하는 자체 매퍼를 만들어야 합니다.

다음은 맞춤 이벤트 프로젝트 예에 포함된 광고 매퍼의 예입니다.

SampleUnifiedNativeAdMapper

자바

    public class SampleUnifiedNativeAdMapper extends UnifiedNativeAdMapper {

        private final SampleNativeAd sampleAd;

        public SampleUnifiedNativeAdMapper(SampleNativeAd ad) {
            sampleAd = ad;
            setHeadline(sampleAd.getHeadline());
            setBody(sampleAd.getBody());
            setCallToAction(sampleAd.getCallToAction());
            setStarRating(sampleAd.getStarRating());
            setStore(sampleAd.getStoreName());
            setIcon(new SampleNativeMappedImage(ad.getIcon(), ad.getIconUri(),
                    SampleCustomEvent.SAMPLE_SDK_IMAGE_SCALE));
            setAdvertiser(ad.getAdvertiser());

            List<NativeAd.Image> imagesList = new ArrayList<NativeAd.Image>();
            imagesList.add(new SampleNativeMappedImage(ad.getImage(), ad.getImageUri(),
                    SampleCustomEvent.SAMPLE_SDK_IMAGE_SCALE));
            setImages(imagesList);

            if (sampleAd.getPrice() != null) {
                NumberFormat formatter = NumberFormat.getCurrencyInstance();
                String priceString = formatter.format(sampleAd.getPrice());
                setPrice(priceString);
            }

            Bundle extras = new Bundle();
            extras.putString(SampleCustomEvent.DEGREE_OF_AWESOMENESS, ad.getDegreeOfAwesomeness());
            this.setExtras(extras);

            setOverrideClickHandling(false);
            setOverrideImpressionRecording(false);

            setAdChoicesContent(sampleAd.getInformationIcon());
        }

        @Override
        public void recordImpression() {
            sampleAd.recordImpression();
        }

        @Override
        public void handleClick(View view) {
            sampleAd.handleClick(view);
        }
    }
    

Kotlin

    class SampleUnifiedNativeAdMapper(private val sampleAd: SampleNativeAd) : UnifiedNativeAdMapper() {

        init {
            headline = sampleAd.headline
            body = sampleAd.body
            callToAction = sampleAd.callToAction
            starRating = sampleAd.starRating
            store = sampleAd.storeName
            icon = SampleNativeMappedImage(sampleAd.icon, sampleAd.iconUri,
                    SampleCustomEvent.SAMPLE_SDK_IMAGE_SCALE)
            advertiser = sampleAd.advertiser

            val imagesList = ArrayList<NativeAd.Image>()
            imagesList.add(SampleNativeMappedImage(sampleAd.image, sampleAd.imageUri,
                    SampleCustomEvent.SAMPLE_SDK_IMAGE_SCALE))
            images = imagesList

            if (sampleAd.price != null) {
                val formatter = NumberFormat.getCurrencyInstance()
                val priceString = formatter.format(sampleAd.price)
                price = priceString
            }

            val extras = Bundle()
            extras.putString(SampleCustomEvent.DEGREE_OF_AWESOMENESS, sampleAd.degreeOfAwesomeness)
            this.extras = extras

            overrideClickHandling = false
            overrideImpressionRecording = false

            adChoicesContent = sampleAd.informationIcon
        }

        override fun recordImpression() {
            sampleAd.recordImpression()
        }

        override fun handleClick(view: View?) {
            sampleAd.handleClick(view)
        }
    }

생성자 메서드와 그 기능에 대해 살펴보겠습니다.

미디에이션 대상인 네이티브 광고 객체에 대한 참조 보유

생성자는 SampleNativeAdNativeAdOptions 매개변수를 허용합니다. SampleNativeAd는 네이티브 광고를 위해 샘플 SDK에서 사용하는 네이티브 광고 클래스입니다. 매퍼는 미디에이션 대상 광고에 대한 참조가 있어야 클릭 및 노출 이벤트를 전달할 수 있습니다. NativeAdOptions는 네이티브 광고에 대한 게시자 환경설정을 포함합니다. 두 매개변수는 로컬 변수로 저장됩니다.

매핑된 애셋 속성 설정

생성자가 SampleNativeAd 객체를 사용하여 UnifiedNativeAdMapper에 애셋을 입력합니다. 예를 들어 다음 코드가 미디에이션 대상 광고의 가격 데이터를 가져와서 매퍼의 가격을 설정하는 데 사용합니다.

자바

    if (sampleAd.getPrice() != null) {
        NumberFormat formatter = NumberFormat.getCurrencyInstance();
        String priceString = formatter.format(sampleAd.getPrice());
        setPrice(priceString);
    }
    

Kotlin

    if (sampleAd.price != null) {
        val formatter = NumberFormat.getCurrencyInstance()
        val priceString = formatter.format(sampleAd.price)
        price = priceString
    }
    

이 경우 미디에이션 대상 광고는 가격을 double로 저장하지만, AdMob에서는 같은 애셋에 String을 사용합니다. 이러한 변환을 매퍼에서 처리해야 합니다.

이미지 애셋 매핑

이미지 애셋 매핑은 double, String 등의 단순한 데이터 유형보다 훨씬 더 복잡합니다. 이미지는 자동으로 다운로드되거나 URL 값으로 반환될 수 있습니다. 픽셀의 dpi 배율 또한 달라질 수 있습니다. Google 모바일 광고 SDK는 맞춤 이벤트 개발자가 이러한 세부정보를 쉽게 관리할 수 있도록 NativeAd.Image 클래스를 제공합니다. 개발자가 미디에이션 대상 네이티브 광고를 매핑하기 위해 UnifiedNativeAdMapper의 하위 클래스를 만들어야 하는 것과 거의 마찬가지로 NativeAd.Image의 하위 클래스를 생성하여 이미지 애셋을 쉽게 매핑할 수 있게 해야 합니다.

다음은 맞춤 이벤트의 SampleNativeMappedImage 클래스에 대한 코드입니다.

자바

    public class SampleNativeMappedImage extends NativeAd.Image {

        private Drawable drawable;
        private Uri imageUri;
        private double scale;

        public SampleNativeMappedImage(Drawable drawable, Uri imageUri, double scale) {
            this.drawable = drawable;
            this.imageUri = imageUri;
            this.scale = scale;
        }

        @Override
        public Drawable getDrawable() {
            return drawable;
        }

        @Override
        public Uri getUri() {
            return imageUri;
        }

        @Override
        public double getScale() {
            return scale;
        }
    }
    

Kotlin

    class SampleNativeMappedImage(private val drawable: Drawable,
                                  private val imageUri: Uri,
                                  private val scale: Double) : NativeAd.Image() {

        override fun getDrawable(): Drawable {
            return drawable
        }

        override fun getUri(): Uri {
            return imageUri
        }

        override fun getScale(): Double {
            return scale
        }
    }
    

SampleUnifiedNativeAdMapper는 이 줄에서 매핑된 이미지 클래스를 사용하여 매퍼의 아이콘 애셋을 설정합니다.

자바

    setIcon(new SampleNativeMappedImage(ad.getAppIcon(), ad.getAppIconUri(),
            SampleCustomEvent.SAMPLE_SDK_IMAGE_SCALE));
    

Kotlin

    icon = SampleNativeMappedImage(sampleAd.appIcon, sampleAd.appIconUri,
            SampleCustomEvent.SAMPLE_SDK_IMAGE_SCALE)
    

추가 번들에 필드 추가

미디에이션 대상 SDK 중 일부에서 AdMob 네이티브 광고 형식에 포함되지 않는 애셋을 추가로 제공하기도 합니다. UnifiedNativeAdMapper 클래스에는 이러한 에셋을 게시자에게 전달하는 데 사용되는 setExtras() 메서드가 포함됩니다. SampleUnifiedNativeAdMapper의 경우 샘플 SDK의 'degree of awesomeness' 애셋에서 이 메서드를 사용합니다.

자바

    Bundle extras = new Bundle();
    extras.putString(SampleCustomEvent.DEGREE_OF_AWESOMENESS, ad.getDegreeOfAwesomeness());
    this.setExtras(extras);
    

Kotlin

    val extras = Bundle()
    extras.putString(SampleCustomEvent.DEGREE_OF_AWESOMENESS, sampleAd.degreeOfAwesomeness)
    this.extras = extras
    

게시자는 UnifiedNativeAd 클래스의 getExtras() 메서드를 이용해 데이터를 가져올 수 있습니다.

AdChoices

맞춤 이벤트에서 UnifiedNativeAdMappersetAdChoicesContent() 메서드를 통해 AdChoices 아이콘을 제공합니다.

다음은 AdChoices 아이콘을 표시하는 방법을 보여주는 SampleUnifiedNativeAdMapper의 스니펫입니다.

자바

    public SampleUnifiedNativeAdMapper(SampleNativeAd ad) {
        ...
        setAdChoicesContent(sampleAd.getInformationIcon());
    }
    

Kotlin

    init {
        ...
        adChoicesContent = sampleAd.informationIcon
    }
    

노출 및 클릭 이벤트

노출 또는 클릭이 발생한 경우 Google 모바일 광고 SDK와 미디에이션 대상 SDK 모두 알아야 하지만 하나의 SDK에서만 이러한 이벤트를 추적하면 됩니다. 맞춤 이벤트는 미디에이션 대상 SDK에서 자체적으로 노출을 추적할 수 있는지 여부에 따라 두 가지 방식을 사용할 수 있습니다.

handleClick 및 recordImpression을 사용하여 클릭 및 노출 처리

미디에이션 대상 SDK에서 자체적으로 노출 및 클릭을 추적하지 않지만 클릭 및 노출을 기록하는 메서드를 제공하는 경우 Google 모바일 광고 SDK에서 이러한 이벤트를 추적하고 어댑터에 알릴 수 있습니다. UnifiedNativeAdMapper에는 맞춤 이벤트가 미디에이션 대상 네이티브 광고 객체에서 해당 메서드를 호출하기 위해 구현할 수 있는 두 가지 메서드인 recordImpression()handleClick()이 포함되어 있습니다.

다음은 SampleUnifiedNativeAdMapper에서 이 작업을 처리하는 방법입니다.

자바

    @Override
    public void recordImpression() {
        sampleAd.recordImpression();
    }

    @Override
    public void handleClick(View view) {
        sampleAd.handleClick(view);
    }
    

Kotlin

    override fun recordImpression() {
        sampleAd.recordImpression()
    }

    override fun handleClick(view: View) {
        sampleAd.handleClick(view)
    }
    

SampleUnifiedNativeAdMapper는 샘플 SDK의 네이티브 광고 객체에 대한 참조를 보유하므로 해당 객체에 대해 적절한 메서드를 간단히 호출하여 클릭 또는 노출을 보고할 수 있습니다. handleClick() 메서드에 있는 단일 매개변수는 클릭을 수신하는 네이티브 광고 애셋에 해당하는 View 객체입니다.

기본 클릭 처리 및 노출 기록 재정의

일부 미디에이션 대상 SDK는 자체적으로 클릭 및 노출을 추적하려고 할 수도 있습니다. 이 경우 UnifiedNativeAdMapper의 생성자에서 다음 두 메서드를 호출하여 기본 클릭 및 노출 추적을 재정의해야 합니다.

자바

    setOverrideClickHandling(true);
    setOverrideImpressionRecording(true);
    

Kotlin

    setOverrideClickHandling(true)
    setOverrideImpressionRecording(true)
    

모바일 광고 SDK에 이벤트 전달 에서 설명한 것처럼, 자체적으로 클릭 및 노출을 추적하는 맞춤 이벤트는 이러한 이벤트를 onAdClicked()onAdImpression() 메서드를 통해 Google 모바일 광고 SDK에 보고해야 합니다.

또한 trackViews() 메서드를 재정의하고 이 메서드를 사용하여 네이티브 광고의 보기를 추적할 미디에이션 대상 SDK에 전달해야 합니다. 이 가이드의 코드 스니펫을 발췌한 맞춤 이벤트 프로젝트 예의 샘플 SDK는 이 방식을 사용하지 않지만, 이 방식을 사용한다면 맞춤 이벤트 코드는 다음과 같았을 것입니다.

자바

    @Override
    public void trackViews(View containerView,
            Map<String, View> clickableAssetViews,
            Map<String, View> nonClickableAssetViews) {
        sampleAd.setNativeAdViewForTracking(containerView);
    }
    

Kotlin


    override fun trackViews(containerView: View?,
            clickableAssetViews: Map<String, View>?,
            nonClickableAssetViews: Map<String, View>?) {
        sampleAd.setNativeAdViewForTracking(containerView)
    }
    

미디에이션 대상 SDK에서 개별 애셋 추적을 지원하는 경우에는 어떤 보기를 클릭이 가능하도록 설정해야 하는지를 clickableAssetViews에서 확인할 수 있습니다. 이 맵의 경우 UnifiedNativeAdAssetNames의 애셋 이름이 키로 지정됩니다.

UnifiedNativeAdMapper에서는 맞춤 이벤트가 (보기에 대한 참조를 취소하고 이 참조와 네이티브 광고 객체의 연결을 해제하는) 반대 목적을 위해 재정의할 수 있는 untrackView() 메서드를 제공합니다.

맞춤 이벤트 사용하기

맞춤 이벤트를 사용하려면 이를 광고 단위의 미디에이션 구성에 추가해야 합니다. 이 작업은 AdMob UI에서 처리할 수 있습니다. 맞춤 이벤트 만들기에 광고 단위의 미디에이션 구성을 수정하는 방법이 자세히 나와 있습니다.

광고 단위의 미디에이션 구성에 맞춤 이벤트를 추가할 때 다음 3가지 정보를 입력해야 합니다.

  • Class Name: 맞춤 이벤트의 클래스 이름으로서 전체 패키지 이름을 포함합니다.
  • Label: AdMob 인터페이스에서 광고 단위의 미디에이션 소스를 표시하기 위해 맞춤 이벤트를 나타낼 때 사용하는 라벨입니다. 게시자를 위한 기능이며 AdMob UI에만 표시됩니다.
  • Parameter: 이 광고 단위로 요청이 이루어질 때마다 맞춤 이벤트에 전달되는 문자열 값입니다. 일반적으로 이 값은 미디에이션 대상 네트워크의 광고 단위 ID로 설정됩니다.

다음은 맞춤 이벤트 항목 예의 스크린샷입니다.

이상으로 AdMob의 자체 Android 맞춤 이벤트를 작성하는 방법에 대해 알아보았습니다.