纯血鸿蒙开发之广告服务(1)

2025-05-23 16:23:54
127次阅读
0个评论

纯血鸿蒙开发之广告服务(1)

大家好,我是青蓝逐码的云杰,今天我想来聊一聊学习一下鸿蒙的广告服务!

Ads Kit(广告服务)

Ads Kit(广告服务)依托华为终端平台与数据能力为您提供流量变现服务,帮助您解决流量变现的难题;同时为广告主提供广告服务,配合华为终端平台向用户提供个性化的营销活动或商业广告。

鲸鸿动能流量变现服务(以下简称流量变现服务)是广告服务依托华为终端强大的平台与数据能力为您提供的App流量变现服务,您通过该服务可以在自己的App中获取并向用户展示精美的、高价值的广告内容,并从中获得广告收益。 为满足App不同场景下的内容形式,流量变现服务提供了横幅广告、原生广告、激励广告、插屏广告、开屏广告、贴片广告六种广告形式。

广告形式 展示形式 应用场景
横幅广告 图片 以通知栏或矩形固定展示在应用内页面顶部、中部或底部,适合用于用户停留较久或者访问频繁的页面。
原生广告 图片、视频 界面内插入广告,与媒体内容无缝融合。
激励广告 视频 游戏通关、复活、获取道具、积分、继续机会、人物技能升级时等展示。
插屏广告 图片、视频 游戏或流媒体开启、暂停、过关、跳转、加载、退出时弹出。
开屏广告 图片、视频 打开App时,以开屏形式全屏展现,展示时长3s-5s,展示完毕后自动关闭并进入应用主页面。
贴片广告 图片、视频 前贴:视频播放前。中贴:视频播放中。后贴:视频播放结束后。说明:您可以根据自身需求设置广告的播放时长。

具体如何进入这项服务,我在之前的文章中专门介绍过接入广告服务,这里就不过多介绍这个,本系列文章主要介绍的是广告的使用和展示

广告展示

1.横幅广告

横幅广告又名Banner广告,是在应用程序顶部、中部或底部占据一个位置的矩形图片,广告内容每隔一段时间会自动刷新。

1.1 解释说明

横幅广告是所有广告里较为简单的。

  1. 获取OAID。

    若需提升广告推送精准度,可以在请求参数AdRequestParams中添加oaid属性以提升广告推送精准度和广告填充率。

    如何获取OAID参考获取OAID信息

    说明

    使用以下示例中提供的测试广告位时,必须先获取OAID信息。

    identifier.getOAID().then((data: string) => {
      this.oaid = data;
    }).catch((error: BusinessError) => {
      hilog.error(0x0000, 'testTag', 'Failed to get OAID');
    });
    
    

  2. 请求和展示广告。

    在您的页面中使用AutoAdComponent组件展示横幅广告。

    请求广告关键参数如下所示:

    请求广告参数名 类型 必填 说明
    adType number 请求广告类型,横幅广告类型为8。
    adId string 广告位ID。如果仅调测广告,可使用测试广告位ID:testw6vs28auh3。如果要接入正式广告,则需要申请正式的广告位ID。可在应用发布前进入流量变现官网,点击“开始变现”,登录鲸鸿动能媒体服务平台进行申请,具体操作详情请参见展示位创建
    adWidth number 广告位宽,单位vp。宽和高支持36057和360144两种尺寸。
    adHeight number 广告位高,单位vp。宽和高支持36057和360144两种尺寸。
    oaid string 开放匿名设备标识符,用于精准推送广告。不填无法获取到个性化广告。

    展示广告关键参数如下所示:

    展示广告参数名 类型 必填 说明
    refreshTime number 横幅广告轮播时间。单位ms,取值范围[30000, 120000]。如果不设置或取值为非数字或小于等于0的数字,则不轮播。设置小于30000的数字取值30000,设置大于120000的数字取值120000。
      AutoAdComponent({
        adParam: this.adParam,
        adOptions: this.adOptions,
        displayOptions: this.displayOptions,
        interactionListener: {
          onStatusChanged: (status: string, ad: advertising.Advertisement, data: string) => {
            hilog.info(0x0000, 'testTag', '%{public}s', `status is ${status}`);
            switch (status) {
              case AdStatus.AD_OPEN:
                hilog.info(0x0000, 'testTag', '%{public}s', 'Status is onAdOpen');
                break;
              case AdStatus.AD_CLICKED:
                hilog.info(0x0000, 'testTag', '%{public}s', 'Status is onAdClick');
                break;
              case AdStatus.AD_CLOSED:
                hilog.info(0x0000, 'testTag', '%{public}s', 'Status is onAdClose');
                this.visibilityState = Visibility.None;
                break;
              case AdStatus.AD_LOAD:
                hilog.info(0x0000, 'testTag', '%{public}s', 'Status is onAdLoad');
                break;
              case AdStatus.AD_FAIL:
                hilog.error(0x0000, 'testTag', '%{public}s', 'Status is onAdFail');
                this.visibilityState = Visibility.None;
                break;
            }
          }
        }
      })

