场景介绍
贴片广告是一种在视频播放前、视频播放中或视频播放结束后插入的视频或图片广告。

接口说明
|   接口名  |   描述  | 
|---|---|
|   loadAd(adParam: AdRequestParams, adOptions: AdOptions, listener: AdLoadListener): void  |   请求单广告位广告,通过AdRequestParams、AdOptions进行广告请求参数设置,通过AdLoadListener监听广告请求回调。  | 
|   AdComponent(ads: advertising.Advertisement[], displayOptions: advertising.AdDisplayOptions, interactionListener: advertising.AdInteractionListener, @BuilderParam adRenderer?: () => void): void  |   展示广告,通过AdDisplayOptions进行广告展示参数设置,通过AdInteractionListener监听广告状态回调。  | 
开发步骤
- 获取OAID。  
如果想要为用户更精准的推送广告,可以在请求参数AdRequestParams中添加oaid属性。
如何获取OAID参见获取OAID信息。
说明
使用以下示例中提供的测试广告位必须先获取OAID信息。
 - 请求单广告位广告。  
需要创建一个AdLoader对象,通过AdLoader的loadAd方法请求广告,最后通过AdLoadListener来监听广告的加载状态。
在请求贴片广告时,需要在AdOptions中设置两个参数:totalDuration和placementAdCountDownDesc。
请求广告关键参数如下所示:
示例代码如下所示:请求广告参数名
类型
必填
说明
adType
number
是
请求广告类型,贴片广告类型为60。
adId
string
是
广告位ID。
- 如果仅调测广告,可使用测试广告位ID:testy3cglm3pj0。
 - 如果要接入正式广告,则需要申请正式的广告位ID。可在应用发布前进入流量变现官网,点击“开始变现”,登录鲸鸿动能媒体服务平台进行申请,具体操作详情请参见展示位创建。
 
