「Android Integeration with AdMob Mediation」修訂間的差異
| imported>Wikiuser  (正在將頁面替換為 '<p style="font-size: 18px;">AdMob網站: https://apps.admob.com/ <br><br></p>  === MADP SDK7 ===  === Android_Inte...') | BrandonTeng(留言 | 貢獻)  | ||
| (未顯示由 2 位使用者於中間所作的 52 次修訂) | |||
| 行 1: | 行 1: | ||
| <p style="font-size: 18px;"> | = 詳細範例 = | ||
| :<p style="font-size: 18px;">[[媒體:TAMedia_AdMob_Medation_20230407.zip | AdMob 21.5.0 Mediation Project]] (包含橫幅、插頁、原生廣告)</p> | |||
| === [[ | = '''新增應用程式''' = | ||
| <p style="font-size: 18px;">AdMob網站: https://apps.admob.com/ </p> | |||
| <ul> | |||
| <li><p style="font-size: 18px;">進入 AdMob 網頁選擇 '''應用程式''' > '''新增應用程式'''</p></li> | |||
| [[ image:Admob0.png | 500px ]] | |||
| <br><br><br> | |||
| <li><p style="font-size: 18px;">選擇平台</p></li> | |||
| [[ image:Admob1.png | 800px ]] | |||
| <br><br><br> | |||
| <li><p style="font-size: 18px;">接著輸入應用程式名稱</p></li> | |||
| [[ image:Admob2.png | 800px ]] | |||
| <br><br><br> | |||
| <li><p style="font-size: 18px;">建立完成</p></li> | |||
| [[ image:Admob3-1.png | 800px ]] | |||
| </ul> | |||
| <br><br><br> | |||
| = '''新增廣告單元''' = | |||
| <ul> | |||
| <li><p style="font-size: 18px;">點選先前建立的應用程式並選擇 '''廣告單元''' > '''開始匯入'''</p></li> | |||
| [[ image:Admob3-2.png | 800px ]] | |||
| <br><br><br> | |||
| <li><p style="font-size: 18px;">選擇欲建立的廣告單元 (以'''橫幅廣告'''為例)</p></li> | |||
| [[ image:Admob4.png | 800px ]] | |||
| <br><br><br> | |||
| <li><p style="font-size: 18px;">輸入廣告單元名稱</p></li> | |||
| [[ image:Admob5.png| 1000px ]] | |||
| <br><br><br> | |||
| <li><p style="font-size: 18px;">建立完成,請記下 AdMob 的'''廣告單元ID'''</p></li> | |||
| [[ image:Admob6.png | 800px ]] | |||
| </ul><br><br><br> | |||
| = '''新增中介服務群組''' = | |||
| <ul> | |||
| <li><p style="font-size: 18px;">進入 AdMob 網頁選擇 '''中介服務''' > '''新增中介服務群組'''</p></li> | |||
| [[ image:Admob_m_1.png | 800px ]] | |||
| <br><br><br> | |||
| <li><p style="font-size: 18px;">設定廣告格式、平台</p></li> | |||
| [[ image:Admob_m_2.png | 400px ]] | |||
| <br><br><br> | |||
| <li><p style="font-size: 18px;">設定中介群組名稱並點選'''加入廣告單元'''</p></li> | |||
| [[ image:Admob_m_3.png | 1000px ]] | |||
| <br><br><br> | |||
| <li><p style="font-size: 18px;">選擇先前建立的廣告單元 (以'''橫幅廣告'''為例)</p></li> | |||
| [[ image:Admob_m_4.png | 600px ]] | |||
| <br><br><br> | |||
| <li> | |||
|    <p style="font-size: 18px;">點選'''新增自訂事件''',並設定下列相關資訊:</p> | |||
|    <p style="font-size: 16px">'''有效千次曝光出價''': 越高代表該家聯播網廣告曝光的機會越高</p> | |||
|    <p style="font-size: 16px">'''Class Name''': com.taiwanmobile.pt.adp.mediation.adapter.TAmediaCustomEvent </p> | |||
|    <p style="font-size: 16px">'''Parameter''': 輸入您的 TAmedia 廣告版位ID </p> | |||
| </li> | |||
| [[ image:Admob_m_5.png | 1000px ]] | |||
| <br><br> | |||
| [[ image:Admob_m_6.png | 1000px ]] | |||
| <br><br> | |||
| = '''TAmedia廣告版位ID''' = | |||
| [[ image:Admob_m_9.png | 1000px ]] | |||
| <br><br> | |||
| <p style="font-size: 18px;">點選完成後,中介服務群組的設置便結束</p> | |||
| [[ image:Admob_m_8.png | 1200px ]] | |||
| </ul> | |||
| <br><br><br> | |||
| = '''程式整合''' = | |||
| :<p style="font-size: 18px;">1. 請參考'''[https://developers.google.com/admob/android/quick-start?hl=zh-TW AdMob for Android]''' 網站提供的方式整合Google Ads SDK,此步驟會使用到'''[[#新增應用程式|新增應用程式]]'''所取得的'''應用程式ID'''</p> | |||
| :<p style="font-size: 18px;">2. 下載'''[[Download MADP Android SDK | TAMedia Android SDK]]''',並參考'''[[Android Getting Started SDK8 | 開始使用Getting Started]]''' 整合TAMedia Android SDK</p> | |||
| :<p style="font-size: 18px;">3. 至詳細範例, 下載'''[[#詳細範例 | AdMob 21.5.0 Mediation Project]]''',並整合下列Mediation Code進開發者專案中</p> | |||
| <br><br><br> | |||
| == '''Mediation Code'''== | |||
| Banner / Interstitial / Native等中介實作皆在TAmediaCustomEvent | |||
| == '''Proguard'''== | |||
| 下列mediation class, 開發商於proguard中須進行保護, 避免混淆後找不到該class造成AdMob SDK拋出錯誤訊息 | |||
| <b><span style="color:#ff0000">Could not load custom event implementation class: com.taiwanmobile.pt.adp.mediation.TAmediaNative, trying Adapter implementation class.</span></b> | |||
| <source> | |||
| -keep class com.taiwanmobile.pt.adp.mediation.** { | |||
|     public protected <fields>; | |||
|     public protected <methods>; | |||
| } | |||
| </source> | |||
| == '''Developer Sample Code''' == | |||
| === '''Banner''' === | |||
| ::<p style="font-size: 18px;">1. 在MainActivity.kt中輸入AdUnit Id</p> | |||
|     companion object { | |||
|         private const val ADUNIT_ID_BANNER_320x50 = "<b>{AdMob Banner AdUnit Id}</b>" | |||
|         private const val ADUNIT_ID_BANNER_300x250 = "<b>{AdMob Banner AdUnit Id}</b>" | |||
|         private const val ADUNIT_ID_SMART_BANNER = "<b>{AdMob Banner AdUnit Id}</b>" | |||
|         private const val ADUNIT_ID_INTERSTITIAL = "{AdMob Interstitial AdUnit Id}" | |||
|         private const val ADUNIT_ID_NATIVE = "{AdMob Native AdUnit Id}" | |||
|         const val KEY_ADUNITID = "adUnitId" | |||
|         const val KEY_ADSIZE = "adSize" | |||
|     } | |||
| ::<p style="font-size: 18px;">2. 在layout檔案中加入可放置廣告的RelativeLayout(※僅供參考,開發者可依照自訂的layout進行配置使用)</p> | |||
|     <RelativeLayout | |||
|         android:id="@+id/adContainer" | |||
|         android:layout_width="wrap_content" | |||
|         android:layout_height="wrap_content" | |||
|         android:layout_centerHorizontal="true" | |||
|         android:layout_alignParentBottom="true"> | |||
|     </RelativeLayout> | |||
| ::<p style="font-size: 18px;">3. BannerActivity 程式加入Banner的宣告, 設定AdUnitId與AdSize</p> | |||
|     class BannerActivity : AppCompatActivity() { | |||
|         private var adView: AdView? = null | |||
|         override fun onCreate(savedInstanceState: Bundle?) { | |||
|             super.onCreate(savedInstanceState) | |||
|             setContentView(R.layout.activity_banner) | |||
|             val adContainer = findViewById<View>(R.id.adContainer) as RelativeLayout | |||
|             val args = intent.extras | |||
|             if (args != null) { | |||
|                 val adUnitId = args.getString(MainActivity.KEY_ADUNITID) | |||
|                 val adSize: AdSize = when (args.getString(MainActivity.KEY_ADSIZE)) { | |||
|                     BANNER_320x50 -> { | |||
|                         AdSize.BANNER | |||
|                     } | |||
|                     BANNER_300x250 -> { | |||
|                         AdSize.MEDIUM_RECTANGLE | |||
|                     } | |||
|                     else -> { | |||
|                         val displayMetrics = resources.displayMetrics | |||
|                         val dpWidth = (displayMetrics.widthPixels / displayMetrics.density).toInt() | |||
|                         AdSize.getCurrentOrientationAnchoredAdaptiveBannerAdSize( | |||
|                             this, | |||
|                             dpWidth | |||
|                         ) | |||
|                     } | |||
|                 } <br> | |||
|                 // Banner initial | |||
|                 adUnitId?.let { | |||
|                     val request = AdRequest.Builder().build() | |||
|                     adView = AdView(this@BannerActivity) | |||
|                     adView?.adUnitId = it | |||
|                     adView?.adSize = adSize | |||
|                     adView?.adListener = AdListenerImpl() | |||
|                     adView?.loadAd(request) | |||
|                     // add view into layout | |||
|                     adContainer.addView(adView) | |||
|                 } | |||
|             } | |||
|         } | |||
|  } | |||
| <br><br> | |||
| === '''Interstitial''' === | |||
| ::<p style="font-size: 18px;">1. 在MainActivity.kt中輸入AdUnit Id</p> | |||
|     companion object { | |||
|         private const val ADUNIT_ID_BANNER_320x50 = "{AdMob Banner AdUnit Id}" | |||
|         private const val ADUNIT_ID_BANNER_300x250 = "{AdMob Banner AdUnit Id}" | |||
|         private const val ADUNIT_ID_SMART_BANNER = "{AdMob Banner AdUnit Id}" | |||
|         private const val ADUNIT_ID_INTERSTITIAL = "<b>{AdMob Interstitial AdUnit Id}</b>" | |||
|         private const val ADUNIT_ID_NATIVE = "{AdMob Native AdUnit Id}" | |||
|         const val KEY_ADUNITID = "adUnitId" | |||
|         const val KEY_ADSIZE = "adSize" | |||
|     } | |||
| ::<p style="font-size: 18px;">2. InterstitialActivity 程式加入Interstitial的宣告, 設定AdUnitId</p> | |||
| <source> | |||
| class InterstitialActivity : AppCompatActivity() { | |||
|     private var interstitialAd: InterstitialAd? = null | |||
|     private var adUnitId: String? = null | |||
|     private lateinit var binding: ActivityInterstitialBinding | |||
|     override fun onCreate(savedInstanceState: Bundle?) { | |||
|         super.onCreate(savedInstanceState) | |||
|         binding = ActivityInterstitialBinding.inflate(layoutInflater) | |||
|         val view = binding.root | |||
|         setContentView(view) | |||
|         val args = intent.extras | |||
|         if (args != null) { | |||
|             adUnitId = args.getString(MainActivity.KEY_ADUNITID) | |||
|         } | |||
|     } | |||
|     // triggered in activity_int.xml | |||
|     fun fireAd(v: View?) { | |||
|         adUnitId?.let { | |||
|             val adRequest = AdRequest.Builder().build() | |||
|             InterstitialAd.load(this, it, adRequest, object : InterstitialAdLoadCallback() { | |||
|                 override fun onAdLoaded(interstitialAd: InterstitialAd) { | |||
|                     this@InterstitialActivity.interstitialAd = interstitialAd | |||
|                     Toast.makeText( | |||
|                         baseContext, | |||
|                         "onAdLoaded(interstitial) invoked!!", | |||
|                         Toast.LENGTH_SHORT | |||
|                     ).show() | |||
|                     interstitialAd.show(this@InterstitialActivity) | |||
|                 } | |||
|                 override fun onAdFailedToLoad(loadAdError: LoadAdError) { | |||
|                     Toast.makeText( | |||
|                         baseContext, | |||
|                         loadAdError.message, | |||
|                         Toast.LENGTH_SHORT | |||
|                     ).show() | |||
|                     interstitialAd = null | |||
|                 } | |||
|             }) | |||
|         } | |||
|     } | |||
| } | |||
| </source> | |||
| <br><br> | <br><br> | ||
| [[ | === '''Native''' === | ||
| ::<p style="font-size: 18px;">1. 在MainActivity.kt中輸入AdUnit Id</p> | |||
|     companion object { | |||
|         private const val ADUNIT_ID_BANNER_320x50 = "{AdMob Banner AdUnit Id}" | |||
|         private const val ADUNIT_ID_BANNER_300x250 = "{AdMob Banner AdUnit Id}" | |||
|         private const val ADUNIT_ID_SMART_BANNER = "{AdMob Banner AdUnit Id}" | |||
|         private const val ADUNIT_ID_INTERSTITIAL = "{AdMob Interstitial AdUnit Id}" | |||
|         private const val ADUNIT_ID_NATIVE = "<b>{AdMob Native AdUnit Id}</b>" | |||
|         const val KEY_ADUNITID = "adUnitId" | |||
|         const val KEY_ADSIZE = "adSize" | |||
|     } | |||
| ::<p style="font-size: 18px;">2. NativeActivity的layout如下, 在layout檔案中加入可放置原生廣告的nativeContainer(※這裡以FrameLayout為例,開發者可依照自訂的layout進行配置使用)</p> | |||
|     <LinearLayout | |||
|         xmlns:android="http://schemas.android.com/apk/res/android" | |||
|         android:layout_width="match_parent" | |||
|         android:layout_height="match_parent" | |||
|         android:paddingBottom="@dimen/activity_vertical_margin" | |||
|         android:paddingLeft="@dimen/activity_horizontal_margin" | |||
|         android:paddingRight="@dimen/activity_horizontal_margin" | |||
|         android:paddingTop="@dimen/activity_vertical_margin" | |||
|         android:orientation="vertical"> | |||
|     <font size = "+1" color="#ff0000"><FrameLayout</font> | |||
|             android:id="@+id/native_container" | |||
|             android:layout_width="match_parent" | |||
|             android:layout_height="wrap_content" | |||
|             android:layout_marginTop="@dimen/activity_vertical_margin" /> | |||
|     </LinearLayout> | |||
| ::<p style="font-size: 18px;">3. 準備廣告佈局native_ad.xml, 使用AdMob com.google.android.gms.ads.nativead.NativeAdView</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"> | |||
|             <LinearLayout | |||
|                 android:layout_width="match_parent" | |||
|                 android:layout_height="wrap_content" | |||
|                 android:layout_gravity="center" | |||
|                 android:background="#FFFFFF" | |||
|                 android:minHeight="50dp" | |||
|                 android:orientation="vertical"> | |||
|                 <LinearLayout | |||
|                     android:layout_width="match_parent" | |||
|                     android:layout_height="wrap_content" | |||
|                     android:orientation="vertical" | |||
|                     android:paddingLeft="20dp" | |||
|                     android:paddingTop="3dp" | |||
|                     android:paddingRight="20dp"> | |||
|                     <LinearLayout | |||
|                         android:layout_width="match_parent" | |||
|                         android:layout_height="wrap_content" | |||
|                         android:orientation="horizontal"> | |||
|                         <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" /> | |||
|                         <LinearLayout | |||
|                             android:layout_width="match_parent" | |||
|                             android:layout_height="wrap_content" | |||
|                             android:orientation="vertical"> | |||
|                             <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" /> | |||
|                         </LinearLayout> | |||
|                     </LinearLayout> | |||
|                     <LinearLayout | |||
|                         android:layout_width="match_parent" | |||
|                         android:layout_height="wrap_content" | |||
|                         android:orientation="vertical"> | |||
|                     <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" /> | |||
|                     <LinearLayout | |||
|                         android:layout_width="wrap_content" | |||
|                         android:layout_height="wrap_content" | |||
|                         android:layout_gravity="end" | |||
|                         android:orientation="horizontal" | |||
|                         android:paddingTop="10dp" | |||
|                         android:paddingBottom="10dp"> | |||
|                             <Button | |||
|                                 android:id="@+id/ad_call_to_action" | |||
|                                 android:layout_width="wrap_content" | |||
|                                 android:layout_height="wrap_content" | |||
|                                 android:gravity="center" | |||
|                                 android:textSize="12sp" /> | |||
|                         </LinearLayout> | |||
|                     </LinearLayout> | |||
|                 </LinearLayout> | |||
|             </LinearLayout> | |||
|     </com.google.android.gms.ads.nativead.NativeAdView> | |||
| ::<p style="font-size: 18px;">4. 使用AdMob AdLoader載入原生廣告</p> | |||
| :::<p style="font-size: 18px;">當AdLoader取得原生廣告時, 產出(inflate)原生廣告佈局native_ad.xml並進行NativeAdView物件填充(population), 詳情可參考下方<b>populateNativeAdView()</b></p> | |||
| :::<p style="font-size: 18px;">NativeAdView填充下列屬性: headline, body, call to action, icon, mediaView等資訊</p> | |||
| :::<p style="font-size: 18px;">填充後將native_ad.xml物件加入nativeContainer</p> | |||
| <source> | |||
|     override fun onCreate(savedInstanceState: Bundle?) { | |||
|         super.onCreate(savedInstanceState) | |||
|         binding = ActivityNativeBinding.inflate(layoutInflater) | |||
|         val view = binding.root | |||
|         setContentView(view) | |||
|         val args = intent.extras | |||
|         args?.let { | |||
|             val adUnitId = args.getString(MainActivity.KEY_ADUNITID) ?: "" | |||
|             val adLoader = AdLoader.Builder(this, adUnitId) | |||
|                 .forNativeAd { ad: NativeAd -> | |||
|                     nativeAd = ad | |||
|                     val adLayout = NativeAdBinding.inflate(layoutInflater) | |||
|                     populateNativeAdView(ad, adLayout) | |||
|                     binding.nativeContainer.removeAllViews() | |||
|                     binding.nativeContainer.addView(adLayout.root) | |||
|                     // If this callback occurs after the activity is destroyed, you | |||
|                     // must call destroy and return or you may get a memory leak. | |||
|                     // Note `isDestroyed` is a method on Activity. | |||
|                     if (isDestroyed) { | |||
|                         ad.destroy() | |||
|                         return@forNativeAd | |||
|                     } | |||
|                 } | |||
|                 .withAdListener(object : AdListener() { | |||
|                     override fun onAdFailedToLoad(adError: LoadAdError) { | |||
|                         Toast.makeText(this@NativeActivity, "onAdFailedToLoad", Toast.LENGTH_LONG) | |||
|                             .show() | |||
|                     } | |||
|                     override fun onAdClicked() { | |||
|                         super.onAdClicked() | |||
|                         Toast.makeText(this@NativeActivity, "onAdClicked", Toast.LENGTH_LONG) | |||
|                             .show() | |||
|                     } | |||
|                     override fun onAdImpression() { | |||
|                         super.onAdImpression() | |||
|                         Toast.makeText(this@NativeActivity, "onAdImpression", Toast.LENGTH_LONG) | |||
|                             .show() | |||
|                     } | |||
|                 }) | |||
|                 .withNativeAdOptions( | |||
|                     NativeAdOptions.Builder() | |||
|                         // Methods in the NativeAdOptions.Builder class can be | |||
|                         // used here to specify individual options settings. | |||
|                         .build() | |||
|                 ) | |||
|                 .build() | |||
|             adLoader.loadAd(AdRequest.Builder().build()) | |||
|         } | |||
|     } | |||
|     /** | |||
|      * Populates a [NativeAdView] object with data from a given [NativeAd]. | |||
|      * | |||
|      * @param nativeAd the object containing the ad's assets | |||
|      * @param viewBinding the view binding object [NativeAdBinding] contains the [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.setNativeAd(nativeAd) | |||
|     } | |||
| </source> | |||
| ::<p style="font-size: 18px;">5. 設計架構圖</p> | |||
| :::<p style="font-size: 18px;">- 藍色為TAmedia SDK原生廣告類別, 黃色為AdMob SDK原生廣告類別</p> | |||
| :::<p style="font-size: 18px;">- 開發者僅需在native_ad.xml使用AdMob SDK, 其他則由TAmedia mediation實作負責</p> | |||
| :::<p style="font-size: 18px;">- 佈局中如果有發現AdMob SDK MediaView, TAmedia SDK TWMMediaView則會主動覆蓋至上面, 負責顯示影音廣告</p> | |||
| [[ image:AdMob_Mediation_SI_20220425.png | 1000px ]] | |||
| == '''AdMob SDK 21.5.0 設定調整''' == | |||
| <p style="font-size: 18px;">中介程式改為TAmediaCustomEvent (Adapter)</p> | |||
| <p style="font-size: 18px;">將CustomEventBanner / CustomEventInterstitial / CustomEventNative改為TAmediaCustomEvent</p> | |||
| [[ image:AdMob_Mediation_21_5_0_Setup_20230307_03.png | 1000px ]] | |||
| <p style="font-size: 18px;">Banner / Interstitial / Native等中介實作皆在TAmediaCustomEvent</p> | |||
| [[ image:AdMob_Mediation_22_2_0_Setup_20230717_01.png | 1000px ]] | |||
| == '''AdMob SDK 22.2.0 設定調整''' [[檔案:new-xxl.png|30px]]== | |||
| *<p style="font-size: 18px;">支援AdMob SDK 22.2.0</p> | |||
| *<p style="font-size: 18px;">支援Google Ad Manager</p> | |||
| **<p style="font-size: 18px;">[[支援Google Ad Manager| Android Integeration with Ad Manager Mediation]]</p> | |||
| <br> | |||
| <br> | |||
| <p style="font-size: 18px;">[[SDK8_Android_SDK_Developer_Guide| 回首頁]]</p> | |||
於 2023年8月8日 (二) 01:50 的最新修訂
詳細範例
- AdMob 21.5.0 Mediation Project (包含橫幅、插頁、原生廣告) 
新增應用程式
AdMob網站: https://apps.admob.com/
新增廣告單元
新增中介服務群組
- 進入 AdMob 網頁選擇 中介服務 > 新增中介服務群組 
- 設定廣告格式、平台 
- 設定中介群組名稱並點選加入廣告單元 
- 選擇先前建立的廣告單元 (以橫幅廣告為例) 
- 
   點選新增自訂事件,並設定下列相關資訊: 有效千次曝光出價: 越高代表該家聯播網廣告曝光的機會越高 Class Name: com.taiwanmobile.pt.adp.mediation.adapter.TAmediaCustomEvent Parameter: 輸入您的 TAmedia 廣告版位ID 
 
 
TAmedia廣告版位ID
點選完成後,中介服務群組的設置便結束
程式整合
- 1. 請參考AdMob for Android 網站提供的方式整合Google Ads SDK,此步驟會使用到新增應用程式所取得的應用程式ID 
- 2. 下載 TAMedia Android SDK,並參考 開始使用Getting Started 整合TAMedia Android SDK 
- 3. 至詳細範例, 下載 AdMob 21.5.0 Mediation Project,並整合下列Mediation Code進開發者專案中 
Mediation Code
Banner / Interstitial / Native等中介實作皆在TAmediaCustomEvent
Proguard
下列mediation class, 開發商於proguard中須進行保護, 避免混淆後找不到該class造成AdMob SDK拋出錯誤訊息
Could not load custom event implementation class: com.taiwanmobile.pt.adp.mediation.TAmediaNative, trying Adapter implementation class.
-keep class com.taiwanmobile.pt.adp.mediation.** {
    public protected <fields>;
    public protected <methods>;
}Developer Sample Code
Banner
- 1. 在MainActivity.kt中輸入AdUnit Id 
 
   companion object {
       private const val ADUNIT_ID_BANNER_320x50 = "{AdMob Banner AdUnit Id}"
       private const val ADUNIT_ID_BANNER_300x250 = "{AdMob Banner AdUnit Id}"
       private const val ADUNIT_ID_SMART_BANNER = "{AdMob Banner AdUnit Id}"
       private const val ADUNIT_ID_INTERSTITIAL = "{AdMob Interstitial AdUnit Id}"
       private const val ADUNIT_ID_NATIVE = "{AdMob Native AdUnit Id}"
       const val KEY_ADUNITID = "adUnitId"
       const val KEY_ADSIZE = "adSize"
   }
- 2. 在layout檔案中加入可放置廣告的RelativeLayout(※僅供參考,開發者可依照自訂的layout進行配置使用) 
 
   <RelativeLayout
       android:id="@+id/adContainer"
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:layout_centerHorizontal="true"
       android:layout_alignParentBottom="true">
   </RelativeLayout>
- 3. BannerActivity 程式加入Banner的宣告, 設定AdUnitId與AdSize 
 
   class BannerActivity : AppCompatActivity() {
       private var adView: AdView? = null
       override fun onCreate(savedInstanceState: Bundle?) {
           super.onCreate(savedInstanceState)
           setContentView(R.layout.activity_banner)
           val adContainer = findViewById<View>(R.id.adContainer) as RelativeLayout
           val args = intent.extras
           if (args != null) {
               val adUnitId = args.getString(MainActivity.KEY_ADUNITID)
               val adSize: AdSize = when (args.getString(MainActivity.KEY_ADSIZE)) {
                   BANNER_320x50 -> {
                       AdSize.BANNER
                   }
                   BANNER_300x250 -> {
                       AdSize.MEDIUM_RECTANGLE
                   }
                   else -> {
                       val displayMetrics = resources.displayMetrics
                       val dpWidth = (displayMetrics.widthPixels / displayMetrics.density).toInt()
                       AdSize.getCurrentOrientationAnchoredAdaptiveBannerAdSize(
                           this,
                           dpWidth
                       )
                   }
               } 
               // Banner initial
               adUnitId?.let {
                   val request = AdRequest.Builder().build()
                   adView = AdView(this@BannerActivity)
                   adView?.adUnitId = it
                   adView?.adSize = adSize
                   adView?.adListener = AdListenerImpl()
                   adView?.loadAd(request)
                   // add view into layout
                   adContainer.addView(adView)
               }
           }
       }
}
Interstitial
- 1. 在MainActivity.kt中輸入AdUnit Id 
 
   companion object {
       private const val ADUNIT_ID_BANNER_320x50 = "{AdMob Banner AdUnit Id}"
       private const val ADUNIT_ID_BANNER_300x250 = "{AdMob Banner AdUnit Id}"
       private const val ADUNIT_ID_SMART_BANNER = "{AdMob Banner AdUnit Id}"
       private const val ADUNIT_ID_INTERSTITIAL = "{AdMob Interstitial AdUnit Id}"
       private const val ADUNIT_ID_NATIVE = "{AdMob Native AdUnit Id}"
       const val KEY_ADUNITID = "adUnitId"
       const val KEY_ADSIZE = "adSize"
   }
- 2. InterstitialActivity 程式加入Interstitial的宣告, 設定AdUnitId 
 
class InterstitialActivity : AppCompatActivity() {
    private var interstitialAd: InterstitialAd? = null
    private var adUnitId: String? = null
    private lateinit var binding: ActivityInterstitialBinding
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityInterstitialBinding.inflate(layoutInflater)
        val view = binding.root
        setContentView(view)
        val args = intent.extras
        if (args != null) {
            adUnitId = args.getString(MainActivity.KEY_ADUNITID)
        }
    }
    // triggered in activity_int.xml
    fun fireAd(v: View?) {
        adUnitId?.let {
            val adRequest = AdRequest.Builder().build()
            InterstitialAd.load(this, it, adRequest, object : InterstitialAdLoadCallback() {
                override fun onAdLoaded(interstitialAd: InterstitialAd) {
                    this@InterstitialActivity.interstitialAd = interstitialAd
                    Toast.makeText(
                        baseContext,
                        "onAdLoaded(interstitial) invoked!!",
                        Toast.LENGTH_SHORT
                    ).show()
                    interstitialAd.show(this@InterstitialActivity)
                }
                override fun onAdFailedToLoad(loadAdError: LoadAdError) {
                    Toast.makeText(
                        baseContext,
                        loadAdError.message,
                        Toast.LENGTH_SHORT
                    ).show()
                    interstitialAd = null
                }
            })
        }
    }
}
Native
- 1. 在MainActivity.kt中輸入AdUnit Id 
 
   companion object {
       private const val ADUNIT_ID_BANNER_320x50 = "{AdMob Banner AdUnit Id}"
       private const val ADUNIT_ID_BANNER_300x250 = "{AdMob Banner AdUnit Id}"
       private const val ADUNIT_ID_SMART_BANNER = "{AdMob Banner AdUnit Id}"
       private const val ADUNIT_ID_INTERSTITIAL = "{AdMob Interstitial AdUnit Id}"
       private const val ADUNIT_ID_NATIVE = "{AdMob Native AdUnit Id}"
       const val KEY_ADUNITID = "adUnitId"
       const val KEY_ADSIZE = "adSize"
   }
- 2. NativeActivity的layout如下, 在layout檔案中加入可放置原生廣告的nativeContainer(※這裡以FrameLayout為例,開發者可依照自訂的layout進行配置使用) 
 
   <LinearLayout
       xmlns:android="http://schemas.android.com/apk/res/android"
       android:layout_width="match_parent"
       android:layout_height="match_parent"
       android:paddingBottom="@dimen/activity_vertical_margin"
       android:paddingLeft="@dimen/activity_horizontal_margin"
       android:paddingRight="@dimen/activity_horizontal_margin"
       android:paddingTop="@dimen/activity_vertical_margin"
       android:orientation="vertical">
   <FrameLayout
           android:id="@+id/native_container"
           android:layout_width="match_parent"
           android:layout_height="wrap_content"
           android:layout_marginTop="@dimen/activity_vertical_margin" />
   </LinearLayout>
- 3. 準備廣告佈局native_ad.xml, 使用AdMob com.google.android.gms.ads.nativead.NativeAdView 
 
   <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">
           <LinearLayout
               android:layout_width="match_parent"
               android:layout_height="wrap_content"
               android:layout_gravity="center"
               android:background="#FFFFFF"
               android:minHeight="50dp"
               android:orientation="vertical">
               <LinearLayout
                   android:layout_width="match_parent"
                   android:layout_height="wrap_content"
                   android:orientation="vertical"
                   android:paddingLeft="20dp"
                   android:paddingTop="3dp"
                   android:paddingRight="20dp">
                   <LinearLayout
                       android:layout_width="match_parent"
                       android:layout_height="wrap_content"
                       android:orientation="horizontal">
                       <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" />
                       <LinearLayout
                           android:layout_width="match_parent"
                           android:layout_height="wrap_content"
                           android:orientation="vertical">
                           <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" />
                       </LinearLayout>
                   </LinearLayout>
                   <LinearLayout
                       android:layout_width="match_parent"
                       android:layout_height="wrap_content"
                       android:orientation="vertical">
                   <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" />
                   <LinearLayout
                       android:layout_width="wrap_content"
                       android:layout_height="wrap_content"
                       android:layout_gravity="end"
                       android:orientation="horizontal"
                       android:paddingTop="10dp"
                       android:paddingBottom="10dp">
                           <Button
                               android:id="@+id/ad_call_to_action"
                               android:layout_width="wrap_content"
                               android:layout_height="wrap_content"
                               android:gravity="center"
                               android:textSize="12sp" />
                       </LinearLayout>
                   </LinearLayout>
               </LinearLayout>
           </LinearLayout>
   </com.google.android.gms.ads.nativead.NativeAdView>
- 4. 使用AdMob AdLoader載入原生廣告 - 當AdLoader取得原生廣告時, 產出(inflate)原生廣告佈局native_ad.xml並進行NativeAdView物件填充(population), 詳情可參考下方populateNativeAdView() 
- NativeAdView填充下列屬性: headline, body, call to action, icon, mediaView等資訊 
- 填充後將native_ad.xml物件加入nativeContainer 
 
 
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityNativeBinding.inflate(layoutInflater)
        val view = binding.root
        setContentView(view)
        val args = intent.extras
        args?.let {
            val adUnitId = args.getString(MainActivity.KEY_ADUNITID) ?: ""
            val adLoader = AdLoader.Builder(this, adUnitId)
                .forNativeAd { ad: NativeAd ->
                    nativeAd = ad
                    val adLayout = NativeAdBinding.inflate(layoutInflater)
                    populateNativeAdView(ad, adLayout)
                    binding.nativeContainer.removeAllViews()
                    binding.nativeContainer.addView(adLayout.root)
                    // If this callback occurs after the activity is destroyed, you
                    // must call destroy and return or you may get a memory leak.
                    // Note `isDestroyed` is a method on Activity.
                    if (isDestroyed) {
                        ad.destroy()
                        return@forNativeAd
                    }
                }
                .withAdListener(object : AdListener() {
                    override fun onAdFailedToLoad(adError: LoadAdError) {
                        Toast.makeText(this@NativeActivity, "onAdFailedToLoad", Toast.LENGTH_LONG)
                            .show()
                    }
                    override fun onAdClicked() {
                        super.onAdClicked()
                        Toast.makeText(this@NativeActivity, "onAdClicked", Toast.LENGTH_LONG)
                            .show()
                    }
                    override fun onAdImpression() {
                        super.onAdImpression()
                        Toast.makeText(this@NativeActivity, "onAdImpression", Toast.LENGTH_LONG)
                            .show()
                    }
                })
                .withNativeAdOptions(
                    NativeAdOptions.Builder()
                        // Methods in the NativeAdOptions.Builder class can be
                        // used here to specify individual options settings.
                        .build()
                )
                .build()
            adLoader.loadAd(AdRequest.Builder().build())
        }
    }
    /**
     * Populates a [NativeAdView] object with data from a given [NativeAd].
     *
     * @param nativeAd the object containing the ad's assets
     * @param viewBinding the view binding object [NativeAdBinding] contains the [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.setNativeAd(nativeAd)
    }- 5. 設計架構圖 - - 藍色為TAmedia SDK原生廣告類別, 黃色為AdMob SDK原生廣告類別 
- - 開發者僅需在native_ad.xml使用AdMob SDK, 其他則由TAmedia mediation實作負責 
- - 佈局中如果有發現AdMob SDK MediaView, TAmedia SDK TWMMediaView則會主動覆蓋至上面, 負責顯示影音廣告 
 
 
AdMob SDK 21.5.0 設定調整
中介程式改為TAmediaCustomEvent (Adapter)
將CustomEventBanner / CustomEventInterstitial / CustomEventNative改為TAmediaCustomEvent
Banner / Interstitial / Native等中介實作皆在TAmediaCustomEvent
AdMob SDK 22.2.0 設定調整 
- 支援AdMob SDK 22.2.0 
- 支援Google Ad Manager 
















