Android Integeration with Ad Manager Mediation

出自TAMedia
於 2023年8月8日 (二) 13:02 由 BrandonTeng留言 | 貢獻 所做的修訂 →‎原生(Native)
跳至導覽 跳至搜尋

詳細範例

Google ADS 22.2.0 Mediation Project (包含橫幅、插頁、原生廣告)。New-xxl.png

新增廣告單元 / 收益群組

登入Google Ad Manager

https://admanager.google.com/home/
Gam android 00.png

橫幅(Banner)

  • 進入 Ad Manager 網頁選擇 應用單元 -> 新增廣告單元

  • Gam banner 00.png

  • 名稱: GAM_Mediation_Android_Banner_320x50

  • 大小: 320x50

  • Gam banner 01.png

  • 新增收益群組

  • Gam banner 02.png

  • 名稱: GAM_Mediation_Android_Banner_320x50

  • 狀態: 有效

  • 廣告格式: 橫幅

  • Gam banner 05.png

  • 新增收益夥伴

  • Gam banner 04.png

  • 其他收益夥伴詳細資訊

  • Gam banner 07.png

  • Label: 用於AdManagerAdView.adUnitId

  • Class Name: com.taiwanmobile.pt.gam.mediation.TAmediaGAMCustomEvent

  • Parameter: TAmedia廣告版位




插頁(Interstitial)

  • 進入 Ad Manager 網頁選擇 應用單元 -> 新增廣告單元

  • Gam banner 00.png

  • 名稱: GAM_Mediation_Android_Interstitial

  • 大小: 1024x768, 768x1024, 480x320, 320x480

  • Gam interstitial 01.png

  • 新增收益群組

  • Gam banner 04.png

  • 名稱: GAM_Mediation_Android_Interstitial

  • 狀態: 有效

  • 廣告格式: 插頁式

  • Gam interstitial 02.png

  • 新增收益夥伴

  • Gam banner 04.png

  • 其他收益夥伴詳細資訊

  • Gam interstitial 03.png

  • Label: 用於AdManagerInterstitialAd.load()

  • Class Name: com.taiwanmobile.pt.gam.mediation.TAmediaGAMCustomEvent

  • Parameter: TAmedia廣告版位




原生(Native)

  • 進入 Ad Manager 網頁選擇 應用單元 -> 新增廣告單元

  • Gam banner 00.png

  • 名稱: GAM_Mediation_Android_Native

  • 大小: 自訂顯示

  • Gam native 01.png

  • 新增收益群組

  • Gam banner 04.png

  • 名稱: GAM_Mediation_Android_Native

  • 狀態: 有效

  • 廣告格式: 原生格式

  • Gam native 02.png

  • 新增收益夥伴

  • Gam banner 04.png

  • 其他收益夥伴詳細資訊

  • Gam native 03.png

  • Label: 用於AdLoader.Builder().forNativeAd()

  • Class Name: com.taiwanmobile.pt.gam.mediation.TAmediaGAMCustomEvent

  • Parameter: TAmedia原生廣告參數(下方說明)

  • MediaView顯示影音

    • adUnitId: TAmedia廣告版位

    • mediaType: VIDEO

    • videoStartUnmuted: 影片聲音預設開關, true: 有聲音, false: 無聲音

    • videoCustomControlRequest: 影片上是否要顯示秒數, 靜音, 前往瀏覽等UI按鈕, true: 不顯示, false: 顯示

{
  "parameters": {
    "adUnitId": "ADUNIT_ID",
    "mediaType": "VIDEO",
    "videoStartUnmuted":true,
    "videoCustomControlRequest":true
  }
}
  • MediaView顯示大圖(1200x628)

    • adUnitId: TAmedia廣告版位

    • mediaType: BIG_IMAGE

{
  "parameters": {
    "adUnitId": "ADUNIT_ID",
    "mediaType": "BIG_IMAGE"
  }
}
  • MediaView顯示小圖(960x640)

    • adUnitId: TAmedia廣告版位

    • mediaType: SMALL_IMAGE

{
  "parameters": {
    "adUnitId": "ADUNIT_ID",
    "mediaType": "SMALL_IMAGE"
  }
}



Gradle設定

// =======================================================================//
// Google Play Service - ADS
// =======================================================================//
implementation 'com.google.android.gms:play-services-ads:22.2.0'

// =======================================================================//
// MADP SDK
// =======================================================================//
implementation fileTree(include: ['*.aar'], dir: 'libs')

