穿山甲(巨量引擎)广告接入

前言

这边乍一看是一个简单的搬砖,可实际上,笔者还是踩了点坑,这里就写下示例代码,一般下次查阅,也希望能帮到广大读者。

PS:这里最值得注意的是,虽然官方提供的示例代码众多,但是实际情况下,我们能够使用的是TTAdNative(原生广告)以下全部为该类型广告,可能是笔者接触较少,不知道其他广告的使用方法,如果有使用到其他方式并成功调用者,请不吝赐教。

开屏广告

kp

  //开屏广告加载超时时间,建议大于3000,这里为了冷启动第一次加载到广告并且展示,示例设置了3000ms
  	 	private val AD_TIME_OUT = 3000
        val createAdNative = TTAdSdk.getAdManager().createAdNative(this)
        //step3:创建开屏广告请求参数AdSlot,具体参数含义参考文档
        val adSlot = AdSlot.Builder()
            .setCodeId("5029535")
            .setSupportDeepLink(true)
            .setImageAcceptedSize(1080, 1920)
            .build()
        createAdNative.loadSplashAd(adSlot, object : TTAdNative.SplashAdListener {
            override fun onSplashAdLoad(ad: TTSplashAd?) {
                if (null == ad) return
                //RxToast.showToast("开屏广告请求成功")
                //获取SplashView
                val view = ad?.splashView
                if (view != null) {
                    mSplashContainer.removeAllViews()
                    //把SplashView 添加到ViewGroup中,注意开屏广告view:width >=70%屏幕宽;height >=50%屏幕宽
                    mSplashContainer.addView(view)
                    //设置不开启开屏广告倒计时功能以及不显示跳过按钮,如果这么设置,您需要自定义倒计时逻辑
                    //ad.setNotAllowSdkCountdown();
                } else {
                    launchActivity<MainActivity> {}
                    finish()
                }

                //设置SplashView的交互监听器
                ad.setSplashInteractionListener(object : TTSplashAd.AdInteractionListener {
                    override fun onAdClicked(view: View, type: Int) {

                        //RxToast.showToast("开屏广告点击")
                    }

                    override fun onAdShow(view: View, type: Int) {
                        //RxToast.showToast("开屏广告展示")
                    }

                    override fun onAdSkip() {
                        //RxToast.showToast("开屏广告跳过")
                        launchActivity<MainActivity> {}
                        finish()
                    }

                    override fun onAdTimeOver() {
                        launchActivity<MainActivity> {}
                        finish()
                    }
                })
                if (ad?.interactionType === TTAdConstant.INTERACTION_TYPE_DOWNLOAD) {
                    ad?.setDownloadListener(object : TTAppDownloadListener {
                        internal var hasShow = false

                        override fun onIdle() {

                        }

                        override fun onDownloadActive(
                            totalBytes: Long,
                            currBytes: Long,
                            fileName: String,
                            appName: String
                        ) {
                            if (!hasShow) {
                                //RxToast.showToast("下载中...")
                                hasShow = true
                            }
                        }

                        override fun onDownloadPaused(
                            totalBytes: Long,
                            currBytes: Long,
                            fileName: String,
                            appName: String
                        ) {
                            //RxToast.showToast("下载暂停...")

                        }

                        override fun onDownloadFailed(
                            totalBytes: Long,
                            currBytes: Long,
                            fileName: String,
                            appName: String
                        ) {
                            //RxToast.showToast("下载失败...")
                        }

                        override fun onDownloadFinished(totalBytes: Long, fileName: String, appName: String) {

                        }

                        override fun onInstalled(fileName: String, appName: String) {

                        }
                    })
                }
            }

            override fun onTimeout() {
                //RxToast.showToast("广告:onTimeout")
                launchActivity<MainActivity> {}
                finish()
            }

            override fun onError(p0: Int, p1: String?) {
                //RxToast.showToast("广告:onTimeout")
                launchActivity<MainActivity> {}
                finish()
            }
        }, AD_TIME_OUT)
    }

开屏广告最简单,我们只需要点完成即可,需要注意的是生成后的广告位ID能对应得上即可
setCodeId("5029535")id