1.2示例代码

为了小伙伴之后,可以直接使用,这边我已经将他封装成自定义组件咯

import { advertising, AutoAdComponent } from '@kit.AdsKit';
import { hilog } from '@kit.PerformanceAnalysisKit';


@Component
export struct BannerView {
 @State adParam: advertising.AdRequestParams = {
   // 广告类型:横幅广告
   adType: 8,
   // 'testw6vs28auh3'为测试专用的广告位ID,应用正式发布时需要改为正式的广告位ID
   adId: 'testw6vs28auh3',
   // 广告位宽
   adWidth: 360,
   // 广告位高
   adHeight: 57
 };
 private adOptions: advertising.AdOptions = {
   // 是否允许流量下载0:不允许,1:允许,不设置以广告主设置为准
   allowMobileTraffic: 0,
   // 是否希望根据 COPPA 的规定将您的内容视为面向儿童的内容: -1默认值,不确定 0不希望 1希望
   tagForChildProtection: -1,
   // 是否希望按适合未达到法定承诺年龄的欧洲经济区 (EEA) 用户的方式处理该广告请求: -1默认值,不确定 0不希望 1希望
   tagForUnderAgeOfPromise: -1,
   // 设置广告内容分级上限: W: 3+,所有受众 PI: 7+,家长指导 J:12+,青少年 A: 16+/18+,成人受众
   adContentClassification: 'A'
 };
 private displayOptions: advertising.AdDisplayOptions = {
   // 广告轮播的时间间隔,单位ms,取值范围[30000, 120000]
   refreshTime: 30000
 }
 private ratio: number = 1;
 private adWidth: number = -1;
 private adHeight: number = -1;
 @State visibilityState: Visibility = Visibility.Visible;

 aboutToAppear() {
   if (this.adParam?.adWidth && typeof (this.adParam?.adWidth) === 'number' && this.adParam?.adWidth > 0) {
     this.adWidth = this.adParam?.adWidth;
   }
   if (this.adParam?.adHeight && typeof (this.adParam?.adHeight) === 'number' && this.adParam?.adHeight > 0) {
     this.adHeight = this.adParam?.adHeight;
   }
   if (this.adWidth > 0 && this.adHeight > 0) {
     this.ratio = this.adWidth / this.adHeight;
   }
 }

 build() {
   Stack({ alignContent: Alignment.Bottom }) {
     this.buildBannerView()
   }
 }

 @Builder
 buildBannerView() {
   Row() {
     AutoAdComponent({
       adParam: this.adParam,
       adOptions: this.adOptions,
       displayOptions: this.displayOptions,
       interactionListener: {
         onStatusChanged: (status: string, ad: advertising.Advertisement, data: string) => {
           hilog.info(0x0000, 'testTag', '%{public}s', `status is ${status}`);
           switch (status) {
             case AdStatus.AD_OPEN:
               hilog.info(0x0000, 'testTag', '%{public}s', 'Status is onAdOpen');
               break;
             case AdStatus.AD_CLICKED:
               hilog.info(0x0000, 'testTag', '%{public}s', 'Status is onAdClick');
               break;
             case AdStatus.AD_CLOSED:
               hilog.info(0x0000, 'testTag', '%{public}s', 'Status is onAdClose');
               this.visibilityState = Visibility.None;
               break;
             case AdStatus.AD_LOAD:
               hilog.info(0x0000, 'testTag', '%{public}s', 'Status is onAdLoad');
               break;
             case AdStatus.AD_FAIL:
               hilog.error(0x0000, 'testTag', '%{public}s', 'Status is onAdFail');
               this.visibilityState = Visibility.None;
               break;
           }
         }
       }
     })
   }
   .width('100%')
   .aspectRatio(this.ratio)
   .visibility(this.visibilityState)
 }
}

enum AdStatus {
 AD_LOAD = 'onAdLoad',
 AD_FAIL = 'onAdFail',
 AD_OPEN = 'onAdOpen',
 AD_CLICKED = 'onAdClick',
 AD_CLOSED = 'onAdClose',
 AD_REWARDED = 'onAdReward',
 AD_VIDEO_START = 'onVideoPlayBegin',
 AD_COMPLETED = 'onVideoPlayEnd'
}

