Skip to content

原生广告(模版\自渲染\draw)

1、场景介绍

原生广告是与应用内容融于一体的广告,通过“和谐”的内容呈现广告信息,在不破坏用户体验的前提下,为用户提供有价值的信息,展示形式包含图片和视频,支持您自由定制界面。

信息流广告分为自渲染广告和模板广告,但是模板广告只有当三方SDK支持时才会返回模板广告。

  • 自渲染广告:聚合SDK返回物料,由开发者在TBNativeAdComponent组件上进行子视图的自行渲染和展示。
  • 模版渲染广告:聚合SDK直接返回渲染好的广告组件TBNativeAdComponent,开发者直接展示即可。

2、广告加载类TBNativeAdLoader

在SDK里只需要使用 TBNativeAdLoader 就可以获取信息流广告。TBNativeAdLoader支持多广告加载,可以一次加载返回多个广告。

注意:adHeight高度为0时,广告的实际高度由模版广告自行渲染决定

typescript
export class TBNativeAdLoader {
  /**
   * 广告请求信息
   */  
  readonly request: TBType.AdRequest;

  /**
   * 构造函数
   */  
  constructor(request: TBType.AdRequest);

  /**
   * 设置广告加载监听器
   */
  set adLoadListener(listener: TBNativeAdLoaderListener);

  /**
   * 返回广告缓存池内所有信息
   * 填充后可调用, 广告关闭后清理
   * @returns
   */
  getCacheAdInfoList(): TBAdInfo[];

  /**
   * 加载广告
   */
  loadAdData();

  /**
   * 销毁广告加载资源
   */
  destroy(): void;

}

3、广告模型类TBNativeAd

在广告加载成功回调中获取相关广告信息,将广告信息传入广告组件TBNativeAdComponent进行信息流广告的展示。

typescript
export class TBNativeAd {
  /**
   * 广告交互监听器
   */
  interactListener: TBNativeAdInteractListener | null = null;
  
  /**
   * 视频交互监听器
   */
  videoListener: TBAdVideoListener | null = null;
  /**
   * 广告dislike弹窗监听
   */
  dislikeListener: TBDislikeListener | null = null;
  /**
   * 渠道ID
   */
  readonly channelId: TBType.Channel;
  /**
   * 普通点击组件Id集合
   */
  readonly clickViewIds: TBClickViewIdList<string> = new TBClickViewIdList();
  /**
   * 创意点击ID集合
   */
  readonly creativeViewIds: TBClickViewIdList<string> = new TBClickViewIdList();
  /**
   * 扩展参数
   */
  readonly extra: Record<string, Object> = {};


  /**
   * 释放资源
   */
  destroy(): void;

  /**
   * 广告唯一标识
   */
  getUniqueId(): string;

  /**
   * 素材类型
   * 【模版渲染为空】
   */
  getMaterialType(): TBType.MaterialType;

  /**
   * 渲染类型 模版渲染 or 自渲染
   */
  getRenderType(): TBType.RenderType;

  /**
   * 信息流广告类型 信息流 or DrawVideo
   */
  getNativeType(): TBType.NativeType;

  /**
   * 广告交互类型
   * 【模版渲染时为空】
   */
  getInteractionType(): TBType.AdInteractionType;

  /**
   * 广告标题
   * 【模版渲染时为空】
   */
  getAdTitle(): string;

  /**
   * 广告描述
   * 【模版渲染时为空】
   */
  getAdDescription(): string;

  /**
   * 广告来源,可能为空
   * 【模版渲染时为空】
   */
  getAdSource(): string;

  /**
   * 获取广告⻆标的logo
   * 当返回string类型时,可能为标准url,(csj)adx广告场景时可能文字描述
   * 【模版渲染时为空】
   */
  getAdLogo(): string | Resource | undefined ;

  /**
   * 广告图片集合,单图和组图类型广告素材有返回,视频类素材返回为空
   * 【模版渲染时为空】
   */
  getImageList(): TBAdImage[];

  /**
   * 广告Icon链接
   * 【模版渲染时为空】
   */
  getAppIconUrl(): string | undefined;

  /**
   * 应用下载相关合规信息
   * 【模版渲染时为空】
   */
  getComplianceInfo(): TBComplianceInfo | undefined;

  /**
   * 应用下载次数文案,非下载返回为空 eg:1000W此下载
   * 【模版渲染时为空】
   */
  getAppDownloadCountDes(): string | undefined;

  /**
   * 广告app评论数
   * 【模版渲染时为0】
   */
  getAppCommentNum(): number;


