之前的文章Android Admob接入中介绍了如何接入和测验Admob的插屏广告、鼓励广告和横幅广告。谈论区有掘友问了为啥没有开屏广告,当然是因为目前我司项目中没有用到开屏广告咯。不过既然有人问了,那么本篇文章就介绍下短少的开屏广告和原生广告。

前置条件以及如何测验请移步Android Admob接入,本文不多赘述。

开屏广告

开屏广告一般在App初度翻开(冷启动)或许App从后台进入前台(热启动)时显现。

官方文档

开屏广告控制类

自定义广告控制类,用于加载、显现开屏广告,代码如下:

class AppOpenAdManager {
    private val appOpenAdUnit = "ca-app-pub-3940256099942544/3419835294"
    private val appOpenAdValidTime = 4 * 60 * 60 * 1000
    private var currentAppOpenAd: AppOpenAd? = null
    private var currentAppOpenAdLoadedTime: Long = 0
    private var loadingAd: Boolean = false
    var showingAd: Boolean = false
        private set
    private var showAdWhenReady: Boolean = false
    private var tempActivity: Activity? = null
    private var tempAppOpenAdShowCallback: AppOpenAdShowCallback? = null
    private val appOpenAdLoadCallback = object : AppOpenAdLoadCallback() {
        override fun onAdLoaded(appOpenAd: AppOpenAd) {
            super.onAdLoaded(appOpenAd)
            // 开屏广告加载成功
            currentAppOpenAdLoadedTime = System.currentTimeMillis()
            currentAppOpenAd = appOpenAd
            loadingAd = false
            // 设置了当加载完结时翻开广告
            if (showAdWhenReady) {
                showAdWhenReady = false
                tempActivity?.let {
                    showAppOpenAd(it, tempAppOpenAdShowCallback)
                }
            }
        }
        override fun onAdFailedToLoad(loadAdError: LoadAdError) {
            super.onAdFailedToLoad(loadAdError)
            // 开屏广告加载失利
            // 官方不主张在此回调中从头加载广告
            // 如果的确需求,则有必要约束最大重试次数,防止在网络受限的情况下连续屡次恳求
            loadingAd = false
        }
    }
    fun loadAd(context: Context) {
        if (!loadingAd) {
            loadingAd = true
            AppOpenAd.load(context, appOpenAdUnit, AdRequest.Builder().build(), appOpenAdLoadCallback)
        }
    }
    fun showAppOpenAd(activity: Activity, appOpenAdShowCallback: AppOpenAdShowCallback? = null, showAdWhenReady: Boolean = false) {
        if (showingAd) {
            // 开屏广告正在展现
            return
        }
        if (!appOpenAdAvailable()) {
            // 开屏广告不可用,从头加载
            loadAd(activity)
            if (showAdWhenReady) {
                // 设置当加载完结时翻开广告,缓存当时页面和回调方法
                this.showAdWhenReady = true
                tempActivity = activity
                tempAppOpenAdShowCallback = appOpenAdShowCallback
            } else {
                // 广告不可用,回调播映完结持续执行后续过程
                appOpenAdShowCallback?.onAppOpenAdShowComplete()
            }
            return
        }
        currentAppOpenAd?.run {
            fullScreenContentCallback = object : FullScreenContentCallback() {
                override fun onAdShowedFullScreenContent() {
                    super.onAdShowedFullScreenContent()
                    // 广告展现
                }
                override fun onAdFailedToShowFullScreenContent(adError: AdError) {
                    super.onAdFailedToShowFullScreenContent(adError)
                    // 广告展现失利,清空缓存数据,从头加载
                    showingAd = false
                    currentAppOpenAd = null
                    appOpenAdShowCallback?.onAppOpenAdShowComplete()
                    tempActivity = null
                    tempAppOpenAdShowCallback = null
                    loadAd(activity)
                }
                override fun onAdDismissedFullScreenContent() {
                    super.onAdDismissedFullScreenContent()
                    // 广告封闭,清空缓存数据,从头加载
                    showingAd = false
                    currentAppOpenAd = null
                    appOpenAdShowCallback?.onAppOpenAdShowComplete()
                    tempActivity = null
                    tempAppOpenAdShowCallback = null
                    loadAd(activity)
                }
            }
            showingAd = true
            show(activity)
            appOpenAdShowCallback?.onAppOpenAdShow()
        }
    }
    fun stopAutoShow() {
        showAdWhenReady = false
        tempActivity = null
        tempAppOpenAdShowCallback = null
    }
    private fun appOpenAdAvailable(): Boolean {
        return currentAppOpenAd != null && (currentAppOpenAdLoadedTime != 0L && System.currentTimeMillis() - currentAppOpenAdLoadedTime <= appOpenAdValidTime)
    }
    interface AppOpenAdShowCallback {
        fun onAppOpenAdShow()
        fun onAppOpenAdShowComplete()
    }
}