1.3 效果演示

1.4 总结

  • 广告请求:通过 AdLoader 请求广告并处理回调。
  • 广告显示:使用 AdComponent 组件展示广告数据,并通过 interactionListener 监听广告状态。

2.开屏广告

开屏广告是一种在应用启动时且在应用主界面显示之前展示的广告。它分为以下两种类型:

  • 全屏开屏广告:广告覆盖整个屏幕。
  • 半屏开屏广告:广告占据部分屏幕,并可自定义布局,通常会显示广告的图标和版权信息。

2.1 开发步骤

2.1.1 获取OAID

  • OAID(Open Advertising ID)是设备的唯一广告标识符,用于精准推送广告。建议在请求广告时传递 OAID 以提升广告投放的精准度。
  • 获取 OAID 示例代码:
identifier.getOAID().then((data: string) => {
  this.oaid = data;
}).catch((error: BusinessError) => {
  hilog.error(0x0000, 'testTag', 'Failed to get OAID');
});

2.1.2 请求广告

需要创建一个AdLoader对象,通过AdLoader的loadAd方法请求广告,最后通过AdLoadListener来监听广告的加载状态。测试开屏广告时,需要使用专门的测试广告位来获取测试开屏广告,示例代码中提供了两种开屏广告类型对应的广告位:半屏开屏(图片)(testq6zq98hecj)和全屏开屏(视频)(testd7c5cewoj6),测试广告位ID仅作为调试使用,不可用于广告变现。

请求广告关键参数如下所示:

请求广告参数名 类型 必填 说明
adType number 请求广告类型,开屏广告类型为1。
adId string 广告位ID。如果仅调测广告,可使用测试广告位ID:testq6zq98hecj半屏开屏(图片)和testd7c5cewoj6全屏开屏(视频)。如果要接入正式广告,则需要申请正式的广告位ID。可在应用发布前进入流量变现官网,点击“开始变现”,登录鲸鸿动能媒体服务平台进行申请,具体操作详情请参见展示位创建
adCount number 广告数量。
返回广告参数名 类型 说明
isFullScreen boolean 标识返回的广告是否为全屏,true为全屏广告,false为半屏广告。

说明

  1. 如果超时没有请求到广告,应用自行跳转到默认首页。
  2. 为保证开屏展示效果,建议开发者在请求广告前,设置屏幕方向为竖屏。

2.1.3 设置监听回调

  • 通过 AdLoadListener 监听广告加载的回调:
    • onAdLoadFailure:广告加载失败。
    • onAdLoadSuccess:广告加载成功。
const adLoaderListener: advertising.AdLoadListener = {
  onAdLoadFailure: (errorCode: number, errorMsg: string) => {
    hilog.error(0x0000, 'testTag', `Failed to load ad. errorCode: ${errorCode}, errorMsg: ${errorMsg}`);
  },
  onAdLoadSuccess: (ads: Array<advertising.Advertisement>) => {
    hilog.info(0x0000, 'testTag', 'Ad loaded successfully!');
    // 展示广告
  }
};

2.2 开发使用

2.2.1 请求封装

将请求开屏广告(全屏和半屏)的方法进行封装

import { router } from '@kit.ArkUI';
import { advertising } from '@kit.AdsKit';
import { common } from '@kit.AbilityKit';
import { emitter } from '@kit.BasicServicesKit';


/**
 * 开屏广告
 * 1.视频  2.图片
 */

export enum AdType {
  // 开屏广告的类型
  SPLASH_AD = 1
}

class SplashAdUtil {
  private context: common.UIAbilityContext = getContext(this) as common.UIAbilityContext;
  private isTimeOut: boolean = false;
  // 超时时间(单位毫秒),开发者可根据实际情况修改
  private timeOutDuration: number = 1 * 1000;
  // 超时index
  private timeOutIndex: number = -1;
  // 广告展示参数
  private adDisplayOptions: advertising.AdDisplayOptions = {
    // 是否静音,默认不静音
    mute: false
  }
  // 广告配置
  private adOptions: advertising.AdOptions = {
    // 是否允许流量下载0:不允许,1:允许,不设置以广告主设置为准
    allowMobileTraffic: 0,
    // 是否希望根据 COPPA 的规定将您的内容视为面向儿童的内容: -1默认值,不确定 0不希望 1希望
    tagForChildProtection: -1,
    // 是否希望按适合未达到法定承诺年龄的欧洲经济区 (EEA) 用户的方式处理该广告请求: -1默认值,不确定 0不希望 1希望
    tagForUnderAgeOfPromise: -1,
    // 设置广告内容分级上限: W: 3+,所有受众 PI: 7+,家长指导 J:12+,青少年 A: 16+/18+,成人受众
    adContentClassification: 'A'
  }
  // 开屏视频广告请求参数
  private splashVideoAdReqParams: advertising.AdRequestParams = {
    // 'testd7c5cewoj6'为测试专用的广告位ID,App正式发布时需要改为正式的广告位ID
    adId: 'testd7c5cewoj6',
    adType: AdType.SPLASH_AD,
    adCount: 1,
  }
  // 开屏图片广告请求参数
  private splashImageAdReqParams: advertising.AdRequestParams = {
    // 'testq6zq98hecj'为测试专用的广告位ID,App正式发布时需要改为正式的广告位ID
    adId: 'testq6zq98hecj',
    adType: AdType.SPLASH_AD,
    adCount: 1,
  }

