原生广告
在 iOS 自定义布局中加载和渲染 CloudX 原生广告
原生广告会公开标题、正文、图标、媒体和行动号召等独立素材,让您能够按照应用的视觉风格进行布局。CloudX 会填充已绑定的视图,并由中标网络的适配器处理展示和点击跟踪。
集成分为三个步骤:
- 绑定布局中的 UI 组件。
- 创建加载器,然后加载或渲染原生广告。
- 不再需要广告和加载器时将其销毁。
支持的网络
各网络的 Native 支持情况(包括 Native Banner 和 Native MREC 变体)以 Native 广告格式矩阵为准。各适配器的依赖和设置说明记录在对应的适配器概览页中。
1. 绑定 UI 组件
使用视图绑定器创建 CLXNativeAdView,将您的自定义子视图映射到各素材角色。网络可能不会返回所有可选素材,因此布局应能够收起或隐藏没有内容的视图。
选项容器是必需的:CloudX 通过它显示网络提供的 AdChoices 或隐私控制。
- (CLXNativeAdView *)createNativeAdView {
CLXNativeAdViewBinder *binder = [[CLXNativeAdViewBinder alloc] initWithBuilderBlock:^(CLXNativeAdViewBinderBuilder *builder) {
builder.titleLabelTag = CLXNativeAdViewTagTitleLabel;
builder.bodyLabelTag = CLXNativeAdViewTagBodyLabel;
builder.iconImageViewTag = CLXNativeAdViewTagIconImageView;
builder.callToActionButtonTag = CLXNativeAdViewTagCallToActionButton;
builder.mediaContentViewTag = CLXNativeAdViewTagMediaViewContainer;
builder.optionsContentViewTag = CLXNativeAdViewTagOptionsContentView;
builder.advertiserLabelTag = CLXNativeAdViewTagAdvertiserLabel;
builder.starRatingContentViewTag = CLXNativeAdViewTagStarRatingContentView;
}];
CLXNativeAdView *adView = [[CLXNativeAdView alloc] init];
[adView bindViewsWithViewBinder:binder];
return adView;
}func createNativeAdView() -> CLXNativeAdView {
let binder = CLXNativeAdViewBinder { builder in
builder.titleLabelTag = CLXNativeAdViewTagTitleLabel
builder.bodyLabelTag = CLXNativeAdViewTagBodyLabel
builder.iconImageViewTag = CLXNativeAdViewTagIconImageView
builder.callToActionButtonTag = CLXNativeAdViewTagCallToActionButton
builder.mediaContentViewTag = CLXNativeAdViewTagMediaViewContainer
builder.optionsContentViewTag = CLXNativeAdViewTagOptionsContentView
builder.advertiserLabelTag = CLXNativeAdViewTagAdvertiserLabel
builder.starRatingContentViewTag = CLXNativeAdViewTagStarRatingContentView
}
let adView = CLXNativeAdView()
adView.bindViews(with: binder)
return adView
}也可以直接在 CLXNativeAdView 上设置各出口(outlet):
CLXNativeAdView *adView = [[CLXNativeAdView alloc] init];
adView.titleLabel = myTitleLabel;
adView.bodyLabel = myBodyLabel;
adView.iconImageView = myIconImageView;
adView.callToActionButton = myCTAButton;
adView.mediaContentView = myMediaContainer;
adView.optionsContentView = myOptionsContainer;
adView.advertiserLabel = myAdvertiserLabel;let adView = CLXNativeAdView()
adView.titleLabel = myTitleLabel
adView.bodyLabel = myBodyLabel
adView.iconImageView = myIconImageView
adView.callToActionButton = myCTAButton
adView.mediaContentView = myMediaContainer
adView.optionsContentView = myOptionsContainer
adView.advertiserLabel = myAdvertiserLabel星级评分
只有当网络提供的评分不低于 3.0 时,CloudX 才会填充星级评分容器;否则容器保持为空。请确保布局在星级评分容器为空时能够收起或隐藏。
2. 创建加载器
@interface YourViewController () <CLXNativeAdDelegate, CLXAdRevenueDelegate>
@property (nonatomic, strong) CLXNativeAdLoader *nativeAdLoader;
@end
@implementation YourViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.nativeAdLoader = [[CloudXCore shared] createNativeAdLoaderWithAdUnitIdentifier:@"your-native-ad-unit-id"];
self.nativeAdLoader.nativeAdDelegate = self;
self.nativeAdLoader.revenueDelegate = self;
}
- (void)dealloc {
[self.nativeAdLoader destroy];
}
@endclass YourViewController: UIViewController, CLXNativeAdDelegate, CLXAdRevenueDelegate {
private var nativeAdLoader: CLXNativeAdLoader?
override func viewDidLoad() {
super.viewDidLoad()
nativeAdLoader = CloudXCore.shared.createNativeAdLoader(adUnitIdentifier: "your-native-ad-unit-id")
nativeAdLoader?.nativeAdDelegate = self
nativeAdLoader?.revenueDelegate = self
}
deinit {
nativeAdLoader?.destroy()
}
}加载广告
请选择一种加载流程。
加载到预构建视图
目标视图已经存在时使用此流程。CloudX 会先填充并注册视图,然后通过 didLoadNativeAd 返回该视图。
CLXNativeAdView *adView = [self createNativeAdView];
[self.nativeAdLoader loadAdIntoAdView:adView];let adView = createNativeAdView()
nativeAdLoader?.loadAd(into: adView)分别加载和渲染
如果希望在目标视图创建前预先加载广告,请使用延迟渲染。在将视图添加到视图层级之前调用 renderNativeAdView(...)。
[self.nativeAdLoader loadAd];
- (void)didLoadNativeAd:(nullable CLXNativeAdView *)nativeAdView forAd:(CLXAd *)ad {
CLXNativeAdView *adView = /* create your ad view */;
[self.nativeAdLoader renderNativeAdView:adView withAd:ad];
[self.view addSubview:adView];
}nativeAdLoader?.loadAd()
func didLoadNativeAd(_ nativeAdView: CLXNativeAdView?, for ad: CLXAd) {
let adView = /* create your ad view */
nativeAdLoader?.renderNativeAdView(adView, with: ad)
view.addSubview(adView)
}处理回调
已加载的原生广告会在加载后一小时过期;届时会触发 didExpireNativeAd,您可以销毁过期广告并加载新广告。在 didFailToLoadNativeAd 中,请避免立即循环重试——应延迟一段时间或在下一个自然展示时机重试。
#pragma mark - CLXNativeAdDelegate (Required)
- (void)didLoadNativeAd:(nullable CLXNativeAdView *)nativeAdView forAd:(CLXAd *)ad {
NSLog(@"Native ad loaded from %@", ad.networkName);
if (ad.nativeAd.isVideoContent) {
NSLog(@"Video duration: %.1fs", ad.nativeAd.videoDuration);
}
if (nativeAdView) {
[self.view addSubview:nativeAdView];
}
}
- (void)didFailToLoadNativeAdForAdUnitIdentifier:(NSString *)adUnitId error:(CLXError *)error {
NSLog(@"Native ad failed to load: %@", error.localizedDescription);
}
- (void)didClickNativeAd:(CLXAd *)ad {
NSLog(@"Native ad clicked");
}
#pragma mark - CLXNativeAdDelegate (Optional)
- (void)didExpireNativeAd:(CLXAd *)ad {
NSLog(@"Native ad expired — destroy and reload");
[self.nativeAdLoader destroyAd:ad];
[self.nativeAdLoader loadAd];
}
- (void)didCloseNativeAd:(CLXAd *)ad {
NSLog(@"User dismissed the ad via AdChoices");
[self.nativeAdLoader destroyAd:ad];
}
#pragma mark - CLXAdRevenueDelegate
- (void)didPayRevenueForAd:(CLXAd *)ad {
NSLog(@"Native ad revenue: %@ from %@", ad.revenue, ad.networkName);
}// MARK: - CLXNativeAdDelegate (Required)
func didLoadNativeAd(_ nativeAdView: CLXNativeAdView?, for ad: CLXAd) {
print("Native ad loaded from \(ad.networkName ?? "unknown")")
if let nativeAd = ad.nativeAd, nativeAd.isVideoContent {
print("Video duration: \(nativeAd.videoDuration)s")
}
if let nativeAdView = nativeAdView {
view.addSubview(nativeAdView)
}
}
func didFailToLoadNativeAd(forAdUnitIdentifier adUnitId: String, error: CLXError) {
print("Native ad failed to load: \(error.localizedDescription)")
}
func didClickNativeAd(_ ad: CLXAd) {
print("Native ad clicked")
}
// MARK: - CLXNativeAdDelegate (Optional)
func didExpireNativeAd(_ ad: CLXAd) {
print("Native ad expired — destroy and reload")
nativeAdLoader?.destroyAd(ad)
nativeAdLoader?.loadAd()
}
func didCloseNativeAd(_ ad: CLXAd) {
print("User dismissed the ad via AdChoices")
nativeAdLoader?.destroyAd(ad)
}
// MARK: - CLXAdRevenueDelegate
func didPayRevenue(for ad: CLXAd) {
print("Native ad revenue: \(ad.revenue ?? 0) from \(ad.networkName ?? "unknown")")
}3. 销毁原生广告
广告被替换或过期时销毁单个广告;所属页面或组件结束时销毁加载器。这样可以释放网络媒体视图,防止资源随时间不断累积。
// Destroy a specific loaded ad
[self.nativeAdLoader destroyAd:ad];
// Destroy the loader and all associated resources
[self.nativeAdLoader destroy];// Destroy a specific loaded ad
nativeAdLoader?.destroyAd(ad)
// Destroy the loader and all associated resources
nativeAdLoader?.destroy()原生广告素材
CLXNativeAd 对象可通过代理回调中的 ad.nativeAd 获取:
| 属性 | 类型 | 描述 |
|---|---|---|
title | NSString? | 标题文本 |
body | NSString? | 正文/描述文本 |
callToAction | NSString? | CTA 按钮文本(如 “Install Now”) |
advertiser | NSString? | 广告主名称 |
icon | CLXNativeAdImage? | 应用图标图片 |
mainImage | CLXNativeAdImage? | 主图(静态素材) |
mediaView | UIView? | 视频/媒体播放器视图(由适配器提供) |
optionsView | UIView? | AdChoices 或选项视图(由适配器提供) |
mediaContentAspectRatio | CGFloat | 媒体内容的宽高比 |
starRating | NSNumber? | 应用商店评分(0–5) |
isVideoContent | BOOL | 素材是否为视频 |
videoDuration | NSTimeInterval | 视频时长(秒),未知时为 0 |
expired | BOOL | 广告是否已过期 |
不同网络和素材返回的资源可能不同。请将可空值视为可选值,并在素材不可用时隐藏对应 UI。mediaContentAspectRatio 或 videoDuration 为 0 表示网络尚未提供可用值。
原生视频元数据
使用 isVideoContent 区分视频和静态原生素材。当其值为 true 时,如果网络已提供时长,videoDuration 会返回以秒为单位的视频时长。渲染完成后查询时长可获得最准确的值。