原生广告
一、注意事项
- 在请求广告时传入UIContext
- 禁止在
onAdLoadFail
回调中执行广告加载的方法,否则会引起死循环。 - 禁止在
onAdLoaded
回调中直接执行广告展示的方法。SDK有广告 过期自动补充功能。如果在onAdLoaded
回调中执行show()
,开发者会无法精准控制告展示的时机。
二、加载广告
- 创建广告位对象
let tpNative = new TPNative()
- 设置请求广告位ID
this.tpNative?.setAdUnitID("在TradPlus后台创建的原生广告位ID")
- 设置请求监听
let loadListener:TPNativeLoadListener = {
onAdLoaded: (adInfo: TPAdInfo): void => {
// 请求一次广告,有广告加载成功,一轮请求只会返回一次
},
onAdLoadFail: (adInfo: TPAdInfo, error: Error): void => {
// 请求一次广告,所有广告加载失败,一轮请求只会返回一次
},
onAdStartLoad: (adInfo: TPAdInfo): void => {
// 广告开始加载
},
onAdOneLayerStartLoad: (adInfo: TPAdInfo): void => {
// 每层广告开始加载
},
onAdBidStart: (adInfo: TPAdInfo): void => {
// Bidding开始
},
onAdBidEnd: (adInfo: TPAdInfo, error?: Error | undefined): void => {
// Bidding结束,error == undefined表示Bidding成功,有error表示Bidding失败
},
onAdOneLayerLoaded: (adInfo: TPAdInfo): void => {
// 单层广告加载成功
},
onAdOneLayerLoadFail: (adInfo: TPAdInfo, error: Error): void => {
// 单层广告加载 加载失败
},
onAdAllLoaded: (adInfo: TPAdInfo, success: boolean): void => {
// 请求一次广告,一轮结束会收到一次回调,success true表示有广告加载成功,false表示所有广告加载失败
},
onAdIsLoading: (adInfo: TPAdInfo): void => {
// 一轮请求还没有结束,又发起了一轮请求
},
}
this.tpNative?.loadListener = loadListener
- 请求广告
this.tpNative?.load(uiContext)
三、展示广告
- 广告是否加载成功:收到onAdLoaded回调,或者通过
isReady()
方法检查
let isReady = await this.tpNative?.isReady()
- 设置展示监听
let showListener:TPNativeShowListener = {
onAdImpression: (adInfo: TPAdInfo): void => {
// 展示成功
},
onAdShowFailed: (adInfo: TPAdInfo): void => {
// 展示失败
},
onAdClosed: (adInfo: TPAdInfo): void => {
// 广告关闭
},
onAdClicked: (adInfo: TPAdInfo): void => {
// 用户触发点击
}
}
this.tpNative?.showListener = showListener
- 展示
详细代码见Demo的NativePage相关Class
- 创建Class
TPNodeController
继承并实现NodeController
实现流程可以参考鸿蒙官方文档: https://developer.huawei.com/consumer/cn/doc/best-practices/bpta-ui-dynamic-operations#section153921947151012
let tpNodeController = new TPNodeController()
- 通过tpNative获取自渲染类型素材对象TPNativeView
const tpNativeView = await this.tpNative?.getTPNativeAd()
- 将tpNative和tpNativeView传给TPNodeController,用于添加组件和注册监听
this.tpNodeController?.show(this.getUIContext(),this.tpNative,this.tpNativeView)
- TPNodeController中构建广告组件,在封装的广告组件AdComponent中绘制布局并注册监听
//点击Id集合,缺少注册将无法点击
@State private clickViewIds: TPNativeArrayList<string> = new TPNativeArrayList();
// 广告布局根节点Id
private rootComponentId: string = util.generateRandomUUID()
build() {
Column() {
Row() {
Row() {
// icon
Image(this.tpNativeView?.iconImageUrl)
.height(32)
.width(32)
.borderRadius(5)
.margin({ right: 5 })
.id(this.clickViewIds?.addAdId(util.generateRandomUUID()))//设置组件Id,需要全局保证唯一性,涉及计费
.onClick((e: ClickEvent) => {
// 点击转化
this.tpNative?.getClickHandler(getContext(this) as common.UIAbilityContext, e)
})
// 描述内容
Text(this.tpNativeView!.subTitle)
.fontSize(12)
.textAlign(TextAlign.Start)
.maxLines(2)
.textOverflow({ overflow: TextOverflow.Ellipsis })
.id(this.clickViewIds?.addAdId(util.generateRandomUUID()))//设置组件Id,需要全局保证唯一性,涉及计费
.onClick((e: ClickEvent) => {
// 点击转化
this.tpNative?.getClickHandler(getContext(this) as common.UIAbilityContext, e)
})
}
.height(35)
.width("85%")
.justifyContent(FlexAlign.Start);
}
.justifyContent(FlexAlign.SpaceBetween)
.height(35)
.width("100%")
.padding({ left: 10, right: 10, bottom: 4 })
Stack({ alignContent: Alignment.BottomStart }) {
if (this.tpNativeView?.mainImageUrl) {
// 大图是图片
this.buildImageLayout()
} else {
// 大图是视频
NodeContainer(this.tpNativeView?.videoNodeController)
}
}.height(200)
Row() {
// 标题
Text(this.tpNativeView?.title)
.fontSize(12)
.textAlign(TextAlign.Center)
.id(this.clickViewIds?.addAdId(util.generateRandomUUID()))//设置组件Id,需要全局保证唯一性,涉及计费
.onClick((e: ClickEvent) => {
// 点击转化
this.tpNative?.getClickHandler(getContext(this) as common.UIAbilityContext, e)
})
// CTA
Button(this.tpNativeView?.callToAction, { type: ButtonType.Normal })
.fontSize(12)
.borderRadius(5)
.id(this.clickViewIds?.addAdId(util.generateRandomUUID()))//设置组件Id,需要全局保证唯一性,涉及计费
.onClick((e: ClickEvent) => {
// 点击转化
this.tpNative?.getClickHandler(getContext(this) as common.UIAbilityContext, e)
})
}
.justifyContent(FlexAlign.SpaceBetween)
.height(35)
.width("100%")
.padding({
top: 5,
bottom: 5,
left: 10,
right: 10
})
}
.backgroundColor("#08000000")
.id(this.rootComponentId) //设置广告容器组件rootId
.onAppear(() => {
// 注册计费事件
this.tpNative?.registerClickView(this.rootComponentId, getContext(this) as common.UIAbilityContext,
this.clickViewIds)
})
// 添加可见区域监听,SDK内部处理曝光逻辑
.onVisibleAreaChange(this.tpNative?.getVisibleAreaRatios(), this.tpNative?.getVisibleAreaChangeListener())
}
@Builder
// 图片类型的广告布局
buildImageLayout() {
Image(this.tpNativeView?.mainImageUrl)
.objectFit(ImageFit.Cover)
.id(this.clickViewIds?.addAdId(util.generateRandomUUID()))//设置组件Id,需要全局保证唯一性,涉及计费
.onClick((e: ClickEvent) => {
// 点击转化
this.tpNative?.getClickHandler(getContext(this) as common.UIAbilityContext, e)
})
}
- 通过NodeContainer容器承载TPNodeController进行广告的展示
NodeContainer(this.tpNodeController)