原生广告(模板\自渲染)包含模板和自渲染两种形式的广告,开发者集成的时候根据业务需求决定用模板还是自渲染形式广告,多用于新闻信息流中,位于app顶部、中部、底部任意一处,横向贯穿整个app页面。
原生(模板\自渲染),同原生(模板)接口入口都是AMPSNativeAd。
class AMPSNativeAd {
/**
* uiContext:当前组件的uiContext
* config: 请求参数
* nativeAdCallBack:广告请求回调
* @param uiContext
* @param config
* @param nativeAdCallBack
*/
constructor(uiContext: UIContext, config: ampsAd.AdOptions, nativeAdCallBack: AMPSNativeAdListener);
/**
* 请求原生(模板\自渲染)广告
*/
load(): void;
}
作为加载广告的回调结果,loadOk中拿到请求结果。loadFail中返回失败的相关信息。
export interface AMPSNativeAdListener {
loadOk: (adItems: Array<AMPSNativeAdWrapper>) => void;
loadFail: (code: number, message: string) => void;
}
作为广告的数据包装器,AMPSNativeAdWrapper提供了所需的数据和相关回调和接口。
export declare class AMPSNativeAdWrapper {
//对应的广告ID
readonly adId: string;
//内部模板渲染相关的回调
renderCallBack?: AMPSNativeRenderListener;
//点击、显示、曝光、关闭等显示
interactCallBack?: AMPSNativeInteractiveListener;
//视频相关回调
videoPlayCallBack?: AMPSVideoPlayListener;
constructor(asnpNativeAdWrapper?: ASNPNativeAdWrapper);
setVideoPlayConfig(playConfig: AMPSAdVideoPlayConfig): void | undefined;
//判断是否是模板渲染,false表示自渲染,true表示模板渲染
isNativeExpress(): boolean;
//设置视频状态相关监听
setVideoPlayListener(videoPlayListener: AMPSVideoPlayListener): void;
//获取视频时长
getVideoDuration(): number;
//获取竞价
getECPM(): number;
//竞胜上报
notifyRTBWin(winPrice: number, secPrice: number): void;
//竞败上报
notifyRTBLoss(winPrice: number, secPrice: number, lossReason: string): void
//开始渲染接口
renderAd(): void;
//获取广告来源
getAdSource(): string | undefined;
//获取标题
getTitle(): string | undefined;
//获取描述
getDescription(): string | undefined;
//获取
getIntroductionInfo(): string | undefined;
//获取简介信息
getIntroductionInfoUrl(): string | undefined;
//获取icon地址
getIconUrl(): string | undefined;
//获取主图地址
getMainImageUrl(): string | undefined;
//获取主题宽度
getMainImageWidth(): number | undefined;
//获取主图高度
getMainImageHeight(): number | undefined;
//获取图片列表
getImgList(): Array<AMPSAdImage>;
//获取主图
getMainImage(): AMPSAdImage | undefined;
//获取Action文本
getActionText(): string | undefined;
//获取Logo地址
getLogoUrl(isGrey?: boolean): ResourceStr | undefined;
//获取视频地址
getVideoUrl(): string | undefined;
//获取视频封面
getVideoCoverImage(): AMPSAdImage | undefined;
//获取素材类型
getMaterialType(): AMPSMaterialType | undefined;
//获取下载信息
getDownloadInfo(): IUnifiedDownloadInfo | undefined;
//用于三方【快手】等设置
getVisibleAreaRatios(): number[] | undefined;
//用于三方【快手】等设置
getVisibleAreaChangeListener(): ((isVisible: boolean, currentRatio: number) => void) | undefined;
//点击回调给SDK内部
getClickHandler(): (context: common.UIAbilityContext, event: ClickEvent, actionType?: AMPSAdItemClickType) => void;
//给SDK内部传入绑定的id和容器组件Id
prepare(rootAdComponentId: string, uiContext: UIContext, clickViewIds: AMPSArrayList<string>,
creativeViewIds: AMPSArrayList<string>): void;
}
广告加载成功之后,在loadOk中返回广告相关的数据AMPSNativeAdWrapper,可以通过给AMPSNativeAdWrapper设置AMPSNativeInteractiveListener监听广告点击、关闭、显示、曝光相关信息。
export interface AMPSNativeInteractiveListener {
onAdShown: (adId?: string) => void;
onAdExposure: (adId?: string) => void;
onAdClicked: (adId?: string) => void;
toCloseAd: (adId?: string) => void;
}
新原生(模板/自渲染)可能自渲染同时有模板,所以,需要开发者主动调用renderAd可从AMPSNativeRenderListener接口回调渲染是否成功、失败信息。
export interface AMPSNativeRenderListener {
renderSuccess: (adWrapper: AMPSNativeAdWrapper) => void;
renderFailed: (adWrapper: AMPSNativeAdWrapper) => void;
}
import {
AMPSAdItemClickType,
ampsAd,
AMPSAdVideoPlayConfigBuilder,
AMPSArrayList,
AMPSMaterialType,
AMPSNativeAd,
AMPSNativeAdListener,
AMPSNativeAdWrapper,
AMPSNativeContainer,
AMPSNativeInteractiveListener,
AMPSVideoAutoPlayType,
AMPSNativeRenderListener
} from 'biz.beizi.adn';
import { promptAction } from '@kit.ArkUI';
import { util } from '@kit.ArkTS';
import { AMPSBuildNativeAdVideoView } from 'biz.beizi.adn';
import { common } from '@kit.AbilityKit';
import { AdItem, Item } from '../model/Item';
const TAG: string = "NativeAdPage"
@Entry
@Component
struct NativeAdPage {
private clickIds = new AMPSArrayList<string>();
private rootComponentId: string = util.generateRandomUUID();
@State message: string = 'Hello World';
//制造假数据
arr: string[] = ["aaaaaaaaaaa", "bbbbbbbbb", "ccccccccc",
"dddddddd", "eeeeeeeee", "aaaaaaaaaaa111", "bbbbbbbbb222", "ccccccccc333",
"dddddddd444", "eeeeeeeee555"]
@State adItems: Item[] = []
@State listHeight: number = 120
@State heightMap: Map<string, number> = new Map()
mInterCallback: AMPSNativeInteractiveListener = {//广告相关回调【关闭,点击,显示,曝光】
onAdClicked: (adId?: string): void => {
console.log("客户端onAdClicked");
},
toCloseAd: (bidId?: string): void => {//关闭删除广告组件Item
let index = -1;
for (let i = 0; i < this.adItems.length; i++) {
if (!(this.adItems[i] instanceof AdItem)) {
continue;
}
let ad = this.adItems[i] as AdItem;
if (ad.wrapper.adId == bidId) {
index = i;
}
}
if (index >= 0) {
this.adItems.splice(index, 1);
}
},
onAdShown: (adId?: string): void => {
},
onAdExposure: (adId?: string): void => {
}
}
mRenderCallBack:AMPSNativeRenderListener = {//渲染是否完成回调
renderSuccess: (adWrapper: AMPSNativeAdWrapper): void => {
//渲染完成,插入广告数据到列表,并显示
let ad = new AdItem(adWrapper)
this.adItems.splice(2, 0, ad)
},
renderFailed: (adWrapper: AMPSNativeAdWrapper): void => {
}
}
private callback: AMPSNativeAdListener = {//广告加载回调
loadOk: (adItems: AMPSNativeAdWrapper[]): void => {
for (let adItemsElement of adItems) {
adItemsElement.interactCallBack = this.mInterCallback
adItemsElement.renderCallBack = this.mRenderCallBack
adItemsElement.setVideoPlayConfig(new AMPSAdVideoPlayConfigBuilder()
.videoSoundEnable(true)
.videoAutoPlayType(AMPSVideoAutoPlayType.AUTO_PLAY)
.videoLoopReplay(true)
.build())
adItemsElement.setVideoPlayListener({
onVideoReady: () => {
console.error("video::时长===" + adItemsElement.getVideoDuration())
},
onVideoPlayStart: () => {
console.error("video::播放了?")
},
onVideoPause: () => {
console.error("video::播放暂停了?")
},
onVideoResume: () => {
console.error("video::暂停到播放?")
},
onVideoPlayComplete: () => {
console.error("video::播放完成了?")
},
onVideoPlayError: (code, extra) => {
console.error("video::错误?")
}
})
//需要注意,renderAd才会触发模板渲染回调结果。避免
adItemsElement.renderAd()
}
},
loadFail: (code: number, message: string): void => {
promptAction.showToast({
message
})
}
}
ad?: AMPSNativeAd
aboutToAppear(): void {
for (let i = 0; i < this.arr.length; i++) {
let o = new Item()
o.index = i
o.message = this.arr[i]
this.adItems.push(o)
}
let option: ampsAd.AdOptions = {
spaceId:'118007'//需要SDK方配置可用的测试spaceId
}
//SDK外部调用加载广告
this.ad = new AMPSNativeAd(this.getUIContext(), option, this.callback)
this.ad.load()
}
aboutToDisappear(): void {
}
//自渲染开发者自定义广告显示样式
@Builder
buildASNPBody(wrapper: AMPSNativeAdWrapper) {
Column() {
Row() {
if (wrapper.getTitle()) {
Text(wrapper.getTitle())
.fontSize(18)
.fontColor(Color.Black)
.fontWeight(FontWeight.Bold)
.textShadow({
radius: 4,
offsetY: 2,
offsetX: 2,
color: Color.Gray
})
.padding(5)
.textAlign(TextAlign.Start)
.id(this.clickIds.addAdId(util.generateRandomUUID()))//设置组件Id,需要全局保证唯一性,涉及计费
}
Text(wrapper.getTitle()).fontColor(Color.Green).fontSize(22).margin({ left: 20, right: 20 }).layoutWeight(1)
Image(wrapper.getLogoUrl()).width(25).height(14).margin({ right: 10 })
}.width('100%')
if (wrapper.getMaterialType() === AMPSMaterialType.SINGLE_IMG) {
Image(wrapper.getMainImageUrl())
.width('100%')
.height(200)
} else if (wrapper.getMaterialType() === AMPSMaterialType.GROUP_IMG) {
ForEach(wrapper.getImgList(), () => {
Image(wrapper.getMainImageUrl())
.width('100%')
.height(200)
})
} else {
Stack() {
if (wrapper.getMainImageUrl()) {
Image(wrapper.getMainImageUrl())
.width('100%')
.height(200)
}
if (wrapper.getVideoUrl()) {
// 展示视频
Column() {
AMPSBuildNativeAdVideoView(wrapper)
}.width(200).height('100%')
}
}.width('100%')
.height(200)
}
if (wrapper.getDescription()) {
Row() {
Text(wrapper.getDescription())
.width('100%')
.layoutWeight(1)
.fontSize(14)
.fontColor(Color.White)
.textAlign(TextAlign.Start)
.padding(5)
.textShadow({ radius: 2, offsetY: 2, color: Color.Black })
if (wrapper.getActionText()) {
Button(wrapper.getActionText())
.type(ButtonType.Normal)
.height(20)
.backgroundColor('#fffa97fa')
.fontColor(Color.White)
.fontSize(12)
.border({ radius: 5, color: Color.White, width: 1 })
.shadow({ radius: 5, color: '#fffa97fa', offsetY: 3 })
.padding({
left: 5,
right: 5,
top: 1,
bottom: 1
})
.margin({ right: 10, bottom: 5, top: 5 })
.id(this.clickIds.addAdId(util.generateRandomUUID()))//设置组件Id,需要全局保证唯一性,涉及计费
.onClick((e) => {
wrapper?.getClickHandler()(getContext(this) as common.UIAbilityContext, e,AMPSAdItemClickType.COMPLAIN)
})
}
}
}
}.margin(10).shadow({ radius: 10, color: Color.Black, offsetY: 5 }).borderRadius(10)
}
build() {
Row() {
Column() {
Row() {
List() {
ForEach(this.adItems, (item: Item, index) => {
ListItem() {
Column() {
if (item instanceof AdItem && !item.wrapper.isNativeExpress()) {
AMPSNativeContainer({
mNativeWrapper: item.wrapper,
buildContent: () => {
this.buildASNPBody(item.wrapper)
}
}).id(this.rootComponentId).onAppear(() => {
//需要传入根id和设置了点击事件的id
item.wrapper.prepare(
this.rootComponentId,
this.getUIContext(), this.clickIds,
new AMPSArrayList<string>())
})
} else {
Text(`第${item.index + 1}条=${item.message}`)
.height("120")
.width("100%")
.backgroundColor(Color.Blue)
.margin(10)
.textAlign(TextAlign.Center)
}
}.width("100%")
}
})
}.width("100%")
.height("100%")
}.width("100%")
}.width('100%').height("100%")
}
}
}
开发者自定义自渲染组件,需要设置点击跳转、关闭、投诉的按钮,跳转 需要绑定唯一ID,并添加到AMPSArrayList数组中,通过wrapper.prepare传入。对于自渲染容器AMPSNativeContainer在其onAppear回调触发之后传入。否则不能点击转化。关键代码如下:
//判断是广告数据类型且是非模板类型
if (item instanceof AdItem && !item.wrapper.isNativeExpress()) {
AMPSNativeContainer({
mNativeWrapper: item.wrapper,
buildContent: () => {
this.buildBody(item.wrapper)
}
}).id(this.rootComponentId).onAppear(() => {
//需要传入根id和设置了点击事件的id
item.wrapper.prepare(
this.rootComponentId,
this.getUIContext(), this.clickIds,
new AMPSArrayList<string>())
})
}