普通视图

发现新文章,点击刷新页面。
今天 — 2025年5月18日首页

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

作者 云_杰
2025年5月18日 12:34

前言

哈喽,小伙伴们大家好!我是青蓝逐码的云杰,上一篇文章我们学习鸿蒙广告服务中的banner广告和开屏广告,今天我们接着学习!

1.原生广告

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

1.1 广告展示

1.2 开发步骤

1.2.1 获取OAID。

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

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

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

1.2.2 请求广告。

请求单广告位广告,需要创建一个AdLoader对象,通过AdLoader的loadAd方法请求广告,最后通过AdLoadListener,来监听广告的加载状态。

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

请求广告参数名 类型 必填 说明
adType number 请求广告类型,原生广告类型为3。
adId string 广告位ID。如果仅调测广告,可使用测试广告位ID:testy63txaom86(原生视频),testu7m3hc4gvm(原生大图),testb65czjivt9(原生小图),testr6w14o0hqz(原生三图)。如果要接入正式广告,则需要申请正式的广告位ID。可在应用发布前进入流量变现官网,点击“开始变现”,登录鲸鸿动能媒体服务平台进行申请,具体操作详情请参见展示位创建
oaid string 开放匿名设备标识符,用于精准推送广告。不填无法获取到个性化广告。

1.2.3 广告监听

  • 通过 AdLoadListener 监听广告加载的回调:
    • onAdLoadFailure:广告加载失败。
    • onAdLoadSuccess:广告加载成功。
    // 广告请求回调监听
    const adLoaderListener: advertising.AdLoadListener = {
      // 广告请求失败回调
      onAdLoadFailure: (errorCode: number, errorMsg: string) => {
        hilog.error(0x0000, 'testTag', '%{public}s',
          `Failed to request ad, message: ${errorMsg}, error code: ${errorCode}`);
      },
      // 广告请求成功回调
      onAdLoadSuccess: (ads: Array<advertising.Advertisement>) => {
        hilog.info(0x0000, 'testTag', '%{public}s', `Succeeded in requesting ad`);
        // 调用原生广告展示页面
        promptAction.showToast({ message: '成功·' })
        emitter.emit('NativeAdPage',
          { data: { 'ads': ads, 'adDisplayOptions': adDisplayOptions } })
      }
    };

1.2.4 封装请求

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

export class NativeAdUtil {
  private ads: Array<advertising.Advertisement> = [];
  private context: common.UIAbilityContext = getContext(this) as common.UIAbilityContext;

  requestAd() {
    // 广告展示参数
    const adDisplayOptions: advertising.AdDisplayOptions = {
      // 是否静音,默认不静音
      mute: false
    }
    // 原生广告配置
    const adOptions: advertising.AdOptions = {
      // 设置是否请求非个性化广告
      nonPersonalizedAd: 1,
      // 是否允许流量下载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'
    }
    // 原生广告请求参数
    const nativeVideoAdReqParams: advertising.AdRequestParams = {
      // 'testu7m3hc4gvm'为测试专用的广告位ID,应用正式发布时需要改为正式的广告位ID
      adId: 'testu7m3hc4gvm',
      adType: 3,
      adCount: 1,
      // 原生广告自定义扩展参数。等所有广告素材下载完后再回调
      enableDirectReturnVideoAd: true
    }
    // 广告请求回调监听
    const adLoaderListener: advertising.AdLoadListener = {
      // 广告请求失败回调
      onAdLoadFailure: (errorCode: number, errorMsg: string) => {
        hilog.error(0x0000, 'testTag', '%{public}s',
          `Failed to request ad, message: ${errorMsg}, error code: ${errorCode}`);
      },
      // 广告请求成功回调
      onAdLoadSuccess: (ads: Array<advertising.Advertisement>) => {
        hilog.info(0x0000, 'testTag', '%{public}s', `Succeeded in requesting ad`);
        // 调用原生广告展示页面
        promptAction.showToast({ message: '成功·' })
        emitter.emit('NativeAdPage',
          { data: { 'ads': ads, 'adDisplayOptions': adDisplayOptions } })
      }
    };
    // 创建AdLoader广告对象
    const load: advertising.AdLoader = new advertising.AdLoader(this.context);
    // 调用广告请求接口
    load.loadAd(nativeVideoAdReqParams, adOptions, adLoaderListener);
  }
}