  private requestAd(adReqParams: advertising.AdRequestParams, adOptions: advertising.AdOptions): void {
    // 广告请求回调监听
    const adLoaderListener: advertising.AdLoadListener = {
      // 广告请求失败回调
      onAdLoadFailure: (errorCode: number, errorMsg: string) => {
        clearTimeout(this.timeOutIndex);
        if (this.isTimeOut) {
          return;
        }
      },
      // 广告请求成功回调
      onAdLoadSuccess: (ads: Array<advertising.Advertisement>) => {
        clearTimeout(this.timeOutIndex);
        if (this.isTimeOut) {
          return;
        }
        // 保存请求到的广告内容用于展示
        if (canIUse("SystemCapability.Advertising.Ads")) {
          if (ads[0].adType === AdType.SPLASH_AD) {
            // 调用开屏广告展示页面
            if (ads[0]?.isFullScreen === true) {
              emitter.emit('SplashFullScreenAdPage',
                { data: { 'ads': ads, 'adDisplayOptions': this.adDisplayOptions } })

            } else {
              emitter.emit('SplashHalfScreenAdPage',
                { data: { 'ads': ads, 'adDisplayOptions': this.adDisplayOptions } })
            }
          } else {

          }
        }
      }
    };
    // 创建AdLoader广告对象
    const load: advertising.AdLoader = new advertising.AdLoader(this.context);
    // 调用广告请求接口
    // adReqParams.oaid = this.oaid;
    this.timeOutHandler();
    load.loadAd(adReqParams, adOptions, adLoaderListener);
  }

  private timeOutHandler(): void {
    this.isTimeOut = false;
    // 超时处理
    this.timeOutIndex = setTimeout(() => {
      this.isTimeOut = true;
      const options: router.RouterOptions = {
        // 开发者可根据项目实际情况修改超时之后要跳转的目标页面
        url: 'pages/Index',
      };
      router.pushUrl(options);
    }, this.timeOutDuration);
  }

  //视频
  splashVideoAd() {
    this.requestAd(this.splashVideoAdReqParams, this.adOptions);
  }

  //图片
  splashImageAd() {
    this.requestAd(this.splashImageAdReqParams, this.adOptions);
  }
}

export const splashAdUtil = new SplashAdUtil()

2.2.2 广告参数传递

当发送广告请求,得到应有的广告参数之后,我们将参数传递给全屏广告或者半屏广告(利用emitter线性通信)

            if (ads[0]?.isFullScreen === true) {
              emitter.emit('SplashFullScreenAdPage',
                { data: { 'ads': ads, 'adDisplayOptions': this.adDisplayOptions } })

            } else {
              emitter.emit('SplashHalfScreenAdPage',
                { data: { 'ads': ads, 'adDisplayOptions': this.adDisplayOptions } })
            }

2.2.3 开屏(全屏)广告展示

  1. 解释广告请求时间点
  aboutToAppear() {
    emitter.on('SplashFullScreenAdPage', (eventData: emitter.EventData) => {
      const data = eventData.data as Record<string, object>
      this.ads = data['ads'] as Array<advertising.Advertisement>
      this.displayOptions = data['adDisplayOptions'] as advertising.AdDisplayOptions
      this.isShow = true
    })
    splashAdUtil.splashVideoAd()
  }

  1. 全屏广告页面
import { router } from '@kit.ArkUI';
import { AdComponent, advertising } from '@kit.AdsKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
import { emitter } from '@kit.BasicServicesKit';
import { splashAdUtil } from '../utils/SplashAdUtil';

const TAG = 'Ads Demo-SplashFullScreenAdPage';