冷启动

Application中进行AdMobSDK的初始化以及开屏广告的加载,因为广告加载需求必定时刻,能够在过渡页面中等候一段时刻(例如3秒),若超时后还没有广告填充则直接进入主页面。

  • 自定义Application类
class ExampleApplication : Application() {
    var appOpenAdManager: AppOpenAdManager? = null
    override fun onCreate() {
        super.onCreate()
        appOpenAdManager = AppOpenAdManager()
        MobileAds.initialize(this) { initializationStatus ->
            val readyAdapter = initializationStatus.adapterStatusMap.entries.find {
                it.value.initializationState == AdapterStatus.State.READY
            }
            if (readyAdapter != null) {
                appOpenAdManager?.loadAd(applicationContext)
            }
        }
    }
}
  • AndroidManifest中装备Application
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
    <application
        android:name=".base.ExampleApplication"
        ... >
        ...
    </application>
</manifest>

自定义启动页

自定义启动页作为过渡页面。

  • 启动页(播映广告)
class AppOpenAdActivity : AppCompatActivity() {
    private val handler = Handler(Looper.myLooper() ?: Looper.getMainLooper())
    private val enterRunnable = Runnable {
        // 中止主动显现,防止进入主页后主动展现广告打断用户行为
        (application as ExampleApplication).appOpenAdManager?.stopAutoShow()
        enterHomePage()
    }
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.layout_app_open_activity)
        (application as ExampleApplication).appOpenAdManager?.showAppOpenAd(this, object : AppOpenAdManager.AppOpenAdShowCallback {
            override fun onAppOpenAdShow() {
                // 开屏广告已显现,中止计时线程
                handler.removeCallbacks(enterRunnable)
            }
            override fun onAppOpenAdShowComplete() {
                // 开屏广告播映完毕(成功或失利),中止计时线程并进入主页
                handler.removeCallbacks(enterRunnable)
                enterHomePage()
            }
        }, true)
        // 三秒内没有显现出广告,主动进入主页
        handler.postDelayed(enterRunnable, 3000)
    }
    private fun enterHomePage() {
        startActivity(Intent(this, HomeActivity::class.java))
        finish()
    }
}
  • AndroidManifest中装备启动页
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
    <application
        android:name=".base.ExampleApplication"
        ... >
        <activity
            android:name=".tripartite.admob.AppOpenAdActivity"
            android:exported="true"
            android:screenOrientation="portrait">
            <intent-filter>
                <category android:name="android.intent.category.DEFAULT" />
                <category android:name="android.intent.category.LAUNCHER" />
                <action android:name="android.intent.action.MAIN" />
            </intent-filter>
        </activity>
        <activity
            android:name=".home.HomeActivity"
            android:screenOrientation="portrait" />
    </application>
</manifest>

作用如图:

SplashScreen(官方主张)

从Android12开端,官方主张运用SplashScreen库实现启动页。

  • 增加SplashScreen
dependencies {
    implementation("androidx.core:core-splashscreen:1.0.0")
}
  • 在主页面中装备SplashScreen,并经过viewTreeObserver.addOnPreDrawListener来暂停主页面的制作,实现过渡作用