export const nativeAdUtil = new NativeAdUtil()

1.2.5 封装原生广告组件

  1. 请求广告

     nativeAdUtil.requestAd()
    
  2. 获取广告参数信息

      aboutToAppear() {
        emitter.on('NativeAdPage', (eventData: emitter.EventData) => {
          const data = eventData.data as Record<string, object>
          this.ads = data['ads'] as Array<advertising.Advertisement>
          this.adDisplayOptions = data['adDisplayOptions'] as advertising.AdDisplayOptions
          this.isShow = true
        })
        nativeAdUtil.requestAd()
      }
    
  3. 广告封装组件

    import { AdComponent, advertising } from '@kit.AdsKit';
    import { emitter } from '@kit.BasicServicesKit';
    import { nativeAdUtil } from '../utils/NativeAdUtil';
    
    
    @Component
    export struct NativeAdView {
      // 广告内容
      private ads: Array<advertising.Advertisement> = [];
      private adDisplayOptions: advertising.AdDisplayOptions = {
        // 是否静音,默认不静音
        mute: false
      };
      @State isShow: boolean = false
      @State isShowClose: boolean = false
    
      aboutToAppear() {
        emitter.on('NativeAdPage', (eventData: emitter.EventData) => {
          const data = eventData.data as Record<string, object>
          this.ads = data['ads'] as Array<advertising.Advertisement>
          this.adDisplayOptions = data['adDisplayOptions'] as advertising.AdDisplayOptions
          this.isShow = true
        })
        nativeAdUtil.requestAd()
      }
    
      build() {
        if (this.isShow) {
          Column() {
            AdComponent({
              ads: this.ads,
              displayOptions: this.adDisplayOptions,
              interactionListener: {
                onStatusChanged: (status: string, ad: advertising.Advertisement, data: string) => {
                  switch (status) {
                    case AdStatus.AD_OPEN:
                      this.isShowClose = true
                      break;
                    case AdStatus.AD_CLICKED:
                      break;
                    case AdStatus.AD_CLOSED:
                      this.isShowClose = false
                      this.isShow = false
                      break;
                    default:
                  }
                }
              }
            })
              .width('100%')
            if (this.isShowClose) {
              Row() {
                Text('关闭')
                  .fontSize(12)
                  .onClick(() => {
                    this.isShow = false
                  })
              }
              .width('100%')
            }
          }
        }
    
      }
    }
    
    enum AdStatus {
      AD_OPEN = 'onAdOpen',
      AD_CLICKED = 'onAdClick',
      AD_CLOSED = 'onAdClose'
    }
    
  4. 效果展示

2. 插屏广告

插屏广告是一种在应用开启、暂停或退出时以全屏或半屏的形式弹出的广告形式,展示时机巧妙避开用户对应用的正常体验,尺寸大,曝光效果好。

2.1 广告展示

2.2 订阅广告监听

开发者需要在App中订阅com.huawei.hms.pps.action.PPS_INTERSTITIAL_STATUS_CHANGED事件来监听插屏广告页面变化并接收插屏信息。示例代码中的订阅方法registerPPSReceiver()需要在每次展示广告前调用 。 在订阅到公共事件后,可以从CommonEventData的parameters参数中使用"interstitial_ad_status"作为key值获取插屏广告页面变化状态。

import { BusinessError, commonEventManager } from '@kit.BasicServicesKit';
import { hilog } from '@kit.PerformanceAnalysisKit';

const KEY_INTERSTITIAL_STATUS = 'interstitial_ad_status';

export class InterstitialAdUtil {
  // 用于保存创建成功的订阅者对象,后续使用其完成订阅及退订的动作
  private subscriber: commonEventManager.CommonEventSubscriber | null = null;

