iOS 原生广告集成
概述
原生广告采用自渲染模式:开发者自行绘制广告视图,通过 NativeAdViewBinder 绑定视图、NativeAdData 填充物料。
iOS 与 Android 的差异
iOS 自渲染采用 view.tag 模式标识组件(替代 Android 的 R.id 资源 ID)。通过为每个子视图设置唯一 tag,再在 NativeAdViewBinder 中传入对应 tag 完成绑定。
集成步骤
1. 创建并加载原生广告
swift
import UIKit
import UjuAdCore
final class NativeAdHelper {
private var nativeAd: UjuAdObject?
func load(vc: UIViewController, container: UIView) {
let config = UjuAdConfig(
placementId: "YOUR_NATIVE_PLACEMENT_ID",
adViewSize: AdViewSize.nativeSize690x388 // 信息流卡片尺寸
)
let native = UjuAdObject.getNativeObject(vc, config: config)
native.setAdObjectListener(NativeListener(helper: self, container: container, vc: vc))
self.nativeAd = native
native.load()
}
func destroy() {
nativeAd?.destroy()
nativeAd = nil
}
}2. 实现原生监听器并渲染
swift
final class NativeListener: FeedAdObjectListener, @unchecked Sendable {
private weak var helper: NativeAdHelper?
private weak var container: UIView?
private weak var vc: UIViewController?
init(helper: NativeAdHelper, container: UIView, vc: UIViewController) {
self.helper = helper
self.container = container
self.vc = vc
}
func onLoadSuccess() {
guard let nativeAd = helper?.nativeAd, let vc = vc, let container = container else { return }
// 自渲染:获取物料数据并绑定视图
renderNativeAd(ad: nativeAd, vc: vc, container: container)
}
func onLoadError(error: UjuException) {
print("原生广告加载失败: \(error.description)")
}
func onAdShow() {}
func onAdClicked() {}
func onAdClosed() {}
func onLpClosed() {}
func onAdError(error: UjuException) {
print("原生广告展示错误: \(error.description)")
}
private func renderNativeAd(ad: UjuAdObject, vc: UIViewController, container: UIView) {
// 详见下方「自渲染示例」
}
}自渲染示例
swift
private func renderNativeAd(ad: UjuAdObject, vc: UIViewController, container: UIView) {
// 1. 获取物料数据
guard let data = ad.getAdData() else { return }
// 2. 创建视图,并为每个子视图设置唯一 tag
let adView = UIView()
let titleLabel = UILabel()
titleLabel.tag = 101
let descLabel = UILabel()
descLabel.tag = 102
let iconImageView = UIImageView()
iconImageView.tag = 103
let mainImageView = UIImageView()
mainImageView.tag = 104
let ctaButton = UIButton(type: .system)
ctaButton.tag = 105
adView.addSubview(titleLabel)
adView.addSubview(descLabel)
adView.addSubview(iconImageView)
adView.addSubview(mainImageView)
adView.addSubview(ctaButton)
// ... 设置 Auto Layout 约束 ...
// 3. 构造 binder(view.tag 模式,仅 titleTag 必填,其余默认 0 表示不绑定)
let binder = NativeAdViewBinder(
titleTag: 101,
descTag: 102,
sourceTag: 0, // 0 表示不绑定来源
imageTag: 104, // 主图
mediaViewTag: 0, // 视频物料时绑定
iconTag: 103, // 图标
callToActionTag: 105,
logoTag: 0,
clickViewTags: [104], // 主图可点击
dislikeTag: 0
)
// 4. 注册视图用于交互(SDK 会自动填充数据 + 绑定点击手势)
ad.registerViewForInteraction(vc: vc, adView: adView, container: container, binder: binder)
ad.show(vc, container: container)
}NativeAdData 字段
UjuAdObject.getAdData() 返回 NativeAdData?,用于自渲染填充数据,所有字段均为可选:
| 字段 | 类型 | 说明 |
|---|---|---|
title | String? | 广告标题 |
desc | String? | 广告描述 |
source | String? | 广告来源 |
callToAction | String? | 行动号召文案(如「立即下载」) |
imageUrl | String? | 单图 URL |
imageUrlList | [String]? | 多图 URL 列表(>1 张时) |
iconUrl | String? | 图标 URL |
如需自行处理数据(不使用 binder 模式):
swift
if let data = ad.getAdData() {
print("title: \(data.title ?? "")")
print("icon: \(data.iconUrl ?? "")")
// 自行下载图片并渲染
}NativeAdViewBinder 字段
NativeAdViewBinder 用于自渲染绑定视图,采用 view.tag 模式。仅 titleTag 必填,其余字段默认 0(或空数组)表示不绑定:
| 字段 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
titleTag | Int | 是 | — | 标题视图 tag |
descTag | Int | 否 | 0 | 描述视图 tag |
sourceTag | Int | 否 | 0 | 来源视图 tag |
imageTag | Int | 否 | 0 | 主图视图 tag |
mediaViewTag | Int | 否 | 0 | 媒体视图 tag(视频广告) |
iconTag | Int | 否 | 0 | 图标视图 tag |
callToActionTag | Int | 否 | 0 | 行动号召按钮 tag |
logoTag | Int | 否 | 0 | 广告标识 tag |
clickViewTags | [Int] | 否 | [] | 额外可点击视图 tag 列表 |
dislikeTag | Int | 否 | 0 | 不感兴趣按钮 tag |
最佳实践
- tag 唯一性:自渲染时确保每个子视图
tag在 adView 范围内唯一,避免与系统 tag 冲突 - 空指针保护:
NativeAdData字段均为可选,使用前做?? ""兜底 - 资源释放:cell 复用或视图移除时调用
destroy() - 图片加载:自行下载
imageUrl/iconUrl,建议使用 SDWebImage / Kingfisher 等库
常见问题
Q: 自渲染视图为什么不显示数据?
A: 可能的原因:
NativeAdViewBinder中tag与视图实际tag不匹配- 未调用
registerViewForInteraction(vc:adView:container:binder:)注册交互 - 容器视图尺寸为 0 或未加入视图层级
getAdData()返回 nil(非 native 类型调用)