class HomeActivity : AppCompatActivity() {
    private var noWaitingOpenAd = false
    private val handler = Handler(Looper.myLooper() ?: Looper.getMainLooper())
    private val timeoutRunnable = Runnable {
        // 中止主动显现,防止展现主页后主动显现广告打断用户行为
        (application as ExampleApplication).appOpenAdManager?.stopAutoShow()
        noWaitingOpenAd = true
    }
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        installSplashScreen()
        findViewById<View>(android.R.id.content).run {
            // 注册制作监听,暂停一段时刻等候开屏广告
            viewTreeObserver.addOnPreDrawListener(object : OnPreDrawListener {
                override fun onPreDraw(): Boolean {
                    if (noWaitingOpenAd) {
                        // 不再等候广告,移除制作监听
                        viewTreeObserver.removeOnPreDrawListener(this)
                    }
                    return noWaitingOpenAd
                }
            })
        }
        (application as ExampleApplication).appOpenAdManager?.showAppOpenAd(this, object : AppOpenAdManager.AppOpenAdShowCallback {
            override fun onAppOpenAdShow() {
                // 开屏广告已显现,中止计时线程
                handler.removeCallbacks(timeoutRunnable)
            }
            override fun onAppOpenAdShowComplete() {
                // 开屏广告播映完毕(成功或失利),开端制作主页面
                noWaitingOpenAd = true
            }
        }, true)
        handler.postDelayed(timeoutRunnable, 3000)
        setContentView(R.layout.layout_home_activity)
    }
}
  • AndroidManifest中装备主页
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
    <application
        android:name=".base.ExampleApplication"
        ... >
        <activity
            android:name=".home.HomeActivity"
            android:exported="true"
            android:screenOrientation="portrait">
            <intent-filter>
                <category android:name="android.intent.category.DEFAULT" />
                <category android:name="android.intent.category.LAUNCHER" />
                <action android:name="android.intent.action.MAIN" />
            </intent-filter>
        </activity>
    </application>
</manifest>

作用如图:

热启动

Application中注册ActivityLifecycleCallbacksLifecycleEventObserver等监听,当接收到进入前台事件时显现开屏广告,详细代码如下:

class ExampleApplication : Application() {
    var appOpenAdManager: AppOpenAdManager? = null
    private var currentActivity: Activity? = null
    private var lastShowOpenAdTime: Long = 0
    private var interval = 4 * 60 * 60 * 1000
    override fun onCreate() {
        super.onCreate()
        appOpenAdManager = AppOpenAdManager()
        MobileAds.initialize(this) { initializationStatus ->
            val readyAdapter = initializationStatus.adapterStatusMap.entries.find {
                it.value.initializationState == AdapterStatus.State.READY
            }
            if (readyAdapter != null) {
                appOpenAdManager?.loadAd(applicationContext)
            }
        }
        // 注册ActivityLifecycleCallbacks来记载当时显现的Activity
        registerActivityLifecycleCallbacks(object : ActivityLifecycleCallbacks {
            override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) {}
            override fun onActivityStarted(activity: Activity) {
                // 开屏广告不展现的情况下,记载当时的Activity
                if (appOpenAdManager?.showingAd != true) {
                    currentActivity = activity
                }
            }
            override fun onActivityResumed(activity: Activity) {}
            override fun onActivityPaused(activity: Activity) {}
            override fun onActivityStopped(activity: Activity) {}
            override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) {}
            override fun onActivityDestroyed(activity: Activity) {}
        })
        // 注册LifecycleEventObserver来监听应用进入前台的事件
        ProcessLifecycleOwner.get().lifecycle.addObserver(object : LifecycleEventObserver {
            override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) {
                if (event == Lifecycle.Event.ON_START) {
                    // 应用进入前台,显现开屏广告
                    currentActivity?.let {
                        // 判别前次显现广告与本次实际广告的时刻距离,防止两次广告之间距离太短
                        if (lastShowOpenAdTime == 0L || System.currentTimeMillis() - lastShowOpenAdTime > interval) {
                            appOpenAdManager?.showAppOpenAd(it, object : AppOpenAdManager.AppOpenAdShowCallback {
                                override fun onAppOpenAdShow() {
                                    lastShowOpenAdTime = System.currentTimeMillis()
                                }
                                override fun onAppOpenAdShowComplete() {}
                            })
                        }
                    }
                }
            }
        })
    }
}

作用如图:

原生广告

原生广告经过原生控件(例如TextViewImageView)来出现广告素材,能够嵌入到App页面中,与App整体风格更和谐。

官方文档

加载与显现

运用AdLoader加载广告。以NativeAdView作为根布局,结合TextViewImageView等原生控件出现广告素材。代码如下:

  • 自定义布局文件,以NativeAdView作为根布局