  // 订阅方法,需要在每次展示广告前调用
  public registerPPSReceiver(): void {
    if (this.subscriber) {
      this.unRegisterPPSReceiver();
    }
    // 订阅者信息
    const subscribeInfo: commonEventManager.CommonEventSubscribeInfo = {
      events: ['com.huawei.hms.pps.action.PPS_INTERSTITIAL_STATUS_CHANGED'],
      publisherBundleName: 'com.huawei.hms.adsservice'
    };
    // 创建订阅者回调
    commonEventManager.createSubscriber(subscribeInfo,
      (err: BusinessError, commonEventSubscriber: commonEventManager.CommonEventSubscriber) => {
        if (err) {
          hilog.error(0x0000, 'testTag', '%{public}s', `CreateSubscriber error, ${err.code}, message: ${err.message}}`);
          return;
        }
        hilog.info(0x0000, 'testTag', '%{public}s', 'Succeeded in creating subscriber');
        this.subscriber = commonEventSubscriber;
        // 订阅公共事件回调
        if (!this.subscriber) {
          hilog.warn(0x0000, 'testTag', '%{public}s', 'Need to create subscriber');
          return;
        }
        commonEventManager.subscribe(this.subscriber,
          (err: BusinessError, commonEventData: commonEventManager.CommonEventData) => {
            if (err) {
              hilog.error(0x0000, 'testTag', '%{public}s', `Subscribe error, ${err.code}, message: ${err.message}`);
            } else {
              // 订阅者成功接收到公共事件
              // 获取插屏广告页面变化状态
              const status: string = commonEventData?.parameters?.[KEY_INTERSTITIAL_STATUS];
              switch (status) {
                case AdStatus.AD_OPEN:
                  console.info('onAdOpen');
                  break;
                case AdStatus.AD_CLICKED:
                  console.info('onAdClick');
                  break;
                case AdStatus.AD_CLOSED:
                  console.info('onAdClose');
                  this.unRegisterPPSReceiver();
                  break;
                case AdStatus.AD_VIDEO_START:
                  console.info('onAdVideoStart');
                  break;
                case AdStatus.AD_COMPLETED:
                  console.info('onAdCompleted');
                  break;
                default:
                  break;
              }
            }
          });
      });
  }

  // 取消订阅
  public unRegisterPPSReceiver(): void {
    commonEventManager.unsubscribe(this.subscriber, (err: BusinessError) => {
      if (err) {
        hilog.error(0x0000, 'testTag', '%{public}s', `Unsubscribe error, ${err.code}, message: ${err.message}}`);
      } else {
        hilog.info(0x0000, 'testTag', '%{public}s', 'Succeeded in unsubscribing');
        this.subscriber = null;
      }
    });
  }
}

export const InterstitialAd = new InterstitialAdUtil()

enum AdStatus {
  AD_OPEN = 'onAdOpen',
  AD_CLICKED = 'onAdClick',
  AD_CLOSED = 'onAdClose',
  AD_VIDEO_START = 'onVideoPlayBegin',
  AD_COMPLETED = 'onVideoPlayEnd'
}

2.3 开发使用

2.3.1 请求广告

  private requestAd(adLoader: advertising.AdLoader): void {
    const adRequestParam: advertising.AdRequestParams = {
      // 广告类型:插屏广告
      adType: 12,
      // 'testb4znbuh3n2'为测试专用的广告位ID,App正式发布时需要改为正式的广告位ID
      adId: 'testb4znbuh3n2',
      // 开放匿名设备标识符
      oaid: this.oaid
    };
    const adOption: advertising.AdOptions = {
      // 设置是否请求非个性化广告
      nonPersonalizedAd: 0,
      // 是否允许流量下载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'
    };
    const adLoaderListener: advertising.AdLoadListener = {
      onAdLoadFailure: (errorCode: number, errorMsg: string) => {
        hilog.error(0x0000, 'testTag', '%{public}s',
          `Failed to request ad, message: ${errorMsg}, error code: ${errorCode}`);
      },
      onAdLoadSuccess: (ads: Array<advertising.Advertisement>) => {
        hilog.info(0x0000, 'testTag', '%{public}s', 'Succeeded in requesting ad!');
        this.ads = [];
        this.ads.push(...ads);
      },
    };
    adLoader.loadAd(adRequestParam, adOption, adLoaderListener);
  }

