赞
踩
这边乍一看是一个简单的搬砖,可实际上,笔者还是踩了点坑,这里就写下示例代码,一般下次查阅,也希望能帮到广大读者。
PS:这里最值得注意的是,虽然官方提供的示例代码众多,但是实际情况下,我们能够使用的是TTAdNative(原生广告)以下全部为该类型广告,可能是笔者接触较少,不知道其他广告的使用方法,如果有使用到其他方式并成功调用者,请不吝赐教。
//开屏广告加载超时时间,建议大于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")
同上是原生广告
不同的
//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}") // } // // }) }
PS:就是App进入首页后突然传出一个窗口,让你想秒关的哪个广告。
/** * 加载插屏广告 */ 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: 代码部分要与创建时一一对应
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()) }
直接点完成即可
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 而已
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>
//广告
implementation(name: 'open_ad_sdk', ext: 'aar')
implementation 'pl.droidsonroids.gif:android-gif-drawable:1.2.6'
这些是Kotlin代码,当然穿山甲Demo使用的是Java语言,17年到现在已经有两年的时间了,Kotlin的发展大家有目共睹,真的建议使用Kotlin开发。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。