<?xml version="1.0" encoding="utf-8"?>
<com.google.android.gms.ads.nativead.NativeAdView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/native_ad_view"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">
    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:minHeight="50dp"
        android:paddingBottom="10dp">
        <androidx.appcompat.widget.AppCompatTextView
            android:id="@+id/tv_ad_attribution"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:width="15dp"
            android:height="15dp"
            android:background="#FFCC66"
            android:gravity="start"
            android:text="Ad"
            android:textColor="@color/white"
            android:textSize="12sp"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />
        <androidx.appcompat.widget.AppCompatImageView
            android:id="@+id/iv_ad_app_icon"
            android:layout_width="40dp"
            android:layout_height="40dp"
            android:layout_marginStart="20dp"
            android:layout_marginTop="3dp"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@id/tv_ad_attribution" />
        <androidx.appcompat.widget.AppCompatTextView
            android:id="@+id/tv_ad_headline"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_marginEnd="23dp"
            android:textColor="#0000FF"
            android:textSize="16sp"
            android:textStyle="bold"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toEndOf="@id/iv_ad_app_icon"
            app:layout_constraintTop_toTopOf="@id/iv_ad_app_icon"
            tools:text="ad headline" />
        <androidx.appcompat.widget.AppCompatTextView
            android:id="@+id/tv_advertiser"
            android:layout_width="wrap_content"
            android:layout_height="0dp"
            app:layout_constraintBottom_toBottomOf="@id/iv_ad_app_icon"
            app:layout_constraintStart_toStartOf="@id/tv_ad_headline"
            app:layout_constraintTop_toBottomOf="@id/tv_ad_headline" />
        <androidx.appcompat.widget.AppCompatRatingBar
            android:id="@+id/rb_ad_stars"
            style="?android:attr/ratingBarStyleSmall"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:isIndicator="true"
            android:numStars="5"
            android:stepSize="0.5"
            app:layout_constraintBottom_toBottomOf="@id/tv_advertiser"
            app:layout_constraintStart_toEndOf="@id/tv_advertiser"
            app:layout_constraintTop_toTopOf="@id/tv_advertiser" />
        <androidx.appcompat.widget.AppCompatTextView
            android:id="@+id/tv_ad_body"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_marginStart="40dp"
            android:layout_marginEnd="40dp"
            android:textSize="12sp"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@id/iv_ad_app_icon"
            tools:text="ad body" />
        <com.google.android.gms.ads.nativead.MediaView
            android:id="@+id/mv_ad_media"
            android:layout_width="250dp"
            android:layout_height="175dp"
            android:layout_marginTop="5dp"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@id/tv_ad_body" />
        <androidx.appcompat.widget.AppCompatButton
            android:id="@+id/btn_ad_call_to_action"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="10dp"
            android:layout_marginEnd="20dp"
            android:gravity="center"
            android:textSize="12sp"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintTop_toBottomOf="@id/mv_ad_media" />
        <androidx.appcompat.widget.AppCompatTextView
            android:id="@+id/tv_ad_store"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:paddingStart="5dp"
            android:paddingTop="5dp"
            android:paddingEnd="5dp"
            android:textSize="12sp"
            app:layout_constraintBottom_toBottomOf="@id/btn_ad_call_to_action"
            app:layout_constraintEnd_toStartOf="@id/btn_ad_call_to_action"
            app:layout_constraintTop_toTopOf="@id/btn_ad_call_to_action" />
        <androidx.appcompat.widget.AppCompatTextView
            android:id="@+id/tv_ad_price"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:paddingStart="5dp"
            android:paddingTop="5dp"
            android:paddingEnd="5dp"
            android:textSize="12sp"
            app:layout_constraintBottom_toBottomOf="@id/btn_ad_call_to_action"
            app:layout_constraintEnd_toStartOf="@id/tv_ad_store"
            app:layout_constraintTop_toTopOf="@id/btn_ad_call_to_action" />
    </androidx.constraintlayout.widget.ConstraintLayout>
</com.google.android.gms.ads.nativead.NativeAdView>
  • 加载并展现原生广告