  /**
   * 应用下载评分,取值0~5.0; 非下载返回为0
   * 【模版渲染时为空】
   */
  getAppScore(): number;

  /**
   * 视频封面url
   * [支持渠道:快手]
   * 【模版渲染时为空】
   */
  getCoverUrl(): TBAdImage | undefined;

  /**
   * 视频url
   * 【模版渲染时为空】
   */
  getVideoUrl(): string | undefined;

  /**
   * 视频时⻓
   * 【模版渲染时为空】
   */
  getVideoDuration(): number;

  /**
   * CTA按钮文案
   * 【模版渲染时为空】
   */
  getActionDescription(): string;


    /**
   * 注册原生自渲染广告点击组件ID
   * @param rootAdComponentId 广告布局根节点Id
   * @param uiContext 当前组件的上下文
   * @param clickViewIds 普通点击Id集合,点击之后,会跳转到落地页,然后再进行后续广告转化
   * @param creativeViewIds: 创意点击Id集合,点击之后,会直接进行转化
   */
  registerViewForInteraction(clickViewIds: TBClickViewIdList<string>, creativeViewIds: TBClickViewIdList<string>);
}

3.1、TBComplianceInfo说明

TBComplianceInfo提供应用下载相关合规信息,仅在返回广告位下载类广告时生效。

typescript
export class TBComplianceInfo extends TBMediaComplianceInfo {

  /**
   * 获取App Name
   * @returns
   */
  getAppName(): string;

  /**
   * 获取应用版本
   * @returns
   */
  getAppVersion(): string;

  /**
   * 获取开发者名称
   * @returns
   */
  getDeveloperName(): string;

  /**
   * 获取隐私协议
   * @returns
   */
  getPrivacyUrl(): string;

  /**
   * 获取权限名称及权限描述列表
   * @returns
   */
  getPermissionsMap(): Map<string, string>;

  /**
   * 获取权限列表url
   * @returns
   */
  getPermissionUrl(): string;

  /**
   * 获取产品功能url
   * @returns
   */
  getIntroductionInfoUrl(): string;
}

4、广告组件TBNativeAdComponent

本组件提供了信息流广告的渲染

TBNativeAdComponent({nativeAd: TBNativeAd, builder: () => void})

展示信息流广告广告

参数名类型必填说明
nativeAdTBNativeAd广告对象
builder() => void应用自渲染广告子组件。

5、视频组件TBNativeMediaComponent

本组件提供了信息流广告视频的渲染(仅在开发者自渲染时渲染)

TBNativeMediaComponent({nativeAd: TBBaseNativeAd})

展示信息流广告视频组件

参数名类型必填说明
nativeAdTBBaseNativeAd广告加载成功后返回的广告对象

6、广告加载监听器

typescript

export interface TBNativeAdLoaderListener {
  /**
   * 广告加载成功
   * @param loader 广告加载对象
   * @param ads 广告对象数据
   */
  onAdLoadSuccessed(ads: TBNativeAd[]): void;

  /**
   * 广告加载失败
   * @param loader 广告加载对象
   * @param error
   */
  onAdLoadFailed(error: BusinessError): void;
}

7、广告交互监听器

typescript
export interface TBNativeAdInteractListener {

  /**
   * 广告渲染成功【仅模版渲染广告】
   * @param adInfo 渠道信息
   * @param width 广告组件宽度
   * @param height 广告组件高度
   */
  onRenderSuccess(adInfo: TBAdInfo, width: number, height: number): void;


  /**
   * 广告渲染失败【仅模版渲染广告】
   * @param adInfo 渠道信息
   * @param error 错误描述信息
   */
  onRenderFail(adInfo: TBAdInfo, error: BusinessError<void>): void;

  /**
   * 广告曝光
   * @param adInfo 渠道信息
   */
  onAdShow(adInfo: TBAdInfo): void;

  /**
   * 广告点击
   * @param adInfo  渠道信息
   */
  onAdClick(adInfo: TBAdInfo): void;

  /**
   * 广告点击关闭
   * @param adInfo  渠道信息
   * @warning 仅在模版渲染时触发,自渲染由开发者自行渲染关闭按钮。
   */
  onAdClose(adInfo: TBAdInfo): void;

}

8、广告视频交互监听器

typescript
export interface TBAdVideoListener {
  /**
   * 视频开始播放
   */
  onVideoPlayStart(adInfo: TBAdInfo): void;

  /**
   * 视频播放结束
   */
  onVideoPlayComplete(adInfo: TBAdInfo): void;

  /**
   * 视频播放失败
   */
  onVideoPlayError(adInfo: TBAdInfo, error: BusinessError): void;
}