Banner广告

同上是原生广告

不同的

  1. 监听器有所不同NativeAdListener
  2. setImageAcceptedSize一定要与下放后红框内标的值一样
  3. setNativeAdType设置成AdSlot.TYPE_BANNER

banner

    //step2:创建TTAdNative对象,createAdNative(Context context) banner广告context需要传入Activity对象
    val mTTAdNative: TTAdNative by lazy {
        TTAdSdk.getAdManager().createAdNative(requireContext())
    }
    //广告部分
    private fun loadBannerAd(codeId: String) {
//        binding.mBannerContainer
        //step4:创建广告请求参数AdSlot,具体参数含义参考文档
        val adSlot = AdSlot.Builder()
            .setCodeId(codeId) //广告位id
            .setSupportDeepLink(true)
            .setNativeAdType(AdSlot.TYPE_BANNER)
            .setAdCount(3) //请求广告数量为1到3条
//            .setExpressViewAcceptedSize(350F,350F) //期望模板广告view的size,单位dp
            .setImageAcceptedSize(600, 300)
            .build()
//         Caused by: java.lang.IllegalArgumentException: 必须设置请求原生广告的类型,目前支持TYPE_BANNER和TYPE_INTERACTION_AD
        //step5:请求广告,对请求回调的广告作渲染处理
        mTTAdNative.loadNativeAd(adSlot, object : TTAdNative.NativeAdListener {
            override fun onNativeAdLoad(ads: MutableList<TTNativeAd>?) {
                if (ads == null || ads.isEmpty()) {
                    return
                }
                val imageUrls = ads.map { ad ->
                    ad.imageList[0].imageUrl
                }
//                val imageList = ads[0].imageList
                Log.i("onNativeAdLoad", "ads.size:${ads.size}")
                Log.i("onNativeAdLoad", "imageUrls.size:${imageUrls.size}")
                binding.banner.apply {
                    setImageLoader(GlideImageLoader())
                    setImages(
                        imageUrls
//                        arrayListOf(
//                            "https://up.enterdesk.com/edpic_360_360/0f/18/15/0f18151ad295ecd910291beca5f54dd0.jpg",
//                            "https://up.enterdesk.com/edpic_360_360/06/ab/c9/06abc90dd7ebd86a2a928baae0725303.jpg"
//                        )

                    )
                    //banner设置方法全部调用完毕时最后调用
                    start()
                }
//                val banner = Class.forName("com.youth.banner.Banner")
//                val field = banner.getDeclaredField("imageViews")
//                field.isAccessible = true
//                val imageViews = field.get(banner) as List<View>
                //重要! 这个涉及到广告计费,必须正确调用。convertView必须使用ViewGroup。
//                Log.i("onError", "imageViews:"+imageViews.toString())
                val imageViews = arrayListOf<View>()
                //现在要获取字段day02b的值
                val declaredFields = binding.banner.javaClass.declaredFields
                try {
                    declaredFields.forEach { field ->
                        val name = field.name
                        if (name == "imageViews") {
                            //用于获取private成员变量
                            field.isAccessible = true
                            Log.i("declaredFields", "字段名称: :$name")

                            //字段值
                            val o = field.get(binding.banner) as List<View>
                            imageViews.addAll(o)
                            Log.i("declaredFields", "要获取字段的值:$o")
                        }
                    }

                } catch (e: IllegalAccessException) {
                    e.printStackTrace()
                }


                ads.forEach {
                    it.registerViewForInteraction(
                        binding.banner as ViewGroup,
                        imageViews,
                        imageViews,
                        object : TTNativeAd.AdInteractionListener {
                            override fun onAdClicked(view: View, ad: TTNativeAd?) {
                                //RxToast.showToast("onAdClicked")
                            }

                            override fun onAdCreativeClick(view: View, ad: TTNativeAd?) {
                                //RxToast.showToast("onAdCreativeClick")
                            }

                            override fun onAdShow(ad: TTNativeAd?) {
                                //RxToast.showToast("onAdShow")
                            }
                        })
                }
            }

            override fun onError(code: Int, message: String) {
//                //RxToast.showToast("load error : $code, $message")
                Log.i("onError", "load error : $code, $message")
            }

        })

//        mTTAdNative.loadNativeExpressAd(adSlot, object : TTAdNative.NativeExpressAdListener {
//            override fun onNativeExpressAdLoad(ads: MutableList<TTNativeExpressAd>?) {
//                Log.i("onNativeAdLoad", ads.toString())
//            }
//
//
//            override fun onError(code: Int, message: String) {
//                //RxToast.showToast("load error : $code, $message")
//                Log.i("load error : $code, $message")
//            }
//
//        })

// Caused by: java.lang.IllegalArgumentException: 请求非原生广告的类型,请勿调用setNativeAdType()方法
//        mTTAdNative.loadBannerExpressAd(adSlot, object : TTAdNative.NativeExpressAdListener {
//
//            override fun onError(code: Int, message: String) {
//                //RxToast.showToast("load error : $code, $message")
//                mBannerContainer.removeAllViews()
//            }
//
//            override fun onNativeExpressAdLoad(ads: MutableList<TTNativeExpressAd>?) {
//                //RxToast.showToast("load error : 请求成功 ads?.size:${ads?.size}")
//            }
//
//        })
    }