class AdmobExampleActivity : AppCompatActivity() {
    private lateinit var binding: LayoutAdmobExampleActivityBinding
    private var nativeAdView: NativeAdView? = null
    private var currentNativeAd: NativeAd? = null
    private val adListener = object : AdListener() {
        override fun onAdLoaded() {
            super.onAdLoaded()
            // 广告加载成功
            // 动态增加NaviteAdView到页面中
            nativeAdView?.let { binding.flNativeAdContainer.addView(it) }
        }
        override fun onAdFailedToLoad(loadAdError: LoadAdError) {
            super.onAdFailedToLoad(loadAdError)
            // 广告加载失利
        }
        override fun onAdOpened() {
            super.onAdOpened()
            // 广告页翻开
        }
        override fun onAdClicked() {
            super.onAdClicked()
            // 广告被点击
        }
        override fun onAdClosed() {
            super.onAdClosed()
            // 广告页封闭
        }
    }
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = DataBindingUtil.setContentView(this, R.layout.layout_admob_example_activity)
        MobileAds.initialize(this, object : OnInitializationCompleteListener {
            override fun onInitializationComplete(initializationStatus: InitializationStatus) {
                val readyAdapter = initializationStatus.adapterStatusMap.entries.find {
                    it.value.initializationState == AdapterStatus.State.READY
                }
                if (readyAdapter != null) {
                    loadNativeAd()
                }
            }
        })
    }
    private fun populateNativeAdView() {
        currentNativeAd?.let { nativeAd ->
            nativeAdView?.let { binding.flNativeAdContainer.removeView(it) }
            (LayoutInflater.from(this).inflate(R.layout.layout_admob_native_ad, null) as? NativeAdView)?.run {
                iconView = findViewById<AppCompatImageView>(R.id.iv_ad_app_icon).apply {
                    nativeAd.icon?.let { setImageDrawable(it.drawable) }
                    visibility = if (nativeAd.icon != null) View.VISIBLE else View.GONE
                }
                headlineView = findViewById<AppCompatTextView>(R.id.tv_ad_headline).apply {
                    text = nativeAd.headline
                }
                advertiserView = findViewById<AppCompatTextView>(R.id.tv_advertiser).apply {
                    text = nativeAd.advertiser
                    visibility = if (nativeAd.advertiser != null) View.VISIBLE else View.INVISIBLE
                }
                starRatingView = findViewById<AppCompatRatingBar>(R.id.rb_ad_stars).apply {
                    nativeAd.starRating?.let { rating = it.toFloat() }
                    visibility = if (nativeAd.starRating != null) View.VISIBLE else View.INVISIBLE
                }
                bodyView = findViewById<AppCompatTextView>(R.id.tv_ad_body).apply {
                    text = nativeAd.body
                    visibility = if (nativeAd.body != null) View.VISIBLE else View.INVISIBLE
                }
                mediaView = findViewById<MediaView>(R.id.mv_ad_media).apply {
                    nativeAd.mediaContent?.let {
                        mediaContent = it
                        it.videoController.videoLifecycleCallbacks = object : VideoController.VideoLifecycleCallbacks() {
                            override fun onVideoStart() {
                                super.onVideoStart()
                                // 视频开端
                            }
                            override fun onVideoEnd() {
                                super.onVideoEnd()
                                // 视频完毕,完毕后能够刷新广告
                            }
                            override fun onVideoPlay() {
                                super.onVideoPlay()
                                // 视频播映
                            }
                            override fun onVideoPause() {
                                super.onVideoPause()
                                // 视频暂停
                            }
                            override fun onVideoMute(mute: Boolean) {
                                super.onVideoMute(mute)
                                // 视频是否静音
                                // mute true 静音 false 非静音
                            }
                        }
                    }
                }
                callToActionView = findViewById<AppCompatButton>(R.id.btn_ad_call_to_action).apply {
                    text = nativeAd.callToAction
                    visibility = if (nativeAd.callToAction != null) View.VISIBLE else View.INVISIBLE
                }
                priceView = findViewById<AppCompatTextView>(R.id.tv_ad_price).apply {
                    text = nativeAd.price
                    visibility = if (nativeAd.price != null) View.VISIBLE else View.INVISIBLE
                }
                storeView = findViewById<AppCompatTextView>(R.id.tv_ad_store).apply {
                    text = nativeAd.store
                    visibility = if (nativeAd.store != null) View.VISIBLE else View.INVISIBLE
                }
                layoutParams = FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.WRAP_CONTENT).apply {
                    gravity = Gravity.BOTTOM
                }
                setNativeAd(nativeAd)
                nativeAdView = this
            }
        }
    }
    private fun loadNativeAd() {
        val adLoader = AdLoader.Builder(this, "ca-app-pub-3940256099942544/2247696110")
            .forNativeAd { nativeAd ->
                // 如果在页面毁掉后触发此回调,需求毁掉NativeAd防止内存泄漏
                if (isDestroyed || isFinishing || isChangingConfigurations) {
                    nativeAd.destroy()
                    return@forNativeAd
                }
                currentNativeAd?.destroy()
                currentNativeAd = nativeAd
                populateNativeAdView()
            }
            .withNativeAdOptions(NativeAdOptions.Builder()
                // 设置视频是否静音播映
                .setVideoOptions(VideoOptions.Builder().setStartMuted(false).build())
                .build())
            .withAdListener(adListener)
            .build()
        adLoader.loadAd(AdRequest.Builder().build())
    }
    override fun onDestroy() {
        super.onDestroy()
        currentNativeAd?.destroy()
    }
}