9、广告Dislike交互监听器

typescript
export interface TBDislikeListener {
  /**
   * dislike 弹窗show
   */
  onShow(): void;

  /**
   * Dislike 条目被选中
   * @param position  条目的index
   * @param value 条目的内容
   * @param enforce 是否强制关闭广告
   */
  onSelected(position: number, value: string, enforce: boolean): void;


  /**
   * Dislike 弹窗取消
   */
  onCancel(): void;

}

10、加载信息流广告

typescript
// 创建广告请求参数
let request: TBType.AdRequest = {
    placementId: 'your placement id',
    userId: 'your user ID',
  adCount: 1, // 加载广告数量,一次建议1~3条
    adWidth: number, // 广告宽度(单位vp)
  adHeight: number, //当高度不设置时,则模版自适应高度(以宽度自适应高度)
}
// 创建广告加载对象
let loader = new TBNativeAdLoader(request);
// 设置广告监听
loader.adLoadListener = this;
// 加载广告
loader.loadAdData();

11、注册原生自渲染广告计费事件

注意:仅针对自渲染生效

通过registerViewForInteraction方法注册原生自渲染广告计费事件和交互事件,方法说明如下,其中TBClickViewIdList类为SDK提供的集合容器继承自ArrayList;该容器主要作用是收集注册点击事件的UI组件Id;

注意:UI组件id在应用中必须保持唯一(华为鸿蒙官方要求)

typescript
/**
   * 注册原生自渲染广告点击组件ID
   * @param rootAdComponentId 广告布局根节点Id
   * @param uiContext 当前组件的上下文
   * @param clickViewIds 普通点击Id集合,点击之后,会跳转到落地页,然后再进行后续广告转化
   * @param creativeViewIds: 创意点击Id集合,点击之后,会直接进行转化
   */
  registerViewForInteraction(clickViewIds: TBClickViewIdList<string>, creativeViewIds: TBClickViewIdList<string>);

注意:这里clickViewIds和creativeViewIds的区别,注册在clickViewIds的组件,点击后会跳转到落地页,然后再进行后续的广告转化,注册在creativeViewIds的组件,点击后,会直接进行转化

注册案例:

typescript
@Builder
  builderAdView(nativeAd: TBNativeAd) {
    Column() {
      Flex({ direction: FlexDirection.Row, justifyContent: FlexAlign.Start, alignItems: ItemAlign.Center }) {
        Image(nativeAd.getAppIconUrl())
          .id(this.clickViewIds.addAdId(util.generateRandomUUID())) //设置组件Id,需要全局保证唯一性,涉及计费
          .objectFit(ImageFit.Contain)
          .height('100%')
          .aspectRatio(1)
          .borderRadius(5)
          .constraintSize({
            minWidth: 50, minHeight: 50
          })
          .backgroundColor(Color.Black)
        Flex({ direction: FlexDirection.Column, justifyContent: FlexAlign.SpaceBetween, alignItems: ItemAlign.Start }) {
          Text(nativeAd.getAdTitle())
              .id(this.clickViewIds.addAdId(util.generateRandomUUID())) //设置组件Id,需要全局保证唯一性,涉及计费
            .maxLines(1)
          Text(nativeAd.getAdDescription())
              .id(this.clickViewIds.addAdId(util.generateRandomUUID())) //设置组件Id,需要全局保证唯一性,涉及计费
            .maxLines(1)
            .textOverflow({
              overflow: TextOverflow.Ellipsis
            })
        }
        .height('100%')
        .margin({ left: 10 })
      }
      .width('100%')
      .height(50)
      .margin({ top: 10 })

      Flex({ direction: FlexDirection.Row, justifyContent: FlexAlign.SpaceBetween, alignItems: ItemAlign.End }) {
        Row({ space: 3 }) {
          if (nativeAd.getAdLogo()) {
            Image(nativeAd.getAdLogo())
              .objectFit(ImageFit.Cover)
              .onComplete((data) => {
                if (data?.loadingStatus === 1) {
                  this.logoWidth = data.width / data.height * 20;
                }
              })
              .width(this.logoWidth).height(20)
          } else {
            Text(nativeAd!.getAdSource())
              .fontColor(Color.Red)
              .fontSize(10)
          }
        }

        Button(nativeAd.getActionDescription())
          .buttonStyle(ButtonStyleMode.TEXTUAL)
          .controlSize(ControlSize.SMALL)
          .fontColor(Color.Blue)
          .borderWidth(0.5)
          .borderColor(Color.Blue)
          .backgroundColor(Color.White)
          .id(this.creativeViewIds.addAdId(util.generateRandomUUID())) //设置组件Id,需要全局保证唯一性,涉及计费
      }
      .width('100%')
      .margin({ top: 10 })
    }
    .width('100%')
    .padding(10)
    .backgroundColor(Color.Transparent)
    .onAppear(() => {
      nativeAd.registerViewForInteraction(this.clickViewIds, this.creativeViewIds)
    })
  }

