「Android Integeration with Ad Manager Mediation」修訂間的差異
BrandonTeng(留言 | 貢獻) 小 (BrandonTeng移動頁面支援Google Ad Manager至Android Integeration with Ad Manager Mediation) |
BrandonTeng(留言 | 貢獻) |
||
(未顯示同一使用者於中間所作的 67 次修訂) | |||
行 1: | 行 1: | ||
== 詳細範例 == | |||
<p style="font-size: 18px;">[[媒體:TAmedia_Ad_Manager_Medation_20230810.zip | Ad Manager 22.2.0 Mediation Project]] (包含橫幅、插頁、原生廣告)。[[檔案:new-xxl.png|30px]]</p> | |||
<br> | |||
== 新增廣告單元 / 收益群組 == | == 新增廣告單元 / 收益群組 == | ||
=== 登入Google Ad Manager === | === 登入Google Ad Manager === | ||
https://admanager.google.com/home/ | https://admanager.google.com/home/ | ||
<br> | <br> | ||
[[ image:gam_android_00.png | | [[ image:gam_android_00.png | center | 800px ]] | ||
<br> | <br> | ||
行 9: | 行 13: | ||
<ul> | <ul> | ||
<li><p style="font-size: 18px;">進入 Ad Manager 網頁選擇 應用單元 -> 新增廣告單元</p></li> | <li><p style="font-size: 18px;">進入 Ad Manager 網頁選擇 應用單元 -> 新增廣告單元</p></li> | ||
[[ image:gam_banner_00.png | | [[ image:gam_banner_00.png | center | 600px ]] | ||
<li><p style="font-size: 18px;">名稱: GAM_Mediation_Android_Banner_320x50</p></li> | <li><p style="font-size: 18px;">名稱: GAM_Mediation_Android_Banner_320x50</p></li> | ||
<li><p style="font-size: 18px;">大小: 320x50 </p></li> | <li><p style="font-size: 18px;">大小: 320x50 </p></li> | ||
[[ image:gam_banner_01.png | 800px ]] | [[ image:gam_banner_01.png | center | 800px ]] | ||
<li><p style="font-size: 18px;">新增收益群組</p></li> | <li><p style="font-size: 18px;">新增收益群組</p></li> | ||
[[ image:gam_banner_02.png | 800px ]] | [[ image:gam_banner_02.png | center | 800px ]] | ||
<li><p style="font-size: 18px;">名稱: GAM_Mediation_Android_Banner_320x50 </p></li> | <li><p style="font-size: 18px;">名稱: GAM_Mediation_Android_Banner_320x50 </p></li> | ||
<li><p style="font-size: 18px;">狀態: 有效 </p></li> | <li><p style="font-size: 18px;">狀態: 有效 </p></li> | ||
<li><p style="font-size: 18px;">廣告格式: 橫幅 </p></li> | <li><p style="font-size: 18px;">廣告格式: 橫幅 </p></li> | ||
[[ image:gam_banner_05.png | | [[ image:gam_banner_05.png | center | 1000px ]] | ||
<li><p style="font-size: 18px;">新增收益夥伴</p></li> | <li><p style="font-size: 18px;">新增收益夥伴</p></li> | ||
[[ image:gam_banner_04.png | | [[ image:gam_banner_04.png | center | 1000px ]] | ||
<br> | <br> | ||
<li><p style="font-size: 18px;">其他收益夥伴詳細資訊</p></li> | <li><p style="font-size: 18px;">其他收益夥伴詳細資訊</p></li> | ||
[[ image:gam_banner_07.png | | [[ image:gam_banner_07.png | center | 600px ]] | ||
<br> | <br> | ||
<li><p style="font-size: 18px;">Label: 用於AdManagerAdView.adUnitId </p></li> | <li><p style="font-size: 18px;">Label: 用於AdManagerAdView.adUnitId </p></li> | ||
行 35: | 行 39: | ||
<ul> | <ul> | ||
<li><p style="font-size: 18px;">進入 Ad Manager 網頁選擇 應用單元 -> 新增廣告單元</p></li> | <li><p style="font-size: 18px;">進入 Ad Manager 網頁選擇 應用單元 -> 新增廣告單元</p></li> | ||
[[ image:gam_banner_00.png | | [[ image:gam_banner_00.png | center | 600px ]] | ||
<li><p style="font-size: 18px;">名稱: GAM_Mediation_Android_Interstitial</p></li> | <li><p style="font-size: 18px;">名稱: GAM_Mediation_Android_Interstitial</p></li> | ||
<li><p style="font-size: 18px;">大小: 1024x768, 768x1024, 480x320, 320x480 </p></li> | <li><p style="font-size: 18px;">大小: 1024x768, 768x1024, 480x320, 320x480 </p></li> | ||
[[ image:gam_interstitial_01.png | 1000px ]] | [[ image:gam_interstitial_01.png | center | 1000px ]] | ||
<li><p style="font-size: 18px;">新增收益群組</p></li> | <li><p style="font-size: 18px;">新增收益群組</p></li> | ||
[[ image:gam_banner_04.png | 1000px ]] | [[ image:gam_banner_04.png | center | 1000px ]] | ||
<li><p style="font-size: 18px;">名稱: GAM_Mediation_Android_Interstitial </p></li> | <li><p style="font-size: 18px;">名稱: GAM_Mediation_Android_Interstitial </p></li> | ||
<li><p style="font-size: 18px;">狀態: 有效 </p></li> | <li><p style="font-size: 18px;">狀態: 有效 </p></li> | ||
<li><p style="font-size: 18px;">廣告格式: 插頁式 </p></li> | <li><p style="font-size: 18px;">廣告格式: 插頁式 </p></li> | ||
[[ image:gam_interstitial_02.png | 1000px ]] | [[ image:gam_interstitial_02.png | center | 1000px ]] | ||
<li><p style="font-size: 18px;">新增收益夥伴</p></li> | <li><p style="font-size: 18px;">新增收益夥伴</p></li> | ||
[[ image:gam_banner_04.png | | [[ image:gam_banner_04.png | center | 1000px ]] | ||
<br> | <br> | ||
<li><p style="font-size: 18px;">其他收益夥伴詳細資訊</p></li> | <li><p style="font-size: 18px;">其他收益夥伴詳細資訊</p></li> | ||
[[ image:gam_interstitial_03.png | | [[ image:gam_interstitial_03.png | center | 600px ]] | ||
<br> | <br> | ||
<li><p style="font-size: 18px;">Label: 用於AdManagerInterstitialAd.load() </p></li> | <li><p style="font-size: 18px;">Label: 用於AdManagerInterstitialAd.load() </p></li> | ||
行 61: | 行 65: | ||
<ul> | <ul> | ||
<li><p style="font-size: 18px;">進入 Ad Manager 網頁選擇 應用單元 -> 新增廣告單元</p></li> | <li><p style="font-size: 18px;">進入 Ad Manager 網頁選擇 應用單元 -> 新增廣告單元</p></li> | ||
[[ image:gam_banner_00.png | | [[ image:gam_banner_00.png | center | 600px ]] | ||
<li><p style="font-size: 18px;">名稱: GAM_Mediation_Android_Native</p></li> | <li><p style="font-size: 18px;">名稱: GAM_Mediation_Android_Native</p></li> | ||
<li><p style="font-size: 18px;">大小: 自訂顯示 </p></li> | <li><p style="font-size: 18px;">大小: 自訂顯示 </p></li> | ||
[[ image:gam_native_01.png | | [[ image:gam_native_01.png | center | 800px ]] | ||
<li><p style="font-size: 18px;">新增收益群組</p></li> | <li><p style="font-size: 18px;">新增收益群組</p></li> | ||
[[ image:gam_banner_04.png | 1000px ]] | [[ image:gam_banner_04.png | center | 1000px ]] | ||
<li><p style="font-size: 18px;">名稱: GAM_Mediation_Android_Native </p></li> | <li><p style="font-size: 18px;">名稱: GAM_Mediation_Android_Native </p></li> | ||
<li><p style="font-size: 18px;">狀態: 有效 </p></li> | <li><p style="font-size: 18px;">狀態: 有效 </p></li> | ||
<li><p style="font-size: 18px;">廣告格式: 原生格式 </p></li> | <li><p style="font-size: 18px;">廣告格式: 原生格式 </p></li> | ||
[[ image:gam_native_02.png | 1000px ]] | [[ image:gam_native_02.png | center | 1000px ]] | ||
<li><p style="font-size: 18px;">新增收益夥伴</p></li> | <li><p style="font-size: 18px;">新增收益夥伴</p></li> | ||
[[ image:gam_banner_04.png | | [[ image:gam_banner_04.png | center | 1000px ]] | ||
<br> | <br> | ||
<li><p style="font-size: 18px;">其他收益夥伴詳細資訊</p></li> | <li><p style="font-size: 18px;">其他收益夥伴詳細資訊</p></li> | ||
[[ image:gam_native_03.png | | [[ image:gam_native_03.png | center | 600px ]] | ||
<br> | <br> | ||
<li><p style="font-size: 18px;">Label: 用於AdLoader.Builder().forNativeAd() </p></li> | <li><p style="font-size: 18px;">Label: 用於AdLoader.Builder().forNativeAd() </p></li> | ||
行 82: | 行 86: | ||
</ul> | </ul> | ||
*MediaView顯示影音 | *<p style="font-size: 18px;">MediaView顯示影音</p> | ||
**adUnitId: TAmedia廣告版位 | **<p style="font-size: 16px;">adUnitId: TAmedia廣告版位</p> | ||
**mediaType: VIDEO | **<p style="font-size: 16px;">mediaType: VIDEO</p> | ||
**videoStartUnmuted: 影片聲音預設開關, true: 有聲音, false: 無聲音 | **<p style="font-size: 16px;">videoStartUnmuted: 影片聲音預設開關, true: 有聲音, false: 無聲音</p> | ||
**videoCustomControlRequest: 影片上是否要顯示秒數, 靜音, 前往瀏覽等UI按鈕, true: 不顯示, false: 顯示 | **<p style="font-size: 16px;">videoCustomControlRequest: 影片上是否要顯示秒數, 靜音, 前往瀏覽等UI按鈕, true: 不顯示, false: 顯示</p> | ||
<pre> | <pre style="font-size: 14px"> | ||
{ | { | ||
"parameters": { | "parameters": { | ||
行 98: | 行 102: | ||
</pre> | </pre> | ||
*MediaView顯示大圖(1200x628) | *<p style="font-size: 18px;">MediaView顯示大圖(1200x628)</p> | ||
**adUnitId: TAmedia廣告版位 | **<p style="font-size: 16px;">adUnitId: TAmedia廣告版位</p> | ||
**mediaType: BIG_IMAGE | **<p style="font-size: 16px;">mediaType: BIG_IMAGE</p> | ||
<pre> | <pre style="font-size: 14px"> | ||
{ | { | ||
"parameters": { | "parameters": { | ||
行 110: | 行 114: | ||
</pre> | </pre> | ||
*MediaView顯示小圖(960x640) | *<p style="font-size: 18px;">MediaView顯示小圖(960x640)</p> | ||
**adUnitId: TAmedia廣告版位 | **<p style="font-size: 16px;">adUnitId: TAmedia廣告版位</p> | ||
**mediaType: SMALL_IMAGE | **<p style="font-size: 16px;">mediaType: SMALL_IMAGE</p> | ||
<pre> | <pre style="font-size: 14px"> | ||
{ | { | ||
"parameters": { | "parameters": { | ||
行 120: | 行 124: | ||
} | } | ||
} | } | ||
</pre> | |||
<br><br> | |||
== Gradle設定 == | |||
<pre> | |||
// =======================================================================// | |||
// 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' | |||
</pre> | |||
<br><br> | |||
== Proguard設定 == | |||
<p style="font-size: 18px;">避免TAmedia Mediation Class Name被被混淆導致Google Ad Manager無法找到中介實作, 請將下列內容加入 proguard-rules.pro </p> | |||
<pre> | |||
-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.** | |||
</pre> | |||
<br><br> | |||
== TAmedia中介程式 == | |||
*<p style="font-size: 18px;">請將com.taiwanmobile.pt.gam.mediation程式碼加入專案, 請確認Google Ad Manager收益群組設定的Class Name與下列一致</p> | |||
*<p style="font-size: 18px;">com.taiwanmobile.pt.gam.mediation.TAmediaGAMCustomEvent</p> | |||
<br> | |||
[[ image:gam_android_mediation_00.png | center | 600px ]] | |||
<br> | |||
*<p style="font-size: 18px;">請確認TAmedia SDK 在libs目錄</p> | |||
[[ image:gam_android_mediation_01.png | center | 600px ]] | |||
<br> | |||
*<p style="font-size: 18px;">請再次檢查Gradle設定有參考其TAmedia SDK aar檔案</p> | |||
[[ image:gam_android_mediation_02.png | center | 600px ]] | |||
=== 橫幅(Banner) === | |||
<p style="font-size: 18px;">請參考TAmediaGAMCustomEvent.loadBannerAd(), 此為橫幅中介程式進入點</p> | |||
<pre style="font-size: 14px"> | |||
override fun loadBannerAd( | |||
configuration: MediationBannerAdConfiguration, | |||
callback: MediationAdLoadCallback<MediationBannerAd, MediationBannerAdCallback> | |||
) { | |||
bannerLoader = TAmediaGAMBannerLoader(configuration, callback) | |||
bannerLoader?.loadAd() | |||
} | |||
</pre> | |||
=== 插頁(Interstitial) === | |||
<p style="font-size: 18px;">請參考TAmediaGAMCustomEvent.loadInterstitialAd(), 此為插頁中介程式進入點</p> | |||
<pre style="font-size: 14px"> | |||
override fun loadInterstitialAd( | |||
configuration: MediationInterstitialAdConfiguration, | |||
callback: MediationAdLoadCallback<MediationInterstitialAd, MediationInterstitialAdCallback> | |||
) { | |||
interstitialLoader = TAmediaGAMInterstitialLoader(configuration, callback) | |||
interstitialLoader?.loadAd() | |||
} | |||
</pre> | </pre> | ||
=== 原生(Native) === | |||
<p style="font-size: 18px;">請參考TAmediaGAMCustomEvent.loadNativeAd(), 此為原生中介程式進入點</p> | |||
<pre style="font-size: 14px"> | |||
override fun loadNativeAd( | |||
configuration: MediationNativeAdConfiguration, | |||
callback: MediationAdLoadCallback<UnifiedNativeAdMapper, MediationNativeAdCallback> | |||
) { | |||
nativeLoader = TAmediaGAMNativeLoader(configuration, callback) | |||
nativeLoader?.loadAd() | |||
} | |||
</pre> | |||
<br><br> | |||
== 開發者程式 == | == 開發者程式 == | ||
<p style="font-size: 18px;">請參考 com.taiwanmobile.pt.guide.gam 相關程式碼</p> | |||
[[ image:gam_android_mediation_03.png | center | 600px ]] | |||
<br> | |||
=== 橫幅(Banner) === | === 橫幅(Banner) === | ||
<p style="font-size: 18px;">請參考GAMBannerActivity.kt, 使用AdManagerAdView載入AdManagerAdRequest, 進行廣告請求</p> | |||
<pre style="font-size: 14px"> | |||
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) | |||
} | |||
</pre> | |||
=== 插頁(Interstitial) === | === 插頁(Interstitial) === | ||
<p style="font-size: 18px;">請參考GAMInterstitialActivity.kt, 使用AdManagerInterstitialAd載入AdManagerAdRequest物件, 進行廣告請求</p> | |||
<pre style="font-size: 14px"> | |||
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) | |||
} | |||
}) | |||
} | |||
</pre> | |||
=== 原生(Native) === | === 原生(Native) === | ||
<p style="font-size: 18px;">請參考GAMNativeActivity.kt, 使用AdLoader.forNativeAd()載入AdManagerAdRequest物件, 進行廣告請求</p> | |||
<pre style="font-size: 14px"> | |||
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()) | |||
</pre> | |||
<p style="font-size: 18px;">請參考GAMNativeActivity.kt, 在populateNativeAdView()有填充NativeAdView實作細節</p> | |||
<pre style="font-size: 14px"> | |||
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) | |||
} | |||
</pre> | |||
<p style="font-size: 18px;">請參考NativeAdBinding佈局細節, 使用NativeAdView設計原生廣告佈局, 使用MediaView顯示 '''<span style="color:red;">影片</span>''' 或 '''<span style="color:red;">大圖</span>''' 或 '''<span style="color:red;">小圖</span>''' /p> | |||
<pre style="font-size: 14px"> | |||
<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> | |||
</pre> | |||
<p style="font-size: 18px;">長標題 / 短標題設定, 請調整TAmediaGAMNativeAdMapper.kt實作, 將headline設為指定的標題即可</p> | |||
<pre style="font-size: 14px"> | |||
// Mapping TWMNativeAd to AdMob Native AD resource | |||
// headline by longSubject | |||
nativeAd.nativeAdContent.longSubject?.let { headline = it } | |||
//nativeAd.nativeAdContent.shortSubject?.let { headline = it } | |||
</pre> | |||
<br><br> | <br><br> | ||
== | == 使用詳細範例 == | ||
=== 下載中介程式 === | |||
<p style="font-size: 24px;">[[#詳細範例 | 下載連結]]</p> | |||
=== 修改 - AndroidManifest.xml === | |||
*<p style="font-size: 20px;">Google Ad Manager中註冊之應用程式ID (Application ID)</p> | |||
<br> | |||
[[ image:gam_android_02.png | center | 800px ]] | |||
<br><br> | |||
[[ image:gam_android_01.png | center | 800px ]] | |||
<br> | |||
=== 修改 - build.gradle === | |||
*<p style="font-size: 18px;">Google Ad Manager中註冊之套件名稱</p> | |||
<br> | |||
[[ image:gam_android_05.png | center | 800px ]] | |||
<br><br> | |||
[[ image:gam_android_06.png | center | 800px ]] | |||
<br> | |||
=== 修改 - 廣告單元 === | |||
*<p style="font-size: 18px;">Google Ad Manager中註冊之廣告單元</p> | |||
<br> | |||
[[ image:gam_android_04.png | center | 800px ]] | |||
<br><br> | |||
*<p style="font-size: 18px;">修改GAMMainActivity中定義的廣告單元 (ex. <span style="color:#000000; background:#86b953">/ACCOUNT_ID/TEST_AD_UNIT</span> ) </p> | |||
[[ image:gam_android_03.png | center | 800px ]] | |||
<br> | |||
<p style="font-size: 18px;">範例程式主畫面, 左邊按鈕為AdMob程式範例, 右邊按鈕為Ad Manager程式範例, 請點選右邊Ad Manager</p> | |||
{| class="wikitable" style="margin:auto" | |||
|+ 範例程式 | |||
|- | |||
! 主選單 !! Ad Manager | |||
|- | |||
| [[ image:gam_android_mediation_selector.png | 200px ]] || [[ image:gam_android_mediation_selector_gam.png | 200px ]] | |||
|} | |||
<br> | |||
=== 橫幅(Banner) === | === 橫幅(Banner) === | ||
{| class="wikitable" style="margin:auto" | |||
|+ 橫幅(Banner) | |||
|- | |||
! 320x50 !! 300x250 | |||
|- | |||
| [[ image:gam_android_demo_banner.png | 200px ]] || [[ image:gam_android_demo_banner_2.png | 200px ]] | |||
|} | |||
<br> | |||
=== 插頁(Interstitial) === | === 插頁(Interstitial) === | ||
{| class="wikitable" style="margin:auto" | |||
|+ 插頁(Interstitial) | |||
|- | |||
! Interstitial !! Interstitial | |||
|- | |||
| [[ image:gam_android_demo_interstitial_01.png | 200px ]] || [[ image:gam_android_demo_interstitial_02.png | 200px ]] | |||
|} | |||
<br> | |||
=== 原生(Native) === | === 原生(Native) === | ||
{| class="wikitable" style="margin:auto" | |||
|+ 原生(Native) | |||
|- | |||
! NATIVE !! NATIVE IMAGE | |||
|- | |||
| [[ image:gam_android_demo_native_01.png | 200px ]] || [[ image:gam_android_demo_native_02.png | 200px ]] | |||
|} | |||
<br><br> | <br><br> | ||
<p style="font-size: 18px;">[[SDK8_Android_SDK_Developer_Guide| 回首頁]]</p> |
於 2023年10月11日 (三) 03:19 的最新修訂
詳細範例
Ad Manager 22.2.0 Mediation Project (包含橫幅、插頁、原生廣告)。
新增廣告單元 / 收益群組
登入Google Ad Manager
https://admanager.google.com/home/
橫幅(Banner)
進入 Ad Manager 網頁選擇 應用單元 -> 新增廣告單元
名稱: GAM_Mediation_Android_Banner_320x50
大小: 320x50
新增收益群組
名稱: GAM_Mediation_Android_Banner_320x50
狀態: 有效
廣告格式: 橫幅
新增收益夥伴
其他收益夥伴詳細資訊
Label: 用於AdManagerAdView.adUnitId
Class Name: com.taiwanmobile.pt.gam.mediation.TAmediaGAMCustomEvent
Parameter: TAmedia廣告版位
插頁(Interstitial)
進入 Ad Manager 網頁選擇 應用單元 -> 新增廣告單元
名稱: GAM_Mediation_Android_Interstitial
大小: 1024x768, 768x1024, 480x320, 320x480
新增收益群組
名稱: GAM_Mediation_Android_Interstitial
狀態: 有效
廣告格式: 插頁式
新增收益夥伴
其他收益夥伴詳細資訊
Label: 用於AdManagerInterstitialAd.load()
Class Name: com.taiwanmobile.pt.gam.mediation.TAmediaGAMCustomEvent
Parameter: TAmedia廣告版位
原生(Native)
進入 Ad Manager 網頁選擇 應用單元 -> 新增廣告單元
名稱: GAM_Mediation_Android_Native
大小: 自訂顯示
新增收益群組
名稱: GAM_Mediation_Android_Native
狀態: 有效
廣告格式: 原生格式
新增收益夥伴
其他收益夥伴詳細資訊
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設定
避免TAmedia Mediation Class Name被被混淆導致Google Ad Manager無法找到中介實作, 請將下列內容加入 proguard-rules.pro
-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.**
TAmedia中介程式
請將com.taiwanmobile.pt.gam.mediation程式碼加入專案, 請確認Google Ad Manager收益群組設定的Class Name與下列一致
com.taiwanmobile.pt.gam.mediation.TAmediaGAMCustomEvent
請確認TAmedia SDK 在libs目錄
請再次檢查Gradle設定有參考其TAmedia SDK aar檔案
橫幅(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() }
開發者程式
請參考 com.taiwanmobile.pt.guide.gam 相關程式碼
橫幅(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, 使用AdLoader.forNativeAd()載入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()有填充NativeAdView實作細節
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>
長標題 / 短標題設定, 請調整TAmediaGAMNativeAdMapper.kt實作, 將headline設為指定的標題即可
// Mapping TWMNativeAd to AdMob Native AD resource // headline by longSubject nativeAd.nativeAdContent.longSubject?.let { headline = it } //nativeAd.nativeAdContent.shortSubject?.let { headline = it }
使用詳細範例
下載中介程式
修改 - AndroidManifest.xml
Google Ad Manager中註冊之應用程式ID (Application ID)
修改 - build.gradle
Google Ad Manager中註冊之套件名稱
修改 - 廣告單元
Google Ad Manager中註冊之廣告單元
修改GAMMainActivity中定義的廣告單元 (ex. /ACCOUNT_ID/TEST_AD_UNIT )
範例程式主畫面, 左邊按鈕為AdMob程式範例, 右邊按鈕為Ad Manager程式範例, 請點選右邊Ad Manager
主選單 | Ad Manager |
---|---|
橫幅(Banner)
320x50 | 300x250 |
---|---|
插頁(Interstitial)
Interstitial | Interstitial |
---|---|
原生(Native)
NATIVE | NATIVE IMAGE |
---|---|