Android 原生广告集成
概述
原生广告是一种可以自定义样式的广告形式,能够与应用界面无缝融合,具有以下特点:
- 高度自定义的外观
- 与应用内容自然融合
- 更好的用户体验
- 较高的点击率和转化率
集成步骤
参考demo示例的NativeAdHelper
1. 初始化原生广告
在 Activity 或 Fragment 中初始化原生广告:
kotlin
/**
* 原生广告帮助类
*
* 负责原生广告的加载、展示和生命周期管理
* 支持模板信息流和自渲染信息流两种展示方式
*
* @param activity 上下文Activity
* @param logger 日志打印工具
*/
class NativeAdHelper(private val activity: Activity, private val logger: PrintLogger) {
/**
* 原生广告对象
*
* 用于管理原生广告的加载、展示和销毁
*/
private var nativeAdObject: NativeAdObject? = null
/**
* 加载原生广告
*
* 该方法会创建广告配置,初始化原生广告对象,并设置广告监听器
* 最后调用load()方法开始加载广告
*/
fun load() {
// 创建广告配置对象,设置广告位ID和广告尺寸
val adConfig = UjuAdConfig(
placementId = DemoConfig.getNativePlacementId(), // 原生广告位ID
adViewSize = AdViewSize(width = 320, height = 100) // 广告尺寸:320x100
)
// 初始化原生广告对象
nativeAdObject = NativeAdObject(activity, adConfig)
// 设置广告监听器,监听广告的各种事件
nativeAdObject?.setAdObjectListener(object : FeedAdObjectListener {
/**
* 广告加载成功回调
*
* @param placementId 广告位ID
*/
override fun onLoadSuccess(placementId: String) {
// 广告加载成功,此时可以展示,建议展示前判断isReady
logger.add("Native: onLoadSuccess")
}
/**
* 广告加载失败回调
*
* @param error 错误信息
* @param placementId 广告位ID
*/
override fun onLoadError(
error: UjuException,
placementId: String
) {
// 记录加载错误信息
logger.add("Native: onLoadError")
DemoLogUtils.d("Native: onLoadError")
}
/**
* 广告展示过程中出错回调
*
* @param error 错误信息
* @param placementId 广告位ID
*/
override fun onAdError(
error: UjuException,
placementId: String
) {
// 记录广告错误信息,包含错误消息和错误码
logger.add("Native: onAdError:message:${error.message}, code:${error.code}")
DemoLogUtils.e("Native: onAdError:message:${error.message}, code:${error.code}")
}
/**
* 广告展示成功回调
*/
override fun onAdShow() {
// 获取广告信息,记录ecpm值
val adInfo = nativeAdObject?.getAdInfo()
logger.add("Native: onAdShow: ecpm:${adInfo?.ecpm}")
DemoLogUtils.d("Native: onAdShow: ecpm:${adInfo?.ecpm}")
}
/**
* 广告被点击回调
*/
override fun onAdClicked() {
// 记录广告点击事件
logger.add("Native: onAdClicked")
}
/**
* 广告关闭回调
*/
override fun onAdClosed() {
// 记录广告关闭事件
logger.add("Native: onAdClosed")
}
/**
* 广告落地页关闭回调
*/
override fun onLpClosed() {
// 记录落地页关闭事件
logger.add("Native: onLpClosed")
}
})
// 开始加载广告
nativeAdObject?.load()
// 记录加载广告的事件
logger.add("Native: load, placementId:${adConfig.placementId}")
DemoLogUtils.d("Native: load, placementId:${adConfig.placementId}")
}
/**
* 展示原生广告
*
* 根据广告类型(模板信息流或自渲染信息流)采用不同的展示方式
* 模板信息流:直接调用show()方法展示
* 自渲染信息流:自定义布局,填充数据并绑定交互
*
* @param viewGroup 用于容纳广告的ViewGroup
*/
fun show(viewGroup: ViewGroup) {
// 检查广告对象是否已创建
val adObject = nativeAdObject ?: run {
logger.add("Native: 请先加载广告")
return
}
// 检查广告是否已准备就绪
if (adObject.isReady()) {
// 判断广告类型:模板信息流或自渲染信息流
if (adObject.getFeedType() == FeedType.EXPRESS) {
// 模板信息流:直接调用show()方法展示
adObject.show(activity, viewGroup)
} else {
// 自渲染信息流:自定义布局,填充数据并绑定交互
// 获取物料数据
val data = adObject.getAdData()
if (data == null) {
// 物料数据为空,提示用户
Toast.makeText(activity, "缺失物料数据", Toast.LENGTH_SHORT).show()
return
}
// 加载自定义广告布局
val adView = activity.layoutInflater.inflate(R.layout.banner_feed_ad_view_layout, null)
// 填充广告数据
adView.findViewById<TextView>(R.id.tvADTitle).text = data.title // 广告标题
adView.findViewById<TextView>(R.id.tvADDesc).text = data.desc // 广告描述
adView.findViewById<TextView>(R.id.tvADSource).text = data.source // 广告来源
adView.findViewById<TextView>(R.id.btnADCreative).text = data.callToAction // 行动号召按钮
// 获取图片视图
val ivAdPic = adView.findViewById<ImageView>(R.id.ivADPic) // 广告大图
val ivAdSmall = adView.findViewById<ImageView>(R.id.ivADSmall) // 广告商图标
// 确定广告图片URL
var imageUrl = ""
if (data.imageUrl != null) {
imageUrl = data.imageUrl.toString() // 使用单张图片URL
} else if (!data.imageUrlList.isNullOrEmpty()) {
imageUrl = data.imageUrlList?.get(0) ?: "" // 使用图片列表中的第一张
}
// 加载广告图片
Glide.with(activity).load(imageUrl).into(ivAdPic)
// 加载广告商图标
Glide.with(activity).load(data.iconUrl).into(ivAdSmall)
// 创建广告视图绑定器,用于绑定广告数据和视图
val binder = NativeAdViewBinder(
titleId = R.id.tvADTitle, // 标题视图ID
descId = R.id.tvADDesc, // 描述视图ID
sourceId = R.id.tvADSource, // 来源视图ID
imageId = R.id.ivADPic, // 图片视图ID
imageViews = listOf(ivAdPic), // 图片视图列表
mediaViewId = R.id.flVideo, // 媒体视图ID(用于视频广告)
iconId = R.id.ivADSmall, // 图标视图ID
callToActionId = R.id.btnADCreative, // 行动号召按钮ID
logoLayoutId = R.id.flADLogo // 广告标识布局ID
)
// 绑定点击响应,使广告可以被点击
adObject.registerViewForInteraction(
activity, // 上下文Activity
adView, // 广告视图
viewGroup, // 容器视图
binder // 视图绑定器
)
}
} else {
// 广告未准备就绪,记录日志
logger.add("Native: 广告还未准备好")
}
}
/**
* 检查广告是否已加载
*
* @return true表示广告对象已创建,false表示未创建
* 注意:此方法仅检查广告对象是否存在,不保证广告已准备就绪
* 要检查广告是否可展示,请使用isReady()方法
*/
fun isLoaded(): Boolean {
return nativeAdObject != null
}
/**
* 销毁广告对象
*
* 当不再需要广告时,调用此方法销毁广告对象,释放资源
*/
fun destroy() {
// 销毁广告对象
nativeAdObject?.destroy()
// 置空广告对象引用
nativeAdObject = null
}
}最佳实践
1. 广告布局设计
- 与应用风格一致:使用与应用相同的设计语言
- 清晰的广告标识:确保用户能够识别这是广告
- 合理的信息层次:标题、描述、品牌信息清晰可见
- 响应式设计:适应不同屏幕尺寸
2. 优化建议
- 预加载广告:在需要展示广告前提前加载
- 缓存机制:实现广告缓存,提高展示速度
- 交替布局:为不同广告创建多种布局
- 性能优化:避免过度渲染和内存泄漏
3. 避免的问题
- 不要隐藏广告标识
- 不要修改广告内容
- 不要干扰广告的正常展示
- 不要在广告中添加无关内容
常见问题
Q: 原生广告为什么不显示?
A: 可能的原因:
- 广告单元 ID 不正确
- 网络连接问题
- 广告库存不足
- 布局问题(容器不可见或尺寸为 0)
- 渲染代码有问题
Q: 如何提高原生广告的效果?
A: 建议:
- 精心设计广告布局
- 确保广告与应用内容相关
- 优化广告加载和渲染
- 测试不同的广告位置
- 分析广告效果数据
Q: 原生广告可以在 RecyclerView 中使用吗?
A: 可以,实现方法:
- 在 ViewHolder 中管理原生广告
- 为广告项创建专门的布局
- 正确处理广告的加载和渲染
- 避免频繁创建和销毁广告