作用如图:

Android Admob(二)开屏广告和原生广告

不再显现此广告(优化用户体验)

原生广告嵌入在App页面中,用户可能会想要封闭原生广告,能够给用户供给一个封闭按钮封闭广告。AdMob供给了一些相关的API,能够用于标记用户封闭广告的原因,当然不运用相关API直接封闭广告也是能够的。

  • 调整NativeAdOptions,在forNativeAd回调中获取不再显现广告的原因
class AdmobExampleActivity : AppCompatActivity() {
    private val muteThisAdReason = ArrayList<MuteThisAdReason>()
    ...
    private fun loadNativeAd() {
        val adLoader = AdLoader.Builder(this, "ca-app-pub-3940256099942544/2247696110")
            .forNativeAd { nativeAd ->
                ...
                // 判别是否支持自定义不再显现广告
                if (nativeAd.isCustomMuteThisAdEnabled) {
                    // 获取不再显现广告的原因
                    muteThisAdReason.addAll(nativeAd.muteThisAdReasons)
                }
            }
            .withNativeAdOptions(NativeAdOptions.Builder()
                // 设置视频是否静音播映
                .setVideoOptions(VideoOptions.Builder().setStartMuted(false).build())
                // 设置自定义不再显现广告
                .setRequestCustomMuteThisAd(true)
                .build())
            .withAdListener(adListener)
            .build()
        adLoader.loadAd(AdRequest.Builder().build())
    }
}
  • 用户挑选封闭广告时,供给原因让用户挑选,用户挑选后经过API上报原因并移除广告
class AdmobExampleActivity : AppCompatActivity() {
    private lateinit var binding: LayoutAdmobExampleActivityBinding
    private val muteThisAdReason = ArrayList<MuteThisAdReason>()
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = DataBindingUtil.setContentView(this, R.layout.layout_admob_example_activity)
        binding.btnStopNativeAd.setOnClickListener { showChoseMuteNativeAdDialog() }
    }
    private fun showChoseMuteNativeAdDialog() {
        val muteThisAdReasonString = arrayOfNulls<CharSequence>(muteThisAdReason.size)
        for ((index, item) in muteThisAdReason.withIndex()) {
            muteThisAdReasonString[index] = item.description
        }
        AlertDialog.Builder(this)
            .setTitle("封闭此原生广告的原因是?")
            .setItems(muteThisAdReasonString) { dialog, which ->
                if (muteThisAdReason.size > which) {
                    muteNativeAd(muteThisAdReason[which])
                }
            }
            .create()
            .show()
    }
    private fun muteNativeAd(muteThisAdReason: MuteThisAdReason) {
        // 能够上报用户封闭广告的原因,便于优化广告
        currentNativeAd?.muteThisAd(muteThisAdReason)
        nativeAdView?.destroy()
        currentNativeAd?.destroy()
        binding.flNativeAdContainer.removeAllViews()
    }
}

作用如图:

示例

在示例Demo中增加了相关的演示代码。

ExampleDemo github

ExampleDemo gitee