插屏广告

cp
PS:就是App进入首页后突然传出一个窗口,让你想秒关的哪个广告。

  1. 和Banner广告比,这个除了type为AdSlot.TYPE_INTERACTION_AD其他基本一致。
  2. setImageAcceptedSize(600, 600)和上图的所标注的1:1x相对于即可。


    /**
     * 加载插屏广告
     */
    private fun loadInteractionAd(codeId: String) {
        //step4:创建插屏广告请求参数AdSlot,具体参数含义参考文档
        val adSlot = Builder()
            .setCodeId(codeId)
            .setSupportDeepLink(true)
            .setAdCount(1) //请求广告数量为1到3条
            .setImageAcceptedSize(600, 600) //根据广告平台选择的尺寸,传入同比例尺寸
            .setNativeAdType(AdSlot.TYPE_INTERACTION_AD)
            .build()
        //step5:请求广告,调用插屏广告异步请求接口
        val mTTAdNative = TTAdSdk.getAdManager().createAdNative(this)
        mTTAdNative.loadNativeAd(adSlot, object : TTAdNative.NativeAdListener {
            override fun onNativeAdLoad(ads: MutableList<TTNativeAd>?) {
                Log.i("onNativeAdLoad", Gson().toJson(ads))
                if (ads == null || ads.isEmpty()) {
                    return
                }
                showAd(ads[0])
            }

            override fun onError(code: Int, message: String) {
                //RxToast.showToast("load error : $code, $message")
                Log.i("onError", "load error : $code, $message")
            }
        })
    }

//==============================自定义一个对话框===========================================
    lateinit var mAdDialog: Dialog
    private fun showAd(ad: TTNativeAd) {
        Log.i("onNativeAdLoad", Gson().toJson(ad))
        mAdDialog = Dialog(this, R.style.native_insert_dialog)
        mAdDialog.setCancelable(true)
        mAdDialog.setContentView(R.layout.native_insert_ad_layout)
        val mRootView = mAdDialog.findViewById<ViewGroup>(R.id.native_insert_ad_root)
        val mAdImageView = mAdDialog.findViewById<ImageView>(R.id.native_insert_ad_img)
        //限制dialog 的最大宽度不能超过屏幕,宽高最小为屏幕宽的 1/3
        val dm = this.resources.displayMetrics
        val maxWidth = dm?.widthPixels ?: 0
        val minWidth = maxWidth / 3
        mAdImageView.setMaxWidth(maxWidth)
        mAdImageView.setMinimumWidth(minWidth)
        mAdImageView.setMinimumHeight(minWidth)
        val iv = mAdDialog.findViewById<ImageView>(R.id.native_insert_ad_logo)
        //绑定关闭按钮
        val stream = ByteArrayOutputStream()
        try {
            ad.adLogo.compress(Bitmap.CompressFormat.PNG, 100, stream)
            Glide.with(this)
                .load(stream.toByteArray())
                .into(iv)
        } catch (e: Exception) {
        } finally {
            try {
                stream.close()
            } catch (e: Exception) {
                e.printStackTrace()
            }
        }

        ad.registerViewForInteraction(mRootView, listOf(mAdImageView), listOf(mAdImageView),
            object : TTNativeAd.AdInteractionListener {
                override fun onAdShow(p0: TTNativeAd?) {

                }

                override fun onAdCreativeClick(p0: View?, p1: TTNativeAd?) {
                    mAdDialog.dismiss()
                }

                override fun onAdClicked(p0: View?, p1: TTNativeAd?) {
                    mAdDialog.dismiss()
                }

            })
        if (ad.imageList != null && !ad.imageList.isEmpty()) {
            val image = ad.imageList[0]
            if (image != null && image.isValid) {
                Glide.with(MainActivity@ this).load(image.imageUrl).into(mAdImageView)
            }
        }
        mAdDialog.show()
    }