// =======================================================================//
// MADP SDK dependencies
// =======================================================================//
// kotlin
implementation 'org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.21'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4'
// retrofit
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
implementation 'com.squareup.retrofit2:converter-scalars:2.9.0'
// advertising ID
implementation 'com.google.android.gms:play-services-ads-identifier:18.0.1'
// appset
implementation 'com.google.android.gms:play-services-appset:16.0.2'
// gson
implementation 'com.google.code.gson:gson:2.10.1'
// lifecycle
def lifecycle_version = "2.6.1"
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version"
implementation "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycle_version"
implementation "androidx.lifecycle:lifecycle-runtime-ktx:$lifecycle_version"
implementation "androidx.lifecycle:lifecycle-viewmodel-savedstate:$lifecycle_version"
implementation "androidx.lifecycle:lifecycle-common-java8:$lifecycle_version"
implementation "androidx.lifecycle:lifecycle-common-java8:$lifecycle_version"
implementation "androidx.lifecycle:lifecycle-service:$lifecycle_version"
implementation "androidx.lifecycle:lifecycle-process:$lifecycle_version"
implementation "androidx.lifecycle:lifecycle-reactivestreams-ktx:$lifecycle_version"
// viewModels
implementation 'androidx.activity:activity-ktx:1.7.2'
// EncryptedSharedPreferences
implementation 'androidx.security:security-crypto:1.1.0-alpha06'



Proguard設定

-keep class com.taiwanmobile.pt.adp.mediation.** {
    public protected <fields>;
    public protected <methods>;
}
-keep class com.taiwanmobile.pt.gam.mediation.** {
    public protected <fields>;
    public protected <methods>;
}
-dontwarn com.google.errorprone.annotations.**



開發者程式

橫幅(Banner)

請參考GAMBannerActivity.kt, 使用AdManagerAdView載入AdManagerAdRequest, 進行廣告請求

    adUnitId?.let {
        val request = AdManagerAdRequest.Builder().build()
        adManagerAdView = AdManagerAdView(this@GAMBannerActivity)
        adManagerAdView?.adUnitId = it
        adManagerAdView?.setAdSizes(adSize)
        adManagerAdView?.adListener = object: AdListener() {
            override fun onAdLoaded() {}
            override fun onAdFailedToLoad(adError : LoadAdError) {}
            override fun onAdClicked() {}
            override fun onAdImpression() {}
        }
        adManagerAdView?.loadAd(request)
        // add view into layout
        binding.adContainer.addView(adManagerAdView)
    }

插頁(Interstitial)

請參考GAMInterstitialActivity.kt, 使用AdManagerInterstitialAd載入AdManagerAdRequest物件, 進行廣告請求

    adUnitId?.let {
        val adRequest = AdManagerAdRequest.Builder().build()
        AdManagerInterstitialAd.load(this, it, adRequest, object : AdManagerInterstitialAdLoadCallback() {
            override fun onAdFailedToLoad(adError: LoadAdError) {}
            override fun onAdLoaded(ad: AdManagerInterstitialAd) {
                interstitialAd = ad
                interstitialAd?.show(this@GAMInterstitialActivity)
            }
        })
    }

原生(Native)

請參考GAMNativeActivity.kt, 使用AdManagerInterstitialAd載入AdManagerAdRequest物件, 進行廣告請求

    val adUnitId = args.getString(GAMMainActivity.KEY_ADUNITID) ?: ""
    val adLoader = AdLoader.Builder(this, adUnitId)
        .forNativeAd { ad: NativeAd ->
        if (isDestroyed) {
            ad.destroy()
            return@forNativeAd
        }
        nativeAd = ad
        val vb = NativeAdBinding.inflate(layoutInflater)
            populateNativeAdView(ad, vb)
            binding.nativeContainer.removeAllViews()
            binding.nativeContainer.addView(vb.root)
        }
        .withAdListener(object : AdListener() {
            override fun onAdFailedToLoad(adError: LoadAdError) {}
            override fun onAdClicked() {}
            override fun onAdImpression() {}
        })
        .withNativeAdOptions(NativeAdOptions.Builder().build())
        .build()
    adLoader.loadAd(AdManagerAdRequest.Builder().build())

