纯血鸿蒙开发之广告服务(1)
纯血鸿蒙开发之广告服务(1)
大家好,我是青蓝逐码的云杰,今天我想来聊一聊学习一下鸿蒙的广告服务!
Ads Kit(广告服务)
Ads Kit(广告服务)依托华为终端平台与数据能力为您提供流量变现服务,帮助您解决流量变现的难题;同时为广告主提供广告服务,配合华为终端平台向用户提供个性化的营销活动或商业广告。
鲸鸿动能流量变现服务(以下简称流量变现服务)是广告服务依托华为终端强大的平台与数据能力为您提供的App流量变现服务,您通过该服务可以在自己的App中获取并向用户展示精美的、高价值的广告内容,并从中获得广告收益。 为满足App不同场景下的内容形式,流量变现服务提供了横幅广告、原生广告、激励广告、插屏广告、开屏广告、贴片广告六种广告形式。
广告形式 | 展示形式 | 应用场景 |
---|---|---|
横幅广告 | 图片 | 以通知栏或矩形固定展示在应用内页面顶部、中部或底部,适合用于用户停留较久或者访问频繁的页面。 |
原生广告 | 图片、视频 | 界面内插入广告,与媒体内容无缝融合。 |
激励广告 | 视频 | 游戏通关、复活、获取道具、积分、继续机会、人物技能升级时等展示。 |
插屏广告 | 图片、视频 | 游戏或流媒体开启、暂停、过关、跳转、加载、退出时弹出。 |
开屏广告 | 图片、视频 | 打开App时,以开屏形式全屏展现,展示时长3s-5s,展示完毕后自动关闭并进入应用主页面。 |
贴片广告 | 图片、视频 | 前贴:视频播放前。中贴:视频播放中。后贴:视频播放结束后。说明:您可以根据自身需求设置广告的播放时长。 |
具体如何进入这项服务,我在之前的文章中专门介绍过接入广告服务,这里就不过多介绍这个,本系列文章主要介绍的是广告的使用和展示
广告展示
1.横幅广告
横幅广告又名Banner广告,是在应用程序顶部、中部或底部占据一个位置的矩形图片,广告内容每隔一段时间会自动刷新。
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'); });
-
请求和展示广告。
在您的页面中使用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为半屏广告。 |
说明
- 如果超时没有请求到广告,应用自行跳转到默认首页。
- 为保证开屏展示效果,建议开发者在请求广告前,设置屏幕方向为竖屏。
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 开屏(全屏)广告展示
- 解释广告请求时间点
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()
}
- 全屏广告页面
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'
}
-
效果展示
2.2.4 开屏(半屏)广告展示
- 解释广告请求时间点
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()
}
-
半屏广告页面
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' }
-
效果展示
后续
今天介绍了广告服务中的两个,后续也会继续学习剩余的广告服务;如果我的内容对您有帮助,可以点赞、关注+收藏,谢谢大家!如果小伙伴对鸿蒙的其他内容感兴趣,欢迎加入我们青蓝逐码!
青蓝逐码官网:https://www.qinglanzhuma.cn/
- 0回答
- 0粉丝
- 0关注
- 纯血鸿蒙开发之广告服务(2)
- 真正的纯血鸿蒙开发者是怎样开发应用的?纯血鸿蒙到底”纯“在哪里?
- 鸿蒙免广告框架
- 元服务—实践篇(1)
- IOS Android Harmonyos next 纯代码布局对比纯手撸
- 元服务——1、概念与环境
- 「Mac畅玩鸿蒙与硬件1」鸿蒙开发环境配置篇1 - 认识鸿蒙系统与开发工具
- 鸿蒙元服务实战-笑笑五子棋(1)
- HarmonyOS NEXT应用开发指南:开屏广告的使用
- 鸿蒙地图功能开发【1. 开发准备】##地图开发##
- 鸿蒙开发:权限管理之权限声明
- 鸿蒙开发:权限管理之授权方式
- HarmonyOS Next应用开发实战:广告的使用介绍及避坑指南
- 如何快速判断 Flutter 库是否需要适配鸿蒙?纯 Dart 库无需适配!
- HarmonyOS 5.0元服务原来是这样的(1)!!