激励广告(看视频)

PS: 代码部分要与创建时一一对应
jl
对应

    private var mHasShowDownloadActive = false
    private fun loadAd(function: (rewardVerify: Boolean) -> Unit) {
//        function(true)
//        return
        //step4:创建广告请求参数AdSlot,具体参数含义参考文档
        val adSlot = AdSlot.Builder()
//            .setCodeId("927650269")
            .setCodeId("929535513")
            .setSupportDeepLink(true)
            .setImageAcceptedSize(1080, 1920)
            .setRewardName("语音包解锁") //奖励的名称
            .setRewardAmount(1)  //奖励的数量
            .setUserID("12768")//用户id,必传参数
            .setMediaExtra("media_extra") //附加参数,可选
            .setOrientation(TTAdConstant.VERTICAL) //必填参数,期望视频的播放方向:TTAdConstant.HORIZONTAL 或 TTAdConstant.VERTICAL
            .build()

        //step5:请求广告
        mTTAdNative.loadRewardVideoAd(adSlot, object : TTAdNative.RewardVideoAdListener {
            override fun onError(code: Int, message: String) {
                //RxToast.showToast(message)
            }

            //视频广告加载后,视频资源缓存到本地的回调,在此回调后,播放本地视频,流畅不阻塞。
            override fun onRewardVideoCached() {
                //RxToast.showToast("rewardVideoAd video cached")
            }

            //视频广告的素材加载完毕,比如视频url等,在此回调后,可以播放在线视频,网络不好可能出现加载缓冲,影响体验。
            override fun onRewardVideoAdLoad(ad: TTRewardVideoAd) {
                //RxToast.showToast("rewardVideoAd loaded")
                ad.setRewardAdInteractionListener(object : TTRewardVideoAd.RewardAdInteractionListener {

                    override fun onAdShow() {
                        //RxToast.showToast("rewardVideoAd show")
                    }

                    override fun onAdVideoBarClick() {
                        //RxToast.showToast("rewardVideoAd bar click")
                    }

                    override fun onAdClose() {
                        //RxToast.showToast("rewardVideoAd close")
                        function(false)
                    }

                    //视频播放完成回调
                    override fun onVideoComplete() {
                        //RxToast.showToast("rewardVideoAd complete")
                    }

                    override fun onVideoError() {
                        //RxToast.showToast("rewardVideoAd error")
                    }

                    //视频播放完成后,奖励验证回调,rewardVerify:是否有效,rewardAmount:奖励梳理,rewardName:奖励名称
                    override fun onRewardVerify(rewardVerify: Boolean, rewardAmount: Int, rewardName: String) {
                        RxToast.showToast("激活" + if (rewardVerify) "成功" else "失败")
                        Log.i(
                            "onRewardVerify", "verify:" + rewardVerify + " amount:" + rewardAmount +
                                    " name:" + rewardName
                        )
                        function(rewardVerify)
                    }

                    override fun onSkippedVideo() {
                        //RxToast.showToast("rewardVideoAd has onSkippedVideo")
                    }
                })
                ad.showRewardVideoAd(requireActivity())
                ad.setDownloadListener(object : TTAppDownloadListener {
                    override fun onIdle() {
                        mHasShowDownloadActive = false
                    }

                    override fun onDownloadActive(
                        totalBytes: Long,
                        currBytes: Long,
                        fileName: String,
                        appName: String
                    ) {
                        if (!mHasShowDownloadActive) {
                            mHasShowDownloadActive = true
                            //RxToast.showToast("下载中,点击下载区域暂停")
                        }
                    }

                    override fun onDownloadPaused(
                        totalBytes: Long,
                        currBytes: Long,
                        fileName: String,
                        appName: String
                    ) {
                        //RxToast.showToast("下载暂停,点击下载区域继续")
                    }

                    override fun onDownloadFailed(
                        totalBytes: Long,
                        currBytes: Long,
                        fileName: String,
                        appName: String
                    ) {
                        //RxToast.showToast("下载失败,点击下载区域重新下载")
                    }

                    override fun onDownloadFinished(totalBytes: Long, fileName: String, appName: String) {
                        //RxToast.showToast("下载完成,点击下载区域重新下载")
                    }

                    override fun onInstalled(fileName: String, appName: String) {
                        //RxToast.showToast("安装完成,点击下载区域打开")
                    }
                })
            }
        })
    }

    val mTTAdNative: TTAdNative by lazy {
        TTAdSdk.getAdManager().createAdNative(requireActivity())
    }

