美文网首页
Android平台Admob广告接入和封装

Android平台Admob广告接入和封装

作者: Codd_Zhang | 来源:发表于2020-05-09 00:12 被阅读0次

    前言

    关于Admob如何接入,官方文档已经写的很清楚,所以不是本文的重点。本文主要讲Admob的调用封装。因为作为开发者接入Admob之后,其实工作远没有结束,可能想做预加载,想做些封装让接口更加简洁友好,此外还想让业务代码尽可能不与SDK耦合,等等。其实这部分内容也是一个轮子,那我们就不要重复造轮子了。

    Admob接入

    1. 官方网站:https://developers.google.cn/admob/android/quick-start

    官网文档有中英文版本,阅读上不是什么问题,实际接入难度不大。只是随着版本的更新,文档同步的不是很及时。

    2. 官方开发论坛:https://groups.google.com/forum/#!forum/google-admob-ads-sdk

    遇到一些问题可以到论坛搜索下。我在开发时遇到一个兼容性问题,某些手机上激励广告播放时会突然被强制关闭,后来就是在论坛上找到了解决方案:正在播放的激励广告需要有明确的引用持有,否则可能被系统回收导致广告关闭。

    二次封装

    完整代码可以查看本文后面的github项目地址。

    AdmobManager

    框架内唯一暴露给业务层的接口,是一个单例。业务层只需要跟它打交道就可以进行加载、获取、显示广告等操作。

    object AdmobManager {
        const val TAG = "AdmobManager"
    
        /**
         * 一个id对应一个广告仓库
         */
        var rewardedAdRepoMap: MutableMap<String, RewardAdRepository> = HashMap()
    
        var nativeAdRepoMap: MutableMap<String, NativeAdRepository> = HashMap()
    
        /**
         * 初始化
         */
        fun init(context: Context) {
            MobileAds.initialize(context)
        }
    
    
        //-------------------------激励广告-----------------
    
    
        /**
         * 是否有[id]对应的已经加载完成的激励广告
         */
        fun isRewardAdReady(context: Context?, id: String): Boolean {
            if (context == null || TextUtils.isEmpty(id)) {
                return false
            }
    
            var rewardAdRepo = rewardedAdRepoMap[id]
    
            if (rewardAdRepo == null) {
                rewardAdRepo = RewardAdRepository(id)
                rewardedAdRepoMap[id] = rewardAdRepo
            }
    
            return rewardAdRepo.isReady(context)
        }
    
        /**
         * 加载[id]激励广告,如果仓库没有建立,则建立完再加载
         */
        fun loadRewardAd(context: Context?, id: String, preloadCount: Int = 1) {
            if (context == null || TextUtils.isEmpty(id)) {
                return
            }
    
            var rewardAdRepo = rewardedAdRepoMap[id]
    
            if (rewardAdRepo == null) {
                rewardAdRepo = RewardAdRepository(id)
                rewardedAdRepoMap[id] = rewardAdRepo
            }
    
            rewardAdRepo.setPreloadCount(preloadCount)
            rewardAdRepo.loadAds(context)
        }
    
        /**
         * 显示激励广告
         *
         * return true : 显示成功
         * return false : 显示失败,可能广告仓库没建立,或者广告还没加载完成
         */
        fun showRewardAd(activity: Activity, id: String, listener: RewardAdShowListener?): Boolean {
            if (activity == null || TextUtils.isEmpty(id)) {
                return false
            }
    
            var rewardAdRepo = rewardedAdRepoMap[id]
    
            if (rewardAdRepo == null) {
                rewardAdRepo = RewardAdRepository(id)
                rewardedAdRepoMap[id] = rewardAdRepo
            }
    
            rewardAdRepo?.let {
                if (it.isReady(activity)) {
                    it.show(activity, listener)
    
                    return true
                }
            }
    
            Log.e(TAG, "$id reward ad is not ready")
    
            return false
        }
    
        /**
         * 添加激励广告加载监听器。注意:监听器会在广告的一轮加载成功后被全部移除。
         */
        fun addRewardAdLoadListener(context: Context?, id: String, listener: RewardAdLoadListener?) {
            if (context == null || TextUtils.isEmpty(id) || listener == null) {
                return
            }
    
            var rewardAdRepo = rewardedAdRepoMap[id]
    
            if (rewardAdRepo == null) {
                rewardAdRepo = RewardAdRepository(id)
                rewardedAdRepoMap[id] = rewardAdRepo
            }
    
            rewardAdRepo.addLoadListener(listener)
        }
    
        /**
         * 移除激励广告加载监听器
         */
        fun removeRewardAdLoadListener(context: Context?, id: String, listener: RewardAdLoadListener?) {
            if (context == null || TextUtils.isEmpty(id) || listener == null) {
                return
            }
    
            var rewardAdRepo = rewardedAdRepoMap[id]
    
            if (rewardAdRepo == null) {
                rewardAdRepo = RewardAdRepository(id)
                rewardedAdRepoMap[id] = rewardAdRepo
            }
    
            rewardAdRepo.removeLoadListener(listener)
        }
    
    
        //-------------------------原生广告-----------------
    
        /**
         * 是否有加载好的[id]对应的原生广告
         */
        fun isNativeAdReady(context: Context?, id: String): Boolean {
            if (context == null || TextUtils.isEmpty(id)) {
                return false
            }
    
            var nativeAdRepo = nativeAdRepoMap[id]
    
            if (nativeAdRepo == null) {
                nativeAdRepo = NativeAdRepository(id)
                nativeAdRepoMap[id] = nativeAdRepo
            }
    
            return nativeAdRepo.isReady(context)
        }
    
        /**
         * 加载原生广告
         */
        fun loadNativeAd(context: Context?, id: String, preloadCount: Int = 1) {
            if (context == null || TextUtils.isEmpty(id)) {
                return
            }
    
            var nativeAdRepo = nativeAdRepoMap[id]
    
            if (nativeAdRepo == null) {
                nativeAdRepo = NativeAdRepository(id)
                nativeAdRepoMap[id] = nativeAdRepo
            }
    
            nativeAdRepo.setPreloadCount(preloadCount)
            nativeAdRepo.loadAds(context)
        }
    
        /**
         * 获取原生广告内容
         */
        fun getNativeAd(context: Context?, id: String): UnifiedNativeAd? {
            if (context == null || TextUtils.isEmpty(id)) {
                return null
            }
    
            var nativeAdRepo = nativeAdRepoMap[id]
    
            if (nativeAdRepo == null) {
                nativeAdRepo = NativeAdRepository(id)
                nativeAdRepoMap[id] = nativeAdRepo
            }
    
            return nativeAdRepo.getAd(context)
        }
    
        /**
         * 添加原生广告加载监听器。注意:监听器会在广告的一轮加载成功后被全部移除。
         */
        fun addNativeAdLoadListener(context: Context?, id: String, listener: NativeAdLoadListener?) {
            if (context == null || TextUtils.isEmpty(id) || listener == null) {
                return
            }
    
            var nativeAdRepo = nativeAdRepoMap[id]
    
            if (nativeAdRepo == null) {
                nativeAdRepo = NativeAdRepository(id)
                nativeAdRepoMap[id] = nativeAdRepo
            }
    
            nativeAdRepo.addLoadListener(listener)
        }
    
        /**
         * 移除原生广告加载监听器
         */
        fun removeNativeAdLoadListener(context: Context?, id: String, listener: NativeAdLoadListener?) {
            if (context == null || TextUtils.isEmpty(id) || listener == null) {
                return
            }
    
            var nativeAdRepo = nativeAdRepoMap[id]
    
            if (nativeAdRepo == null) {
                nativeAdRepo = NativeAdRepository(id)
                nativeAdRepoMap[id] = nativeAdRepo
            }
    
            nativeAdRepo.removeLoadListener(listener)
        }
    }
    

    NativeAdRepository

    原生高级广告仓库,一个广告位id对应一个广告仓库。本质是一个广告池,可实现给定数量的广告预加载,并在广告被使用后自动进行个数的加载补足。

    /**
     * 一个id对应一个广告仓库,仓库会自动进行广告的预加载(个数preloadCount),并向外提供广告内容
     *
     * id默认是测试广告
     */
    class NativeAdRepository constructor(private var id: String = "ca-app-pub-3940256099942544/2247696110",
                                         private var preloadCount: Int = 1) {
        /**
         * 已加载的广告列表
         */
        var adList = LinkedList<UnifiedNativeAd>()
    
        /**
         * 是否正在进行广告加载
         */
        var isLoading = false
    
        /**
         * 正在加载的广告个数
         */
        var loadingCount = 0
    
        var loadListenerList = ArrayList<NativeAdLoadListener>()
    
        /**
         * 进行广告加载
         */
        fun loadAds(context: Context) {
            if (isLoading || adList.size >= preloadCount) {
                Log.w(AdmobManager.TAG, "$id NativeAd don't need load")
                return
            }
    
            isLoading = true //开始加载
    
            val request = AdRequest.Builder().build()
    
            val adLoader = AdLoader.Builder(context, id).forUnifiedNativeAd {//广告加载完成
                adList.offer(it)
    
                for(listener in loadListenerList) {
                    listener.onLoaded()
                }
    
                onAdLoaded()
            }.withAdListener(object : AdListener() {
                override fun onAdFailedToLoad(errorCode: Int) {
                    onAdLoaded()
    
                    Log.w(AdmobManager.TAG, "$id NativeAd load failed, errorCode = $errorCode")
                }
            }).build()
    
            //开始加载
            loadingCount = preloadCount - adList.size
            adLoader.loadAds(request, loadingCount)
        }
    
        /**
         * 一个广告加载完成时调用
         */
        private fun onAdLoaded() {
            //更新正在加载的广告个数
            loadingCount--
    
            //所有广告加载完成,状态更新成未在加载中
            if (loadingCount <= 0) {
                isLoading = false
    
                //一般广告加载成功,收到一次通知即可,所以将所有监听器在这里进行移除
                if(adList.size > 0) {
                    loadListenerList.clear()
                }
            }
        }
    
        /**
         * 是否已经有广告加载完成
         */
        fun isReady(context: Context): Boolean {
            return adList.isNotEmpty()
        }
    
        /**
         * 获取加载好的原生广告
         */
        fun getAd(context: Context): UnifiedNativeAd? {
            var ad = adList.poll()
    
            //广告被取走后,需要重新加载广告,保证池子里面有一定数量的预加载广告
            loadAds(context)
    
            return ad
        }
    
        /**
         * 设置预加载个数
         */
        fun setPreloadCount(value: Int) {
            preloadCount = value
        }
    
    
        /**
         * 添加广告加载监听器。注意:监听器会在广告的一轮加载成功后被全部移除。
         */
        fun addLoadListener(listener: NativeAdLoadListener) {
            if (!loadListenerList.contains(listener)) {
                loadListenerList.add(listener)
            }
        }
    
        /**
         * 移除广告加载监听器
         */
        fun removeLoadListener(listener: NativeAdLoadListener) {
            loadListenerList.remove(listener)
        }
    }
    

    RewardAdRepository

    激励广告仓库,一个广告位id对应一个广告参考,实现方式与原生高级广告基本一致。

    
    class RewardAdRepository constructor(private var id: String = "ca-app-pub-3940256099942544/5224354917",
                                         private var preloadCount: Int = 1) {
        /**
         * 是否正在加载
         */
        var isLoading = false
    
        var adList = ArrayList<RewardedAd>()
    
        /**
         * 正在加载的广告个数
         */
        var loadingCount = 0
    
        /**
         * 正在播放的广告需要有明确的引用持有,否则在有些系统里面广告会被强制回收关闭
         */
        var rewardedAdShowing: RewardedAd? = null
    
        var loadListenerList = ArrayList<RewardAdLoadListener>()
    
        val rewardAdLoaderCallback = object : RewardedAdLoadCallback() {
            override fun onRewardedAdLoaded() {
                Log.i(AdmobManager.TAG, "$id Reward Ad loaded")
    
                for(listener in loadListenerList) {
                    listener.onLoaded()
                }
    
                onAdLoaded()
            }
    
            override fun onRewardedAdFailedToLoad(var1: Int) {
                Log.e(AdmobManager.TAG, "$id Reward Ad load failed, errorCode = $var1")
    
                onAdLoaded()
            }
        }
    
        private fun onAdLoaded() {
            loadingCount--
    
            if (loadingCount <= 0) {
                isLoading = false
    
                //一般广告加载成功,收到一次通知即可,所以将所有监听器在这里进行移除
                if(adList.size > 0) {
                    loadListenerList.clear()
                }
            }
        }
    
        /**
         * 加载广告
         */
        fun loadAds(context: Context) {
            if (isLoading) {
                return
            }
    
            //用来放没有加载成功的广告
            var removeList = ArrayList<RewardedAd>()
    
            for (rewardAd in adList) {
                //没加载成功的广告就丢到待删除列表里
                if (!rewardAd.isLoaded) {
                    removeList.add(rewardAd)
                }
            }
    
            adList.removeAll(removeList)
    
            loadingCount = preloadCount - adList.size
    
            val request = AdRequest.Builder().build()
    
            while (adList.size < preloadCount) {
                var rewardedAd =  RewardedAd(context, id)
                adList.add(rewardedAd)
                rewardedAd.loadAd(request, rewardAdLoaderCallback)
    
                isLoading = true
    
                Log.i(AdmobManager.TAG, "$id Reward Ad loading")
            }
        }
    
        /**
         * 是否有加载完成的激励广告
         */
        fun isReady(context: Context): Boolean {
            for(rewardAd in adList) {
                if (rewardAd.isLoaded) {
                    return true
                }
            }
    
            return false
        }
    
        /**
         * 显示激励广告
         */
        fun show(activity: Activity, listener: RewardAdShowListener?) {
            for(rewardAd in adList) {
                if (rewardAd.isLoaded) {
                    Log.i(AdmobManager.TAG, "$id Reward Ad show")
    
                    rewardedAdShowing = rewardAd
    
                    rewardAd.show(activity, object : RewardedAdCallback() {
                        override fun onRewardedAdOpened() {
                            listener?.onShowed()
                        }
    
                        override fun onRewardedAdClosed() {
                            listener?.onClosed()
    
                            rewardedAdShowing = null
                        }
    
                        override fun onUserEarnedReward(@NonNull var1: RewardItem) {
                            listener?.onEarned()
                        }
    
                        override fun onRewardedAdFailedToShow(var1: Int) {
                            listener?.onShowFailed(var1)
                        }
                    })
                }
            }
        }
    
        /**
         * 设置预加载个数
         */
        fun setPreloadCount(value: Int) {
            preloadCount = value
        }
    
        /**
         * 添加广告加载监听器。注意:监听器会在广告的一轮加载成功后被全部移除。
         */
        fun addLoadListener(listener: RewardAdLoadListener) {
            if (!loadListenerList.contains(listener)) {
                loadListenerList.add(listener)
            }
        }
    
        /**
         * 移除广告加载监听器
         */
        fun removeLoadListener(listener: RewardAdLoadListener) {
            loadListenerList.remove(listener)
        }
    }
    

    Demo

    项目地址:https://github.com/CoddZhang/AdmobDemo

    包含:

    1. 对SDK调用的封装代码

    2. 使用测试id实现激励广告和原生高级广告。

    image

    写在最后

    Admob其实是被Google收购的,并非土著的Google开发团队作品,所以SDK的设计水准感觉一般,友好性和自由度上做的不太好,不够赏心悦目。

    相关文章

      网友评论

          本文标题:Android平台Admob广告接入和封装

          本文链接:https://www.haomeiwen.com/subject/lficnhtx.html