这边乍一看是一个简单的搬砖,可实际上,笔者还是踩了点坑,这里就写下示例代码,一般下次查阅,也希望能帮到广大读者。
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
//重要! 这个涉及到广告计费,必须正确调用。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?) {
// 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?) {
// //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()
}
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'
穿山甲联盟Android SDK
这些是Kotlin代码,当然穿山甲Demo使用的是Java语言,17年到现在已经有两年的时间了,Kotlin的发展大家有目共睹,真的建议使用Kotlin开发。