信息流广告(列表页)

直接点完成即可
xxl

val ads = arrayListOf<TTFeedAd>()
    lateinit var mTTAdNative: TTAdNative
    /**
     * 加载feed广告
     */
    private fun loadListAd() {
        mTTAdNative = TTAdSdk.getAdManager().createAdNative(requireActivity())
        //step4:创建feed广告请求类型参数AdSlot,具体参数含义参考文档
        val adSlot = AdSlot.Builder()
//            .setCodeId("927650179")
            .setCodeId("929535710")
            .setSupportDeepLink(true)
            .setImageAcceptedSize(228, 150)
            .setAdCount(3) //请求广告数量为1到3条11
            .build()
        //step5:请求广告,调用feed广告异步请求接口,加载到广告后,拿到广告素材自定义渲染
        mTTAdNative.loadFeedAd(adSlot, object : TTAdNative.FeedAdListener {
            override fun onFeedAdLoad(ads: MutableList<TTFeedAd>?) {
                if (ads == null || ads.isEmpty()) {
                    Log.i("loadFeedAd", "on FeedAdLoaded: ad is null!")
                    return
                }
                Log.i("loadFeedAd", "FeedAdLoaded: ad is null!ads ===============" + ads.size)
                if (ads.size <= 0) return
                this@VpItemFragment.ads.addAll(ads)
                myBaseQuickAdapter.notifyDataSetChanged()
            }

            override fun onError(code: Int, message: String) {
                Log.i("loadFeedAd", "code: :$code  message :$message")
            }
        })
    }
    //========================Adapter======================
    val myBaseQuickAdapter =
        object : BaseQuickAdapter<File, VpBaseViewHolder>(R.layout.layout_vp_item) {
            override fun convert(helper: VpBaseViewHolder?, item: File) {
                val adView = helper!!.getView<ImageView>(R.id.ad)
                val videView = helper!!.getView<ViewGroup>(R.id.videView)
                adView.visibility = View.GONE
                videView.visibility = View.GONE
                val num = helper?.layoutPosition ?: 0
                if (ads.size > 0 && num < ads.size)
                    if (num == 0 || num % 2 == 0) {
                        val ad = ads[num]
                        if (ad == null) {

                        } else if (
                            ad.imageMode == TTAdConstant.IMAGE_MODE_SMALL_IMG
                            || ad.imageMode == TTAdConstant.IMAGE_MODE_LARGE_IMG
                            || ad.imageMode == TTAdConstant.IMAGE_MODE_GROUP_IMG
                            || ad.imageMode == TTAdConstant.IMAGE_MODE_VERTICAL_IMG
                        ) {
                            ad.registerViewForInteraction(
                                helper.itemView as ViewGroup,
                                listOf(adView),
                                listOf(adView),
                                object : TTNativeAd.AdInteractionListener {
                                    override fun onAdClicked(view: View, ad: TTNativeAd?) {
                                        if (ad != null) {
//                                        RxToast.showToast("广告" + ad.title + "被点击")
                                        }
                                    }

                                    override fun onAdCreativeClick(view: View, ad: TTNativeAd?) {
                                        if (ad != null) {
//                                        RxToast.showToast("广告" + ad.title + "被创意按钮被点击")
                                        }
                                    }

                                    override fun onAdShow(ad: TTNativeAd?) {
                                        if (ad != null) {
//                                        RxToast.showToast("广告" + ad.title + "展示")
                                        }
                                    }
                                })
                            Glide.with(this@VpItemFragment).load(ad.imageList[0].imageUrl)
                                .into(adView.apply { visibility = View.VISIBLE })
                        } else if (ad.imageMode == TTAdConstant.IMAGE_MODE_VIDEO) {
                            val video = ad.getAdView()
                            if (video != null) {
                                if (video.parent == null) {
                                    videView.removeAllViews()
                                    videView.addView(video)
                                }
                            }
                            videView.visibility = View.VISIBLE
                            ad.registerViewForInteraction(
                                helper.itemView as ViewGroup,
                                listOf(video),
                                listOf(video),
                                object : TTNativeAd.AdInteractionListener {
                                    override fun onAdClicked(view: View, ad: TTNativeAd?) {
                                        if (ad != null) {
//                                        RxToast.showToast("广告" + ad.title + "被点击")
                                        }
                                    }

                                    override fun onAdCreativeClick(view: View, ad: TTNativeAd?) {
                                        if (ad != null) {
//                                        RxToast.showToast("广告" + ad.title + "被创意按钮被点击")
                                        }
                                    }

                                    override fun onAdShow(ad: TTNativeAd?) {
                                        if (ad != null) {
//                                        RxToast.showToast("广告" + ad.title + "展示")
                                        }
                                    }
                                })
                        } else {
//                            RxToast.showToast("图片展示样式错误")
                        }
                    } 
            }
        }

