在移动应用商业化进程中,广告服务是重要的变现途径,但不当的广告集成往往会破坏用户体验,甚至违反平台合规要求。HarmonyOS 针对广告服务提供了系统化的解决方案,支持 6 类主流广告形式,并明确了合规与体验平衡的实践标准。这篇文章我将基于华为开发者学院相关课程内容,从广告形式场景化选型、开发流程、合规风险规避三个维度,为大家总结广告服务集成方案。
文章目录
- [一、广告形式场景化选型:匹配 App 功能与用户习惯](#一、广告形式场景化选型:匹配 App 功能与用户习惯)
-
- [1. Banner 广告:工具类 App 的 "轻量之选"](#1. Banner 广告:工具类 App 的 “轻量之选”)
- [2. 原生广告:内容类 App 的 "融合之选"](#2. 原生广告:内容类 App 的 “融合之选”)
- [3. 激励广告:游戏 / 工具类 App 的 "共赢之选"](#3. 激励广告:游戏 / 工具类 App 的 “共赢之选”)
- [4. 插屏广告:场景切换时的 "高效之选"](#4. 插屏广告:场景切换时的 “高效之选”)
- [5. 开屏广告:流量入口的 "曝光之选"](#5. 开屏广告:流量入口的 “曝光之选”)
- [6. 贴片广告:视频类 App 的 "内容绑定之选"](#6. 贴片广告:视频类 App 的 “内容绑定之选”)
- [二、开发前置准备:权限与 SDK 配置](#二、开发前置准备:权限与 SDK 配置)
-
- [1. 权限声明与动态申请](#1. 权限声明与动态申请)
- [2. 导入广告 SDK](#2. 导入广告 SDK)
- 三、激励广告完整流程
-
- [1. 页面结构定义(UI 部分)](#1. 页面结构定义(UI 部分))
- [2. 广告初始化与加载(逻辑部分)](#2. 广告初始化与加载(逻辑部分))
- [3. 广告展示与奖励发放](#3. 广告展示与奖励发放)
- [四、ArkTS 多广告形式扩展:Banner 与原生广告](#四、ArkTS 多广告形式扩展:Banner 与原生广告)
-
- [1. Banner 广告](#1. Banner 广告)
- [五、 广告开发注意事项](#五、 广告开发注意事项)
- [六、 总结](#六、 总结)
一、广告形式场景化选型:匹配 App 功能与用户习惯
HarmonyOS 广告服务的 6 类广告形式各有特性,开发者需结合 App 的业务场景、用户交互节奏及核心功能,选择最适配的广告类型,避免 "为加广告而加广告" 的误区。以下为不同广告形式的场景化选型指南:
1. Banner 广告:工具类 App 的 "轻量之选"

Banner 广告以固定在页面顶部或底部的横幅形态存在,尺寸小巧(典型 320×50px),持续展示但不打断用户操作,适合核心功能为 "工具使用" 的 App。例如:
天气 App 的首页底部:用户查看天气时,Banner 广告位于视觉边缘,不影响温度、预警信息的核心阅读;
计算器 App 的结果展示区下方:用户输入计算指令时,广告不会遮挡数字键盘或计算结果;
待办清单 App 的任务列表顶部:滚动查看任务时,Banner 广告位置固定,避免随内容滚动频繁晃动。
选型关键:需确保 Banner 广告与页面背景色有轻微区分(如浅灰色背景),同时避免在同一页面叠加多个 Banner------ 例如部分工具 App 为追求收益,在顶部和底部同时放置 Banner,导致中间核心功能区被挤压,用户体验大幅下降。
2. 原生广告:内容类 App 的 "融合之选"

原生广告的核心优势是 "形态自定义",可根据 App 界面风格调整字体、配色、布局,让广告内容与原生内容无缝融合,适合以 "信息流" 为核心的内容类 App。典型应用场景包括:
社交 App 的动态列表:将原生广告设计为 "好友动态卡片" 样式,仅在右上角标注 "广告" 标识,用户滑动浏览时无明显割裂感;
电商 App 的商品推荐页:原生广告以 "商品卡片" 形态插入推荐列表,图片尺寸、价格字体与普通商品一致,仅通过 " Sponsored" 标签区分;
资讯 App 的文章列表:原生广告标题字体、摘要长度与普通文章统一,点击后跳转至广告落地页,避免用户因 "广告突兀" 产生抵触。
选型关键:自定义程度越高,越需注意合规边界 ------ 根据 HarmonyOS 广告规范,原生广告必须在明显位置标注 "广告" 或 " Sponsored" 标识,且标识颜色需与正文区分(如红色 "广告" 标签),禁止通过 "隐藏标识" 误导用户点击。
3. 激励广告:游戏 / 工具类 App 的 "共赢之选"

激励广告以 "用户完成指定行为获取奖励" 为核心逻辑,用户主动参与度高,适合需要 "用户付费解锁功能" 或 "虚拟道具变现" 的场景:
游戏 App:用户观看 30 秒视频广告后,获取游戏币、复活机会或解锁新关卡,相比 "强制付费" 更易被用户接受;
图片处理 App:用户点击广告后,解锁 "去除水印""高清导出" 等高级功能,替代传统 "付费会员" 模式;
小说阅读 App:用户观看广告后,获取 "免费阅读 1 章" 的权限,平衡免费用户体验与商业化需求。
选型关键:奖励的 "即时性" 是用户接受度的核心 ------ 例如游戏 App 需在广告播放完成后,立即弹出 "奖励已到账" 提示,并同步更新游戏内道具数量;若出现 "广告完成但奖励未到账" 的情况,会严重损害用户信任,甚至导致 App 被投诉。
4. 插屏广告:场景切换时的 "高效之选"

插屏广告在应用场景切换时(如页面跳转、功能完成)弹出,全屏或半屏展示,单次曝光强度高,适合 "用户操作间隙" 的场景:
游戏 App:关卡结束结算时弹出插屏广告,此时用户处于 "等待结果" 状态,广告不会打断游戏操作;
阅读 App:章节切换加载时弹出广告,利用 "内容加载时间" 展示广告,减少对阅读节奏的影响;
文件管理 App:文件导出成功后弹出广告,用户完成核心操作(导出文件)后,对广告的容忍度更高。
选型关键:控制弹出频率是避免用户反感的核心 ------ 建议同一用户 1 小时内插屏广告弹出不超过 2 次,且必须提供明显的 "关闭" 按钮(如右上角红色圆形关闭图标,尺寸不小于 48×48px),禁止 "强制观看满时长才能关闭" 的设计。
5. 开屏广告:流量入口的 "曝光之选"

开屏广告在 App 启动时展示,持续 3-5 秒,是曝光量最大的广告形式,适合各类 App 的 "启动流量变现":
社交 App:启动时展示 3 秒动态开屏广告,3 秒后出现 "跳过" 按钮,用户可选择 "观看获取奖励" 或 "直接跳过";
电商 App:大促期间(如 618、双 11),开屏广告展示促销活动信息,点击后直接跳转至活动主会场;
工具 App:启动时展示静态开屏广告,背景图与 App 品牌色调一致,避免因 "风格冲突" 影响品牌认知。
选型关键:启动速度优先于广告展示 ------ 需提前预加载开屏广告资源(如在 App 前一次退出时缓存广告图片 / 视频),避免因 "广告加载缓慢" 延长 App 启动时间;根据 HarmonyOS 性能规范,App 冷启动时间需控制在 3 秒内,开屏广告加载不可导致启动时间超过 5 秒。
6. 贴片广告:视频类 App 的 "内容绑定之选"

贴片广告嵌入在视频内容中,分为前贴片(视频播放前)、中贴片(播放中)、后贴片(播放后),适合以 "视频内容" 为核心的 App:
短视频 App:15 秒短视频播放前,展示 5 秒前贴片广告,点击 "跳过" 按钮可直接观看视频;
教育 App:课程视频播放中,每 20 分钟插入 1 个 15 秒中贴片广告,利用 "学习间隙" 减少干扰;
影视 App:电影播放结束后,展示后贴片广告,推荐 "同类影片" 或 "影视周边",用户接受度较高。
选型关键:时长与插入时机需匹配视频长度 ------ 前贴片建议≤5 秒(短视频)或≤15 秒(长视频),中贴片需避免在 "剧情高潮" 或 "知识点关键处" 插入,例如教育 App 可在 "章节总结" 后插入中贴片广告,不影响核心知识点学习。
二、开发前置准备:权限与 SDK 配置
1. 权限声明与动态申请
(1)配置module.json5权限
ArkTS 项目需在src/main/module.json5中声明广告服务所需权限,相比 Java 项目的config.json,module.json5支持更清晰的权限分类:
bash
{
"module": {
"reqPermissions": [
{
"name": "ohos.permission.INTERNET", // 必选:加载广告资源
"reason": "用于获取广告素材和数据",
"usedScene": { "ability": ["MainAbility"], "when": "always" }
},
{
"name": "ohos.permission.WRITE_USER_STORAGE", // 可选:缓存广告素材
"reason": "用于缓存广告图片和视频,提升加载速度",
"usedScene": { "ability": ["MainAbility"], "when": "always" },
"grantMode": "user_grant" // 需用户授权的权限
},
{
"name": "ohos.permission.READ_USER_STORAGE", // 可选:读取缓存
"reason": "读取缓存的广告素材",
"usedScene": { "ability": ["MainAbility"], "when": "always" },
"grantMode": "user_grant"
}
]
}
}
(2)动态申请用户授权权限
存储权限属于 "用户授权权限",需在 ArkTS 页面中通过requestPermissionsFromUser方法动态申请,避免直接使用导致权限报错:
bash
import abilityAccessCtrl from '@ohos.abilityAccessCtrl';
import bundle from '@ohos.bundle';
// 动态申请存储权限
async function requestStoragePermission() {
const permissions = ['ohos.permission.WRITE_USER_STORAGE', 'ohos.permission.READ_USER_STORAGE'];
const atManager = abilityAccessCtrl.createAtManager();
const bundleInfo = await bundle.getBundleInfoForSelf(bundle.BundleFlag.GET_BUNDLE_INFO_WITH_APPLICATION);
const appInfo = bundleInfo.appInfo;
// 检查权限是否已授权
for (const permission of permissions) {
const status = await atManager.checkAccessToken(appInfo.accessTokenId, permission);
if (status !== abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED) {
// 未授权则发起申请
const result = await atManager.requestPermissionsFromUser(getContext(), permissions);
if (result.authResults[0] !== abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED) {
// 用户拒绝授权:提示"无法缓存广告,可能影响加载速度"
promptAction.showToast({ message: '请授予存储权限以优化广告体验' });
return false;
}
}
}
return true;
}
2. 导入广告 SDK
从华为开发者联盟官网下载 HarmonyOS 广告服务 ArkTS SDK(通常为ad-sdk-arkts.har),将其复制到项目src/main/libs目录下;
在src/main/module.json5中添加 SDK 依赖,确保编译器能识别 SDK 中的 ArkTS 类:
bash
{
"module": {
"dependencies": [
{
"name": "ad-sdk-arkts",
"type": "har",
"source": "local",
"version": "1.0.0" // 与SDK实际版本一致
}
]
}
}
同步项目(点击 IDE 中的 "Sync Now"),确保无 "模块未找到" 的编译错误。
三、激励广告完整流程
这里用激励广告举例,它是 ArkTS 项目中最常用的广告形式之一,以下从 "初始化→加载→展示→奖励发放" 全流程,提供可直接复用的代码:
1. 页面结构定义(UI 部分)
首先在 ArkTS 页面中定义 "观看广告获取奖励" 按钮,以及奖励展示区域:
bash
import promptAction from '@ohos.promptAction';
import { IncentiveAd, AdParam, AdDisplayListener, IncentiveAdListener, Reward } from '@huawei/hms.ads';
@Entry
@Component
struct IncentiveAdPage {
// 状态变量:广告是否加载完成、当前游戏币数量
@State isAdLoaded: boolean = false;
@State coinCount: number = 0;
// 激励广告实例
private incentiveAd: IncentiveAd | null = null;
// 测试广告单元ID(上线前替换为正式ID)
private readonly AD_UNIT_ID: string = 'testx9dtjwj8hp';
build() {
Column({ space: 20 }) {
// 奖励展示区域
Text(`当前游戏币:${this.coinCount}`)
.fontSize(20)
.fontWeight(FontWeight.Bold);
// 广告展示按钮(加载完成前禁用)
Button('观看广告获取10游戏币')
.width(280)
.height(50)
.fontSize(16)
.enabled(this.isAdLoaded)
.onClick(() => this.showIncentiveAd())
.backgroundColor(this.isAdLoaded ? '#007DFF' : '#CCCCCC');
}
.width('100%')
.height('100%')
.justifyContent(FlexAlign.Center)
.onPageShow(() => {
// 页面显示时初始化广告
this.initIncentiveAd();
})
.onPageHide(() => {
// 页面隐藏时销毁广告,避免内存泄漏
this.destroyIncentiveAd();
});
}
}
2. 广告初始化与加载(逻辑部分)
在页面类中补充广告初始化、加载的核心方法,通过监听onAdLoaded和onAdFailed事件处理加载状态:
bash
// 初始化激励广告
private async initIncentiveAd() {
// 先申请存储权限(可选,但推荐)
const hasPermission = await requestStoragePermission();
if (!hasPermission) return;
// 创建激励广告实例
this.incentiveAd = IncentiveAd.createIncentiveAd(this.AD_UNIT_ID);
if (!this.incentiveAd) {
promptAction.showToast({ message: '广告初始化失败' });
return;
}
// 设置广告加载监听器
this.incentiveAd.setAdLoadListener({
onAdLoaded: () => {
// 广告加载成功:更新按钮状态
this.isAdLoaded = true;
promptAction.showToast({ message: '广告已就绪,点击按钮观看' });
},
onAdFailed: (errorCode: number) => {
// 广告加载失败:提示错误信息(错误码可参考华为广告文档)
this.isAdLoaded = false;
let errorMsg = '广告加载失败';
switch (errorCode) {
case 1001: errorMsg = '网络异常,请检查网络'; break;
case 2001: errorMsg = '广告单元ID无效'; break;
case 3001: errorMsg = '广告资源暂时不足'; break;
}
promptAction.showToast({ message: errorMsg });
// 10秒后重试加载(避免频繁请求)
setTimeout(() => this.loadIncentiveAd(), 10000);
}
});
// 发起广告加载请求
this.loadIncentiveAd();
}
// 加载广告(单独封装,便于重试)
private loadIncentiveAd() {
if (!this.incentiveAd) return;
// 构建广告请求参数(可设置用户标签用于精准投放)
const adParam = new AdParam.Builder()
.setGender(AdParam.GENDER_MALE) // 示例:设置用户性别(可选)
.setAge(25) // 示例:设置用户年龄(可选)
.build();
this.incentiveAd.loadAd(adParam);
}
// 销毁广告实例
private destroyIncentiveAd() {
if (this.incentiveAd) {
this.incentiveAd.destroy();
this.incentiveAd = null;
this.isAdLoaded = false;
}
}
3. 广告展示与奖励发放
补充showIncentiveAd方法,实现广告展示、关闭及奖励发放逻辑,重点处理 "用户完成广告观看" 的事件:
bash
// 展示激励广告
private showIncentiveAd() {
if (!this.incentiveAd || !this.isAdLoaded) return;
// 设置广告展示监听器(监听广告显示/关闭)
this.incentiveAd.setAdDisplayListener({
onAdDisplayed: () => {
// 广告开始展示:禁用按钮,防止重复点击
this.isAdLoaded = false;
},
onAdClosed: () => {
// 广告关闭:重新加载广告,为下一次展示做准备
this.loadIncentiveAd();
},
onAdClicked: () => {
// 广告被点击:可记录点击数据(可选)
console.log('激励广告被点击');
}
});
// 设置奖励监听器(监听用户是否完成广告任务)
this.incentiveAd.setIncentiveAdListener({
onUserEarnedReward: (reward: Reward) => {
// 用户完成广告观看:发放奖励(reward.amount为奖励数量,此处固定为10)
const rewardAmount = reward.amount || 10;
this.coinCount += rewardAmount;
// 提示奖励到账
promptAction.showToast({
message: `奖励到账!获得${rewardAmount}游戏币`,
duration: 2000
});
},
onRewardVerify: (isVerify: boolean) => {
// 奖励验证(部分场景下广告平台会验证奖励有效性)
if (!isVerify) {
promptAction.showToast({ message: '奖励验证失败,请稍后重试' });
}
}
});
// 展示广告(需传入当前页面的Context)
this.incentiveAd.show(getContext() as common.UIAbilityContext);
}
四、ArkTS 多广告形式扩展:Banner 与原生广告
除激励广告外,Banner 广告和原生广告也是 ArkTS 项目中的常用形式,以下补充核心实现代码:
1. Banner 广告
Banner 广告通过BannerAd组件直接嵌入页面,适合工具类 App 的顶部 / 底部展示:
bash
import { BannerAd, AdParam } from '@huawei/hms.ads';
@Component
struct BannerAdComponent {
// Banner广告单元ID(需与激励广告ID区分)
private readonly AD_UNIT_ID: string = 'testb4znbuh3n2';
build() {
// Banner广告组件(宽高比建议16:9,避免拉伸)
BannerAd({
adUnitId: this.AD_UNIT_ID,
adParam: new AdParam.Builder().build(),
// 广告加载状态回调
onAdLoaded: () => {
console.log('Banner广告加载成功');
},
onAdFailed: (errorCode: number) => {
console.error(`Banner广告加载失败:${errorCode}`);
},
onAdClicked: () => {
console.log('Banner广告被点击');
}
})
.width('100%')
.height(150) // 典型Banner尺寸:宽度满屏,高度150px
.margin({ top: 10 });
}
}
// 使用方式:在页面的Column中直接引入
// Column() {
// BannerAdComponent()
// // 其他页面内容
// }
- 原生广告
原生广告需自定义 UI 样式,与页面内容融合,适合信息流场景:
bash
import { NativeAd, NativeAdLoadListener, NativeAdData } from '@huawei/hms.ads';
@Component
struct NativeAdComponent {
@State nativeAdData: NativeAdData | null = null;
private nativeAd: NativeAd | null = null;
private readonly AD_UNIT_ID: string = 'testn44hll3dty';
build() {
if (!this.nativeAdData) return;
// 自定义原生广告UI(模拟信息流卡片样式)
Column({ space: 8 }) {
// 广告标识(必加,合规要求)
Text('广告')
.fontSize(12)
.backgroundColor('#FF4444')
.color('white')
.padding(2)
.alignSelf(ItemAlign.Start);
// 广告标题
Text(this.nativeAdData.getTitle() || '未知标题')
.fontSize(16)
.fontWeight(FontWeight.Bold);
// 广告描述
Text(this.nativeAdData.getDescription() || '未知描述')
.fontSize(14)
.color('#666666')
.maxLines(2)
.textOverflow({ overflow: TextOverflow.Ellipsis });
// 广告图片(若有)
if (this.nativeAdData.getImages()?.length) {
Image(this.nativeAdData.getImages()![0].getUrl())
.width('100%')
.height(180)
.objectFit(ImageFit.Cover);
}
// 广告按钮
Button(this.nativeAdData.getCallToAction() || '立即查看')
.width('100%')
.height(40)
.fontSize(14)
.backgroundColor('#007DFF')
.onClick(() => {
// 触发广告点击(必须调用,否则无法统计点击数据)
this.nativeAd?.onAdClicked(this.nativeAdData);
});
}
.width('100%')
.padding(12)
.backgroundColor('white')
.borderRadius(8)
.margin(10)
.shadow({ radius: 4, color: '#EEEEEE' });
}
aboutToAppear() {
// 页面渲染前初始化原生广告
this.initNativeAd();
}
aboutToDisappear() {
// 页面销毁前销毁广告
if (this.nativeAd) {
this.nativeAd.destroy();
this.nativeAd = null;
}
}
private initNativeAd() {
this.nativeAd = NativeAd.createNativeAd(this.AD_UNIT_ID);
this.nativeAd?.setAdLoadListener({
onAdLoaded: (ads: NativeAdData[]) => {
// 加载到广告数据,取第一条展示
if (ads.length > 0) {
this.nativeAdData = ads[0];
// 触发广告曝光(必须调用,否则无法统计曝光数据)
this.nativeAd?.onAdImpression(this.nativeAdData);
}
},
onAdFailed: (errorCode: number) => {
console.error(`原生广告加载失败:${errorCode}`);
}
});
// 加载原生广告(请求1条数据)
this.nativeAd?.loadAd(1);
}
}
五、 广告开发注意事项
上下文(Context)正确性:
广告展示(如incentiveAd.show())需传入UIAbilityContext,避免使用ApplicationContext导致崩溃,可通过getContext() as common.UIAbilityContext获取当前页面上下文。
状态管理与内存泄漏:
使用@State装饰器管理广告加载状态,在onPageHide或aboutToDisappear中销毁广告实例,避免页面销毁后广告仍占用资源。
测试广告与正式广告区分:
集成初期使用华为提供的测试广告单元 ID(如激励广告testx9dtjwj8hp),上线前需在华为广告平台申请正式 ID,并替换代码中的测试 ID,否则无法产生真实收益。
六、 总结
总结一下,关于HarmonyOS 广告服务的集成,核心是在 "商业化变现" 与 "用户体验" 之间找到平衡。我们作为开发者需遵循以下原则:
场景优先:根据 App 的核心功能(如工具、内容、游戏)选择适配的广告形式,避免 "一刀切" 的广告策略;
合规底线:严格遵守隐私保护、内容审核、标识标注的合规要求,避免因违规导致 App 下架;
体验优化:通过预加载、频率控制、交互适配等手段,减少广告对用户的干扰,提升用户接受度。
好了,本篇文章就讲到这里,谢谢大家阅读观看。