@Entry
@Component
struct SplashFullScreenAdPage {
  private ads: Array<advertising.Advertisement> = [];
  private displayOptions?: advertising.AdDisplayOptions;
  @State isShow: boolean = false

  aboutToAppear() {
    emitter.on('SplashFullScreenAdPage', (eventData: emitter.EventData) => {
      const data = eventData.data as Record<string, object>
      this.ads = data['ads'] as Array<advertising.Advertisement>
      this.displayOptions = data['adDisplayOptions'] as advertising.AdDisplayOptions
      this.isShow = true
    })
    splashAdUtil.splashVideoAd()
  }

  build() {
    if (this.isShow) {
      Column() {
        // 运行在提供方进程里
        AdComponent({
          ads: this.ads, displayOptions: this.displayOptions,
          interactionListener: {
            onStatusChanged: (status: string, ad: advertising.Advertisement, data: string) => {
              switch (status) {
                case AdStatus.AD_OPEN:
                  hilog.info(0x0000, 'testTag', '%{public}s', 'Status is onAdOpen');

                  break;
                case AdStatus.AD_CLICKED:
                  hilog.info(0x0000, 'testTag', '%{public}s', 'Status is onAdClick');

                  break;
                case AdStatus.AD_CLOSED:
                  hilog.info(0x0000, 'testTag', '%{public}s', 'Status is onAdClose');
                  router.replaceUrl({
                    url: 'pages/Index',
                  })
                  break;
              }
            }
          }
        })
          .width('100%')
          .height('100%')

      }
      .width('100%')
      .height('100%')
    }

  }
}

export enum AdStatus {
  AD_OPEN = 'onAdOpen',
  AD_CLICKED = 'onAdClick',
  AD_CLOSED = 'onAdClose'
}
  1. 效果展示

2.2.4 开屏(半屏)广告展示

  1. 解释广告请求时间点
  aboutToAppear() {
    emitter.on('SplashHalfScreenAdPage', (eventData: emitter.EventData) => {
      const data = eventData.data as Record<string, object>
      this.ads = data['ads'] as Array<advertising.Advertisement>
      this.displayOptions = data['adDisplayOptions'] as advertising.AdDisplayOptions
      this.isShow = true
    })
    splashAdUtil.splashImageAd()
  }
  1. 半屏广告页面

    import { router } from '@kit.ArkUI';
    import { AdComponent, advertising } from '@kit.AdsKit';
    import { splashAdUtil } from '../utils/SplashAdUtil';
    import { emitter } from '@kit.BasicServicesKit';
    
    @Entry
    @Component
    struct SplashHalfScreenAdPage {
      private ads: Array<advertising.Advertisement> = [];
      private displayOptions?: advertising.AdDisplayOptions;
      @State isShow: boolean = false
    
      aboutToAppear() {
        emitter.on('SplashHalfScreenAdPage', (eventData: emitter.EventData) => {
          const data = eventData.data as Record<string, object>
          this.ads = data['ads'] as Array<advertising.Advertisement>
          this.displayOptions = data['adDisplayOptions'] as advertising.AdDisplayOptions
          this.isShow = true
        })
        splashAdUtil.splashImageAd()
      }
    
      build() {
        if (this.isShow) {
          Column() {
            // 运行在提供方进程里
            AdComponent({
              ads: this.ads, displayOptions: this.displayOptions,
              interactionListener: {
                onStatusChanged: (status: string, ad: advertising.Advertisement, data: string) => {
                  switch (status) {
                    case AdStatus.AD_OPEN:
    
                      break;
                    case AdStatus.AD_CLICKED:
                      break;
                    case AdStatus.AD_CLOSED:
    
                      router.replaceUrl({
                        url: 'pages/Index',
                      })
                      break;
                  }
                }
              }
            })
              .width('100%')
              .height('87%')
    
            // 展示媒体自定义icon、应用名称、版权信息
            Column({}) {
              Text('广告')
            }.width('100%').height('100%')
          }
        }
    
      }
    }
    
    export enum AdStatus {
      AD_OPEN = 'onAdOpen',
      AD_CLICKED = 'onAdClick',
      AD_CLOSED = 'onAdClose'
    }
    
  2. 效果展示

后续

今天介绍了广告服务中的两个,后续也会继续学习剩余的广告服务;如果我的内容对您有帮助,可以点赞、关注+收藏,谢谢大家!如果小伙伴对鸿蒙的其他内容感兴趣,欢迎加入我们青蓝逐码!

青蓝逐码官网:https://www.qinglanzhuma.cn/

收藏00

登录 后评论。没有帐号? 注册 一个。