有人会好奇这个videView是什么,其实就是一个简单的FrameLayout 而已
videoView

集成部分

manifest

//权限
    <uses-permission android:name="android.permission.VIBRATE"/>
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
    <uses-permission android:name="android.permission.CALL_PHONE"/>
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.CAMERA"/>
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/> <!-- 获取网络状态 -->
    <uses-permission android:name="android.permission.INTERNET"/> <!-- 网络通信 -->
    <uses-permission android:name="android.permission.READ_PHONE_STATE"/> <!-- 获取设备信息 -->
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/> <!-- 获取MAC地址 -->
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <!-- 读写sdcard,storage等等 -->
    <uses-permission android:name="android.permission.RECORD_AUDIO"/> <!-- 允许程序录制音频 -->
    <uses-permission android:name="android.permission.GET_TASKS"/>
    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/> <!-- 如果有视频相关的广告且使用textureView播放,请务必添加,否则黑屏 -->
    <uses-permission android:name="android.permission.WAKE_LOCK"/>
    <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>
    <uses-permission
            android:name="android.permission.PACKAGE_USAGE_STATS"
            tools:ignore="ProtectedPermissions"/>
//7.0权限            
<provider
        android:name="com.bytedance.sdk.openadsdk.TTFileProvider"
        android:authorities="${applicationId}.TTFileProvider"
        android:exported="false"
        android:grantUriPermissions="true">
    <meta-data
            android:name="android.support.FILE_PROVIDER_PATHS"
            android:resource="@xml/file_paths"/>
</provider>

build.gradle

    //广告
    implementation(name: 'open_ad_sdk', ext: 'aar')
    implementation 'pl.droidsonroids.gif:android-gif-drawable:1.2.6'

SDK下载

穿山甲联盟Android SDK

最后

这些是Kotlin代码,当然穿山甲Demo使用的是Java语言,17年到现在已经有两年的时间了,Kotlin的发展大家有目共睹,真的建议使用Kotlin开发。

发布了141 篇原创文章 · 获赞 40 · 访问量 17万+

猜你喜欢

转载自blog.csdn.net/qq_20330595/article/details/102666068
今日推荐