oaid
string
否
开放匿名设备标识符,用于精准推送广告。不填无法获取到个性化广告。
- import { advertising, identifier } from '@kit.AdsKit';
 - import { common } from '@kit.AbilityKit';
 - import { hilog } from '@kit.PerformanceAnalysisKit';
 - import { BusinessError } from '@kit.BasicServicesKit';
 - import { router } from '@kit.ArkUI';
 - @Entry
 - @Component
 - struct Index {
 - private context: common.UIAbilityContext = getContext(this) as common.UIAbilityContext;
 - // 获取到的OAID
 - private oaid: string = '';
 - aboutToAppear() {
 - try {
 - // 使用Promise回调方式获取OAID
 - identifier.getOAID().then((data: string) => {
 - 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, code: ${error.code}, message: ${error.message}`);
 - })
 - } catch (error) {
 - hilog.error(0x0000, 'testTag', '%{public}s', `Catch err, code: ${error.code}, message: ${error.message}`);
 - }
 - }
 - build() {
 - Row() {
 - Button('加载广告', { type: ButtonType.Normal, stateEffect: true })
 - .onClick(() => {
 - // 调用加载广告方法
 - requestAd(this.context, this.oaid);
 - })
 - .borderRadius(8)
 - .backgroundColor(0x317aff)
 - .width(90)
 - .height(40)
 - }
 - .height('100%')
 - }
 - }
 - /**
 - * 加载广告
 - *
 - * @param context 上下文环境
 - * @param oaid OAID信息
 - */
 - function requestAd(context: common.Context, oaid: string): void {
 - const adRequestParam: advertising.AdRequestParams = {
 - // 广告类型
 - adType: 60,
 - // 'testy3cglm3pj0'为测试专用的广告位ID,App正式发布时需要改为正式的广告位ID
 - adId: 'testy3cglm3pj0',
 - // 在AdRequestParams中添加oaid参数
 - oaid: oaid,
 - // 用于区分普通请求和预加载请求,默认值false代表普通请求,true代表预加载请求
 - isPreload: false
 - };
 - const adOptions: advertising.AdOptions = {
 - // 在AdOptions中添加totalDuration参数,用于设置贴片广告展示时长(贴片广告必填)
 - totalDuration: 30,
 - // 在AdOptions中添加placementAdCountDownDesc参数,设置贴片广告倒计时文案(可选,填写了则展示文案,不填写则只展示倒计时)
 - placementAdCountDownDesc: encodeURI('VIP免广告'),
 - // 是否允许流量下载 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 single ad, errorCode is: ${errorCode}, errorMsg is: ${errorMsg}`);
 - },
 - // 广告请求成功回调
 - onAdLoadSuccess: (ads: Array<advertising.Advertisement>) => {
 - hilog.info(0x0000, 'testTag', '%{public}s', 'Succeeded in requesting single ad!');
 - // 保存请求到的广告内容用于展示
 - const returnAds = ads;
 - // 路由到广告展示页面
 - routePage('pages/PlacementAdPage', returnAds);
 - }
 - };
 - // 创建AdLoader广告对象
 - const load: advertising.AdLoader = new advertising.AdLoader(context);
 - // 调用广告请求接口
 - hilog.info(0x0000, 'testTag', '%{public}s', 'Request single ad!');
 - load.loadAd(adRequestParam, adOptions, adLoaderListener);
 - }
 - /**
 - * 路由跳转
 - *
 - * @param pageUri 要路由到的页面
 - */
 - async function routePage(pageUri: string, ads: Array<advertising.Advertisement | null>) {
 - let options: router.RouterOptions = {
 - url: pageUri,
 - params: {
 - ads: ads
 - }
 - }
 - try {
 - hilog.info(0x0000, 'testTag', '%{public}s', `RoutePage: ${pageUri}`);
 - router.pushUrl(options);
 - } catch (error) {
 - hilog.error(0x0000, 'testTag', '%{public}s',
 - `Failed to routePage callback, code: ${error.code}, msg: ${error.message}`);
 - }
 - }
 
 - 展示广告。  
在您的页面中使用AdComponent组件展示贴片广告,由媒体判断流量场景下,可以自动播放则展示广告,反之则不展示。以前贴广告为例,前贴广告播放完成后进入正片播放。您需要在entry/src/main/resources/base/profile/main_pages.json文件中添加页面,如下图所示。

您需要在media和rawfile目录下分别指定正片未播放时的预览图video_preview.PNG和对应的正片文件videoTest.mp4,如下图所示。
示例代码如下所示:
- import { router, window } from '@kit.ArkUI';
 - import { BusinessError } from '@kit.BasicServicesKit';
 - import { advertising, AdComponent } from '@kit.AdsKit';
 - import { hilog } from '@kit.PerformanceAnalysisKit';
 - @Entry
 - @Component
 - export struct PlacementAdPage {
 - // 是否竖屏
 - private portrait: boolean = true;
 - // 请求到的广告内容
 - private ads: Array<advertising.Advertisement> = [];
 - // 广告展示参数
 - private adDisplayOptions: advertising.AdDisplayOptions = {
 - // 是否静音,默认不静音
 - mute: false
 - }
 - // 广告参数
 - private adOptions: advertising.AdOptions = {
 - // 设置贴片广告展示时长(贴片广告必填)
 - totalDuration: 30,
 - // 设置贴片广告倒计时文案,文案需要使用encodeURI编码(可选,填写了则展示文案,不填写则只展示倒计时)
 - placementAdCountDownDesc: encodeURI('VIP免广告'),
 - // 是否希望根据 COPPA 的规定将您的内容视为面向儿童的内容: -1默认值,不确定 0不希望 1希望
 - tagForChildProtection: -1,
 - // 是否希望按适合未达到法定承诺年龄的欧洲经济区 (EEA) 用户的方式处理该广告请求: -1默认值,不确定 0不希望 1希望
 - tagForUnderAgeOfPromise: -1,
 - // 设置广告内容分级上限: W: 3+,所有受众 PI: 7+,家长指导 J:12+,青少年 A: 16+/18+,成人受众
 - adContentClassification: 'A'
 - }
 - // 已经播放的贴片广告数量
 - private playedAdSize: number = 0;
 - // 是否播放正片
 - @State isPlayVideo: boolean = false;
 - // 视频播放控制器
 - private controller: VideoController = new VideoController();
 - // 指定视频未播放时的预览图片路径
 - private previewUris: Resource = $r('app.media.video_preview');
 - // 指定视频播放源的路径,这里取本地视频资源
 - private innerResource: Resource = $rawfile('videoTest.mp4');
 - // 用于渲染右上角倒计时
 - private countDownTxtPlaceholder: string = '%d | %s';
 - @State countDownTxt: string = '';
 - aboutToAppear() {
 - const params: Record<string, Object> = router.getParams() as Record<string, Object>;
 - if (params && params.ads as Array<advertising.Advertisement>) {
 - this.ads = params.ads as Array<advertising.Advertisement>;
 - this.adOptions = params.adOptions as advertising.AdOptions;
 - this.initData();
 - }
 - }
 - build() {
 - Stack({ alignContent: Alignment.TopEnd }) {
 - // AdComponent组件用于展示非全屏广告
 - AdComponent({
 - ads: this.ads, displayOptions: this.adDisplayOptions,
 - interactionListener: {
 - // 广告状态变化回调
 - onStatusChanged: (status: string, ad: advertising.Advertisement, data: string) => {
 - switch (status) {
 - case 'onPortrait':
 - hilog.info(0x0000, 'testTag', '%{public}s', 'Status is onPortrait');
 - // 设置屏幕方向为竖屏或返回上一页
 - this.setWindowPortrait();
 - break;
 - case 'onLandscape':
 - hilog.info(0x0000, 'testTag', '%{public}s', 'Status is onLandscape');
 - // 设置屏幕方向为横屏
 - this.setWindowLandscape();
 - break;
 - case 'onMediaProgress':
 - hilog.info(0x0000, 'testTag', '%{public}s', 'Status is onMediaProgress');
 - break;
 - case 'onMediaStart':
 - hilog.info(0x0000, 'testTag', '%{public}s', 'Status is onMediaStart');
 - break;
 - case 'onMediaPause':
 - hilog.info(0x0000, 'testTag', '%{public}s', 'Status is onMediaPause');
 - break;
 - case 'onMediaStop':
 - hilog.info(0x0000, 'testTag', '%{public}s', 'Status is onMediaStop');
 - break;
 - case 'onMediaComplete':
 - hilog.info(0x0000, 'testTag', '%{public}s', 'Status is onMediaComplete');
 - // 所有广告都播放完毕后,开始播放正片
 - this.playedAdSize++;
 - if (this.playedAdSize === this.ads.length) {
 - this.isPlayVideo = true;
 - }
 - break;
 - case 'onMediaError':
 - hilog.error(0x0000, 'testTag', '%{public}s', 'Status is onMediaError');
 - break;
 - case 'onMediaCountdown':
 - try {
 - hilog.info(0x0000, 'testTag', '%{public}s', 'Status is onMediaCountdown');
 - const parseData: Record<string, number> = JSON.parse(JSON.stringify(data));
 - this.updateCountDownTxt(parseData.countdownTime);
 - } catch (e) {
 - hilog.error(0x0000, 'testTag', '%{public}s',
 - `Failed to parse data, code: ${e.code}, msg: ${e.message}`);
 - }
 - break;
 - }
 - }
 - }
 - })
 - .visibility(!this.isPlayVideo ? Visibility.Visible : Visibility.None)
 - .width('100%')
 - .height('100%')
 - Row() {
 - if (this.countDownTxt) {
 - Text(this.countDownTxt.split('').join('\u200B'))
 - .fontSize(12)
 - .textAlign(TextAlign.Center)
 - .maxLines(1)
 - .fontColor(Color.White)
 - .lineHeight(12)
 - .textOverflow({ overflow: TextOverflow.Ellipsis })
 - .maxLines(1)
 - .backgroundColor('#66000000')
 - .border({ radius: 25 })
 - .padding({
 - left: 8,
 - right: 8,
 - top: 6,
 - bottom: 6
 - })
 - .margin({ right: 16, top: 16 })
 - .height(24)
 - .constraintSize({ minWidth: 60, maxWidth: 100 })
 - .onClick((event: ClickEvent) => {
 - hilog.info(0x0000, 'testTag', '%{public}s', 'OnVipClicked, do something...');
 - })
 - }
 - }
 - .alignItems(VerticalAlign.Top)
 - .justifyContent(FlexAlign.End)
 - Video({
 - src: this.innerResource,
 - previewUri: this.previewUris,
 - controller: this.controller
 - })
 - .visibility(this.isPlayVideo ? Visibility.Visible : Visibility.None)
 - .autoPlay(this.isPlayVideo ? true : false)
 - .controls(false)
 - .width('100%')
 - .height('100%')
 - }.width('100%').height('100%')
 - }
 - /**
 - * 设置竖屏或返回上一页
 - */
 - private setWindowPortrait() {
 - hilog.info(0x0000, 'testTag', '%{public}s', `Set WindowPortrait, portrait: ${this.portrait}`);
 - if (!this.portrait) {
 - window.getLastWindow(getContext(this), (err: BusinessError, win) => {
 - win.setPreferredOrientation(window.Orientation.PORTRAIT)
 - });
 - this.portrait = true;
 - } else {
 - router.back();
 - }
 - }
 - /**
 - * 设置横屏(正向)
 - */
 - private setWindowLandscape() {
 - hilog.info(0x0000, 'testTag', '%{public}s', `Set WindowLandscape, portrait: ${this.portrait}`);
 - if (this.portrait) {
 - window.getLastWindow(getContext(this), (err: BusinessError, win) => {
 - win.setPreferredOrientation(window.Orientation.LANDSCAPE)
 - });
 - this.portrait = false;
 - }
 - }
 - private initData() {
 - this.initCountDownText();
 - }
 - private initCountDownText() {
 - const decodeText = this.decodeString(this.adOptions?.placementAdCountDownDesc as string);
 - if (!this.isBlank(decodeText)) {
 - this.countDownTxtPlaceholder = this.countDownTxtPlaceholder.replace('%s', decodeText);
 - } else {
 - this.countDownTxtPlaceholder = '%d';
 - }
 - }
 - private updateCountDownTxt(leftTime: number) {
 - hilog.info(0x0000, 'testTag', '%{public}s', `Show LeftTime: ${leftTime}`);
 - this.countDownTxt = this.countDownTxtPlaceholder.replace('%d', leftTime + '');
 - }
 - private decodeString(str: string): string {
 - if (!str) {
 - return str;
 - }
 - let decodeUrl = str;
 - try {
 - decodeUrl = decodeURIComponent(str.replace(/\+/g, '%20'));
 - } catch (e) {
 - hilog.error(0x0000, 'testTag', '%{public}s', `Failed to decodeURIComponent, code:${e.code}, msg: ${e.message}`);
 - }
 - return decodeUrl;
 - }
 - private isBlank(str: string): boolean {
 - if (str === null || str === undefined) {
 - return true;
 - }
 - if (typeof str === 'string') {
 - return str.trim().length === 0;
 - }
 - return false;
 - }
 - }
 
 



