2.3.2 展示广告

  1. 展示时期

由于我们不清楚广告参数什么时候请求成功,我们可以监听存储广告参数的数组ads,当ads的长度不为空时,就可以展示广告advertising.showAd

import { advertising, identifier } from '@kit.AdsKit';
import { common } from '@kit.AbilityKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
import { BusinessError } from '@kit.BasicServicesKit';

@Entry
@Component
struct Index {
  private ads: Array<advertising.Advertisement> = [];
  private context = getContext(this) as common.UIAbilityContext;
  private oaid: string = '';
  private displayOptions: advertising.AdDisplayOptions = {
    // 插屏广告视频播放是否静音
    mute: true
  };
  @State index: number = 0

  aboutToAppear() {
    try {
      // 使用Promise回调方式获取OAID
      identifier.getOAID().then((data) => {
        this.oaid = data;
        hilog.info(0x0000, 'testTag', '%{public}s', 'Succeeded in getting adsIdentifierInfo by promise');
      }).catch((error: BusinessError) => {
        hilog.error(0x0000, 'testTag', '%{public}s', `Failed to get adsIdentifierInfo, message: ${error.message}`);
      })
    } catch (error) {
      hilog.error(0x0000, 'testTag', '%{public}s', `Catch err, code: ${error.code}, message: ${error.message}`);
    }
    let load: advertising.AdLoader = new advertising.AdLoader(this.context);
    this.requestAd(load);

    //监听广告数组长度来判断广告的出现时期
    this.showAd()

  }

  build() {
    Column() {

    }
    .width('100%')
    .height('100%')
    .justifyContent(FlexAlign.Center)
  }

  private showAd() {
    // 请在此处自行增加步骤3中的,注册插屏广告状态监听器
    // ...
    // InterstitialAd.registerPPSReceiver()
    // 此处ads[0]表示请求到的第一个广告,用户根据实际情况选择
    advertising.showAd(this.ads[0], this.displayOptions, this.context);
  }

  private requestAd(adLoader: advertising.AdLoader): void {
    const adRequestParam: advertising.AdRequestParams = {
      // 广告类型:插屏广告
      adType: 12,
      // 'testb4znbuh3n2'为测试专用的广告位ID,App正式发布时需要改为正式的广告位ID
      adId: 'testb4znbuh3n2',
      // 开放匿名设备标识符
      oaid: this.oaid
    };
    const adOption: advertising.AdOptions = {
      // 设置是否请求非个性化广告
      nonPersonalizedAd: 0,
      // 是否允许流量下载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'
    };
    const adLoaderListener: advertising.AdLoadListener = {
      onAdLoadFailure: (errorCode: number, errorMsg: string) => {
        hilog.error(0x0000, 'testTag', '%{public}s',
          `Failed to request ad, message: ${errorMsg}, error code: ${errorCode}`);
      },
      onAdLoadSuccess: (ads: Array<advertising.Advertisement>) => {
        hilog.info(0x0000, 'testTag', '%{public}s', 'Succeeded in requesting ad!');
        this.ads = [];
        this.ads.push(...ads);
      },
    };
    adLoader.loadAd(adRequestParam, adOption, adLoaderListener);
  }
}
  1. 效果展示

总结

今天介绍了广告服务中的两个,目前我们已经掌握了广告服务,如果对这方面还有疑惑,欢迎在评论区留言或者加入我们组织,组织里很多厉害的大佬!如果我的内容对您有帮助,可以点赞、关注+收藏,谢谢大家!如果小伙伴对鸿蒙的其他内容感兴趣,欢迎加入我们青蓝逐码!

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

昨天 — 2025年5月17日首页
❌
❌