12、展示信息流广告

信息流广告分为自渲染和模版渲染,渲染类型可通过native.getRenderType()判断

12.1、展示自渲染信息流广告

typescript
TBNativeAdComponent({
    nativeAd: this.nativeAd,
    builder: (): void => this.builderAd()
})

其中builderAd中为渲染自渲染的布局,由开发者自定布局样式。

注意:自渲染需通过registerViewForInteraction方法注册原生自渲染广告计费事件和交互事件,否则会影响计费

typescript
@Builder
builderAd(nativeAd: TBNativeAd) {
    Column() {
      Stack() {
        if (nativeAd.getMaterialType() === TBType.MaterialType.video) {
          this.builderVideo()
        } else {
          this.builderImage()
        }
      }
      .width('100%')
      .aspectRatio(1.7778)
      .borderRadius(10)
      .clip(true)
      .backgroundColor(Color.Black)

      Flex({ direction: FlexDirection.Row, justifyContent: FlexAlign.Start, alignItems: ItemAlign.Center }) {
        Image(nativeAd.getAppIconUrl())
          .id(this.clickViewIds.addAdId(util.generateRandomUUID())) //设置组件Id,需要全局保证唯一性,涉及计费
          .objectFit(ImageFit.Contain)
          .height('100%')
          .aspectRatio(1)
          .borderRadius(5)
          .constraintSize({
            minWidth: 50, minHeight: 50
          })
          .backgroundColor(Color.Black)
        Flex({ direction: FlexDirection.Column, justifyContent: FlexAlign.SpaceBetween, alignItems: ItemAlign.Start }) {
          Text(nativeAd.getAdTitle())
              .id(this.clickViewIds.addAdId(util.generateRandomUUID())) //设置组件Id,需要全局保证唯一性,涉及计费
            .maxLines(1)
          Text(nativeAd.getAdDescription())
              .id(this.clickViewIds.addAdId(util.generateRandomUUID())) //设置组件Id,需要全局保证唯一性,涉及计费
            .maxLines(1)
            .textOverflow({
              overflow: TextOverflow.Ellipsis
            })
        }
        .height('100%')
        .margin({ left: 10 })
      }
      .width('100%')
      .height(50)
      .margin({ top: 10 })

      Flex({ direction: FlexDirection.Row, justifyContent: FlexAlign.SpaceBetween, alignItems: ItemAlign.End }) {
        Row({ space: 3 }) {
          if (nativeAd.getAdLogo()) {
            Image(nativeAd.getAdLogo())
              .objectFit(ImageFit.Cover)
              .onComplete((data) => {
                if (data?.loadingStatus === 1) {
                  this.logoWidth = data.width / data.height * 20;
                }
              })
              .width(this.logoWidth).height(20)
          } else {
            Text(nativeAd!.getAdSource())
              .fontColor(Color.Red)
              .fontSize(10)
          }
        }

        Button(nativeAd.getActionDescription())
          .buttonStyle(ButtonStyleMode.TEXTUAL)
          .controlSize(ControlSize.SMALL)
          .fontColor(Color.Blue)
          .borderWidth(0.5)
          .borderColor(Color.Blue)
          .backgroundColor(Color.White)
          .id(this.creativeViewIds.addAdId(util.generateRandomUUID())) //设置组件Id,需要全局保证唯一性,涉及计费
      }
      .width('100%')
      .margin({ top: 10 })
    }
    .width('100%')
    .padding(10)
    .backgroundColor(Color.Transparent)
    .onAppear(() => {
      nativeAd.registerViewForInteraction(this.clickViewIds, this.creativeViewIds)
    })
  }

  @Builder
  builderImage() {
    if (this.nativeAd?.getImageList() !== undefined) {
      Image(this.nativeAd!.getImageList()[0].imageUrl)
        .objectFit(ImageFit.Contain)
        .width('100%').height('100%')
        .backgroundColor(Color.Transparent)
    }

  }

  @Builder
  builderVideo() {
    TBNativeMediaComponent({ nativeAd: this.nativeAd })
      .width('100%')
      .width('100%').height('100%')
      .backgroundColor(Color.Black)
  }

12.2、展示模版渲染信息流广告

typescript
TBNativeAdComponent({
    nativeAd: this.nativeAd
})