請參考GAMNativeActivity.kt, 在populateNativeAdView()有填充NativeAd物件實作細節

    private fun populateNativeAdView(nativeAd: NativeAd, viewBinding: NativeAdBinding) {

        // fetch NativeAdView from NativeAdBinding
        val nativeAdView: NativeAdView = viewBinding.root

        // headline
        if (nativeAd.headline == null) {
            viewBinding.adHeadline.visibility = View.INVISIBLE
        } else {
            viewBinding.adHeadline.visibility = View.VISIBLE
            viewBinding.adHeadline.text = nativeAd.headline
            nativeAdView.headlineView = viewBinding.adHeadline
        }
        // body
        if (nativeAd.body == null) {
            viewBinding.adBody.visibility = View.INVISIBLE
        } else {
            viewBinding.adBody.visibility = View.VISIBLE
            viewBinding.adBody.text = nativeAd.body
            nativeAdView.bodyView = viewBinding.adBody
        }
        // call to action
        if (nativeAd.callToAction == null) {
            viewBinding.adCallToAction.visibility = View.INVISIBLE
        } else {
            viewBinding.adCallToAction.visibility = View.VISIBLE
            viewBinding.adCallToAction.text = nativeAd.callToAction
            nativeAdView.callToActionView = viewBinding.adCallToAction
        }
        // icon
        if (nativeAd.icon == null) {
            viewBinding.adAppIcon.visibility = View.GONE
        } else {
            nativeAd.icon?.drawable?.let {
                viewBinding.adAppIcon.setImageDrawable(it)
                viewBinding.adAppIcon.visibility = View.VISIBLE
                nativeAdView.iconView = viewBinding.adAppIcon
            }
        }
        // mediaView
        nativeAdView.mediaView = viewBinding.adMedia
        nativeAdView.mediaView?.mediaContent = nativeAd.mediaContent
        nativeAdView.setNativeAd(nativeAd)
    }

請參考NativeAdBinding佈局細節, 使用NativeAdView設計原生廣告佈局, 使用MediaView顯示 影片大圖小圖 /p>

<com.google.android.gms.ads.nativead.NativeAdView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical">

    <ImageView
        android:id="@+id/ad_app_icon"
        android:layout_width="40dp"
        android:layout_height="40dp"
        android:adjustViewBounds="true"
        android:paddingEnd="5dp"
        android:paddingRight="5dp"
        android:paddingBottom="5dp" />

    <TextView
        android:id="@+id/ad_headline"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textColor="#0000FF"
        android:textSize="16sp"
        android:textStyle="bold" />

    <TextView
        android:id="@+id/ad_body"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginEnd="20dp"
        android:layout_marginRight="20dp"
        android:textSize="12sp" />

    <com.google.android.gms.ads.nativead.MediaView
        android:id="@+id/ad_media"
        android:layout_width="250dp"
        android:layout_height="175dp"
        android:layout_gravity="center_horizontal"
        android:layout_marginTop="5dp" />

    <Button
        android:id="@+id/ad_call_to_action"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:textSize="12sp" />

</com.google.android.gms.ads.nativead.NativeAdView>



TAmedia中介程式

橫幅(Banner)

請參考TAmediaGAMCustomEvent.loadBannerAd(), 此為橫幅中介程式進入點

    override fun loadBannerAd(
        configuration: MediationBannerAdConfiguration,
        callback: MediationAdLoadCallback<MediationBannerAd, MediationBannerAdCallback>
    ) {
        bannerLoader = TAmediaGAMBannerLoader(configuration, callback)
        bannerLoader?.loadAd()
    }

插頁(Interstitial)

請參考TAmediaGAMCustomEvent.loadInterstitialAd(), 此為插頁中介程式進入點

    override fun loadInterstitialAd(
        configuration: MediationInterstitialAdConfiguration,
        callback: MediationAdLoadCallback<MediationInterstitialAd, MediationInterstitialAdCallback>
    ) {
        interstitialLoader = TAmediaGAMInterstitialLoader(configuration, callback)
        interstitialLoader?.loadAd()
    }

原生(Native)

請參考TAmediaGAMCustomEvent.loadNativeAd(), 此為原生中介程式進入點

   override fun loadNativeAd(
        configuration: MediationNativeAdConfiguration,
        callback: MediationAdLoadCallback<UnifiedNativeAdMapper, MediationNativeAdCallback>
    ) {
        nativeLoader = TAmediaGAMNativeLoader(configuration, callback)
        nativeLoader?.loadAd()
    }



實際範例

橫幅(Banner)

插頁(Interstitial)

原生(Native)

回首頁