HarmonyOS鸿蒙Next中uniapp开发的应用如何通过嵌入原生组件的方式添加广告呢?比如banner,插屏,激励视频

HarmonyOS鸿蒙Next中uniapp开发的应用如何通过嵌入原生组件的方式添加广告呢?比如banner,插屏,激励视频

【问题描述】:uniapp开发的鸿蒙应用. 如何通过嵌入原生组件的方式添加广告呢?比如banner,插屏,激励视频。

【问题现象】:已经用uniapp开发好应用,上架了鸿蒙next,现在想添加广告变现。官方目前还没有适配,然后自己通过uts嵌入原生组件的方式开发原生广告,页面中不显示,原生日志打印提示广告也加载完成。

【版本信息】:HBuilder X 5.07

【复现代码】:

import { NativeEmbedBuilderOptions, defineNativeEmbed } from "@dcloudio/uni-app-runtime"

import { abilityAccessCtrl, common, PermissionRequestResult } from '@kit.AbilityKit';
import { advertising, AutoAdComponent, identifier } from '@kit.AdsKit';
import { hilog } from '@kit.PerformanceAnalysisKit';

@Component
struct adsBannerComponent {
 @State visibilityState: Visibility = Visibility.None;
  // 广告请求参数
  private adRequestParams: advertising.AdRequestParams = {
	// 'h5xkz3mbr2'为测试专用的广告位ID,App正式发布时需要改为正式的广告位ID
	adId: 'h5xkz3mbr2',
	// 横幅广告类型
	adType: 8,
	// 广告位宽
	adWidth: 360,
	// 广告位高
	adHeight: 57
  };
  
    // 广告配置参数,开发者可根据项目实际情况设置
    private adOptions: advertising.AdOptions = {};
    // 广告展示参数,开发者可根据项目实际情况设置
    private adDisplayOptions: advertising.AdDisplayOptions = {
      // 广告轮播的时间间隔,单位ms,取值范围[30000, 120000]
      refreshTime: 30000
    };
    private ratio: number = 1;
    private context: common.UIAbilityContext =  this.getUIContext().getHostContext()  as common.UIAbilityContext;
  
    async aboutToAppear(): Promise<void> {
      // 开放匿名设备标识符
      this.adRequestParams.oaid = await requestOAID(this.context);
	  console.log('this.adRequestParams',this.adRequestParams);
      this.visibilityState = Visibility.Visible;
      if (this.adRequestParams.adWidth && this.adRequestParams.adHeight) {
        this.ratio = this.adRequestParams.adWidth / this.adRequestParams.adHeight;
      }
    }
	

	
  build() {
     Stack({ alignContent: Alignment.Bottom }) {
         Row() {
		   AutoAdComponent({
			 adParam: this.adRequestParams,
			 adOptions: this.adOptions,
			 displayOptions: this.adDisplayOptions,
			 interactionListener: {
			   onStatusChanged: (status: string, ad: advertising.Advertisement, data: string) => {
				 switch (status) {
				   case 'onAdOpen':
					console.log('打开广告');
					 break;
				   case 'onAdClick':
					 console.log('点击广告');
					 break;
				   case 'onAdClose':
					console.log('关闭广告');
					 this.visibilityState = Visibility.None;
					 break;
				   case 'onAdLoad':
					console.log('广告加载成功');
					 break;
				   case 'onAdFail':
					console.log('广告加载失败');
					 this.visibilityState = Visibility.None;
					 break;
				 }
			   }
			 }
		   }).width('100%')
			.height('100%')
	
         }
         .width('100%')
         .aspectRatio(this.ratio)
         .visibility(this.visibilityState)
       }
  }
}


async function requestOAID(context: Context): Promise<string | undefined> {
  // 向用户请求授权广告跨应用关联访问权限
  let isPermissionGranted: boolean = false;
  try {
	const atManager: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager();
	const result: PermissionRequestResult =
	  await atManager.requestPermissionsFromUser(context, ['ohos.permission.APP_TRACKING_CONSENT']);
	isPermissionGranted = result.authResults[0] === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED;
  } catch (err) {
	hilog.error(0x0000, 'testTag', `Failed to request permission. Code is ${err.code}, message is ${err.message}`);
  }
  if (isPermissionGranted) {
	hilog.info(0x0000, 'testTag', 'Succeeded in requesting permission');
	try {
	  const oaid = await identifier.getOAID();
	  hilog.info(0x0000, 'testTag', 'Succeeded in getting OAID');
	  return oaid;
	} catch (err) {
	  hilog.error(0x0000, 'testTag', `Failed to get OAID. Code is ${err.code}, message is ${err.message}`);
	}
  } else {
	hilog.error(0x0000, 'testTag', 'Failed to request permission. User rejected');
  }
  return undefined;
}

@Builder
function adsBannerBuilder(options: NativeEmbedBuilderOptions) {
  adsBannerComponent()
}

defineNativeEmbed('adsbanner', {
  builder: adsBannerBuilder
})

【尝试解决方案】:不涉及


更多关于HarmonyOS鸿蒙Next中uniapp开发的应用如何通过嵌入原生组件的方式添加广告呢?比如banner,插屏,激励视频的实战教程也可以访问 https://www.itying.com/category-93-b0.html

14 回复

尊敬的开发者,您好,uni-app嵌入ArkUI组件使用了同层渲染,广告不支持纹理导出,NodeController挂载节点时不能设置为NodeRenderType.RENDER_TYPE_TEXTURE,nodeRenderType需要设置为NodeRenderType.RENDER_TYPE_DISPLAY请参考uni-app官网链接修改,以下为修改后的参考代码。

嵌入HarmonyOS原生组件

import { NativeEmbedBuilderOptions, defineNativeEmbed } from "@dcloudio/uni-app-runtime"

import { abilityAccessCtrl, common, PermissionRequestResult } from '@kit.AbilityKit';
import { advertising, AutoAdComponent, identifier } from '@kit.AdsKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
import { NodeRenderType } from '@kit.ArkUI'

@Component
struct adsBannerComponent {
  @State visibilityState: Visibility = Visibility.None;
  // 广告请求参数
  private adRequestParams: advertising.AdRequestParams = {
    // 'h5xkz3mbr2'为测试专用的广告位ID,App正式发布时需要改为正式的广告位ID
    adId: 'h5xkz3mbr2',
    // 横幅广告类型
    adType: 8,
    // 广告位宽
    adWidth: 360,
    // 广告位高
    adHeight: 57
  };
  // 广告配置参数,开发者可根据项目实际情况设置
  private adOptions: advertising.AdOptions = {};
  // 广告展示参数,开发者可根据项目实际情况设置
  private adDisplayOptions: advertising.AdDisplayOptions = {
    // 广告轮播的时间间隔,单位ms,取值范围[30000, 120000]
    refreshTime: 30000
  };
  private ratio: number = 1;
  private context: common.UIAbilityContext = this.getUIContext().getHostContext() as common.UIAbilityContext;

  async aboutToAppear(): Promise<void> {
    // 开放匿名设备标识符
    this.adRequestParams.oaid = await requestOAID(this.context);
    console.log('this.adRequestParams', this.adRequestParams);
    this.visibilityState = Visibility.Visible;
    if (this.adRequestParams.adWidth && this.adRequestParams.adHeight) {
      this.ratio = this.adRequestParams.adWidth / this.adRequestParams.adHeight;
    }
  }

  build() {
    Row() {
      AutoAdComponent({
        adParam: this.adRequestParams,
        adOptions: this.adOptions,
        displayOptions: this.adDisplayOptions,
        interactionListener: {
          onStatusChanged: (status: string, ad: advertising.Advertisement, data: string) => {
            switch (status) {
              case 'onAdOpen':
                console.log('打开广告');
                break;
              case 'onAdClick':
                console.log('点击广告');
                break;
              case 'onAdClose':
                console.log('关闭广告');
                this.visibilityState = Visibility.None;
                break;
              case 'onAdLoad':
                console.log('广告加载成功');
                break;
              case 'onAdFail':
                console.log('广告加载失败');
                this.visibilityState = Visibility.None;
                break;
            }
          }
        }
      })
        .width('100%')
        .height('100%')
        .aspectRatio(this.ratio)
        .visibility(this.visibilityState)
        .backgroundColor(Color.Red)
    }
  }
}

async function requestOAID(context: Context): Promise<string | undefined> {
  // 向用户请求授权广告跨应用关联访问权限
  let isPermissionGranted: boolean = false;
  try {
    const atManager: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager();
    const result: PermissionRequestResult =
      await atManager.requestPermissionsFromUser(context, ['ohos.permission.APP_TRACKING_CONSENT']);
    isPermissionGranted = result.authResults[0] === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED;
  } catch (err) {
    hilog.error(0x0000, 'testTag', `Failed to request permission. Code is ${err.code}, message is ${err.message}`);
  }
  if (isPermissionGranted) {
    hilog.info(0x0000, 'testTag', 'Succeeded in requesting permission');
    try {
      const oaid = await identifier.getOAID();
      hilog.info(0x0000, 'testTag', 'Succeeded in getting OAID');
      return oaid;
    } catch (err) {
      hilog.error(0x0000, 'testTag', `Failed to get OAID. Code is ${err.code}, message is ${err.message}`);
    }
  } else {
    hilog.error(0x0000, 'testTag', 'Failed to request permission. User rejected');
  }
  return undefined;
}

@Builder
function adsBannerBuilder(options: NativeEmbedBuilderOptions) {
  adsBannerComponent()
    .width(options.width)
    .height(options.height)
}

defineNativeEmbed('adsbanner', {
  builder: adsBannerBuilder,
  nodeRenderType: NodeRenderType.RENDER_TYPE_DISPLAY
})

更多关于HarmonyOS鸿蒙Next中uniapp开发的应用如何通过嵌入原生组件的方式添加广告呢?比如banner,插屏,激励视频的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


你这个问题里,最关键的结论其实不是 AdsKit,而是 uni-app 的原生嵌入模式本身

先说结论

你现在这套写法:

  • defineNativeEmbed(...)
  • NativeEmbedBuilderOptions
  • 在 uni-app 页面里嵌一个 ArkTS 原生组件

这条路在鸿蒙上大概率就是不支持的,所以会出现:

  • 原生日志里 onAdLoad 成功
  • 但页面里就是不显示

原因是 DCloud 官方文档已经写了:

  • uni-app兼容模式 的 uts 组件开发
  • 不支持鸿蒙
  • 只有 uni-app x标准模式,基于 native-view,才支持 HarmonyOS 见 DCloud 文档:uts插件 - 组件开发

文档原话核心意思是:

  • uni-app兼容模式:支持 uni-app 的 app-nvue 和 uni-app x 的 app-uvue,不支持鸿蒙
  • 标准模式:仅支持 uni-app x,但全平台支持,其中包含 HarmonyOS 同页可见:uts插件 - 组件开发

这也解释了你现在的现象

你现在不是“广告没加载成功”,而是更像:

  • AdsKit 原生广告组件已经加载完成
  • uni-app 页面容器并没有真正把这个原生组件渲染到鸿蒙页面文档流里

所以看起来就是:

  • 逻辑通了
  • 广告回调通了
  • 但 UI 不显示

这和你描述的现象是完全一致的。


你当前这条路里,哪些广告能做,哪些不能做

1. Banner

如果你想要的是页面内嵌 banner,那它本质上是一个“原生组件嵌入页面”的问题。

这在你当前的 uni-app 经典工程 里,鸿蒙侧基本不可行,原因就是上面说的:

  • defineNativeEmbed 这类兼容模式组件
  • 鸿蒙不支持

2. 插屏激励视频

这两个其实不一定要走“页面内嵌组件”。

DCloud 文档也区分了:

而:

  • 插屏广告
  • 激励视频广告

本身就是全屏/弹窗式广告,所以更适合封装成 UTS API 插件,而不是嵌入组件。

也就是说:

  • Banner:你现在这套 uni-app 经典工程里不适合
  • 插屏/激励视频:可以改成 UTS 原生 API 调用 方式做

另外,AdsKit 本身是没问题的

华为官方文档确认:

所以你这段代码本身从 AdsKit 角度看并不离谱,甚至和官方示例很接近。 问题更可能就是:

广告组件在原生侧创建了,但 uni-app 鸿蒙页面没有承载它。


你现在最可行的方案

方案 1:插屏 + 激励视频 先做成 UTS API 插件

这是最现实的。

因为这两类广告不是页面内嵌型,可以走:

  • UTS 暴露 showInterstitialAd()
  • UTS 暴露 showRewardAd()
  • 页面里直接 JS/UTS 调用

这种方式不依赖页面内嵌原生组件,成功率最高。

方案 2:Banner 如果一定要做页面内嵌,建议迁移到 uni-app x

如果你必须做鸿蒙原生 Banner 内嵌:

  • 最好改成 uni-app x
  • 用 DCloud 官方说的 标准模式
  • 基于 native-view 做原生组件承载 见:uts插件 - 组件开发

方案 3:如果项目必须留在经典 uni-app

那就建议:

  • 放弃鸿蒙原生 Banner 内嵌
  • 只先接 插屏 / 激励视频
  • Banner 改成其他替代变现方案

你代码里还有几个次要点

这些不是主因,但后面真做原生插件时建议一起注意:

1. 权限和 module 配置

UTS 鸿蒙插件里,权限要通过插件自己的 module.json5 配置,DCloud 文档有说明:uts for HarmonyOS

2. Context 获取方式

DCloud 也建议在鸿蒙插件里通过宿主窗口拿 getHostContext(),而不是按普通页面 JS 思路处理:uts for HarmonyOS

3. 设备类型限制

Banner 只支持:

  • Phone
  • Tablet
  • PC/2in1 不支持所有设备类型。见:横幅广告

一句话结论

不是广告没加载,而是你现在用的 uni-app 原生嵌入方案在鸿蒙上不成立。

所以建议你这样定方案:

  • Banner:要么迁移 uni-app xnative-view 原生组件,要么暂时不做
  • 插屏/激励视频:直接做成 UTS API 插件,不走嵌入组件

你的外层 Row 依赖 aspectRatio 撑高,但在数据未返回时,ratio 计算可能为 1,导致 Row 高度过小而不可见。可以试试是给最外层 Row 加一个最小高度,确保点击区域存在:

Row() {
  // ...
}
.width('100%')
.constraintSize({ minHeight: 50 }) // 保证行可见
.aspectRatio(this.ratio)
.visibility(this.visibilityState)

找HarmonyOS工作还需要会Flutter的哦,有需要Flutter教程的可以学学大地老师的教程,很不错,B站免费学的哦:https://www.bilibili.com/video/BV1S4411E7LY/?p=17,

学习一下

从现象看,“广告已加载但页面不显示”优先排查广告类型和展示组件是否匹配,以及 uni-app 原生嵌入组件是否真的布局出来。横幅广告通常用 AutoAdComponent;原生、开屏、贴片广告用 AdComponent;插屏和激励视频一般不是嵌入页面组件,而是加载后调用 showAd 展示。建议先在纯 ArkTS 页面只跑通 banner,再放入 native embed,并确认外层容器有明确 width/height,没有被滚动容器裁剪或被 zIndex/overflow 影响。

期待HarmonyOS能继续优化多屏协同功能,让跨设备体验更加完美。

<template>
	<view class="content">
		<image class="logo" src="/static/logo.png"></image>
		<view class="text-area">
			<text class="title">{{title}}</text>
		</view>
		<embed class="native-button" tag="button" :options="options" @buttonclick="onClick"></embed>
		<embed class="native-button" tag="adsbanner"></embed>
	</view>
</template>

<script>
	import '@/uni_modules/harmony-ads'
	export default {
		data() {
			return {
				title: 'Hello',
				options: {
					label: '广告测试'
				}
			}
		},
		onLoad() {

		},
		methods: {

		}
	}
</script>

<style>
	.native-button {
		display: block;
		width: 200px;
		height: 50px;
		margin: 10px auto;
	}

	.content {
		display: flex;
		flex-direction: column;
		align-items: center;
		justify-content: center;
	}

	.logo {
		height: 200rpx;
		width: 200rpx;
		margin-top: 200rpx;
		margin-left: auto;
		margin-right: auto;
		margin-bottom: 50rpx;
	}

	.text-area {
		display: flex;
		justify-content: center;
	}

	.title {
		font-size: 36rpx;
		color: #8f8f94;
	}
</style>

需要编写插件搭桥,可以试试embed的方式引入广告

<embed class="native-button" tag="adsbanner"></embed>

就是引入了但是页面不显示 写一个button按钮或者地图什么的都显示 就是这个广告不显示

你可以新建一个项目,然后用最小化验证的方式去测试一下,这样就可以测出到底是这玩意儿不生效,还是因为你原本项目中的什么东西干扰了,

我新建了一个项目测试了一下感觉就是不生效 代码跟效果我新开了一个楼

在鸿蒙Next中,uniapp应用通过创建原生插件(如ExtensionAbility或Service)集成广告SDK,使用NativeContainer或XComponent等ArkUI原生组件嵌入广告视图。通过JSBridge暴露接口,前端调用Native方法加载并展示banner、插屏或激励视频广告,各广告类型需在原生侧分别实现对应组件渲染与生命周期管理。

问题在于 Stack 和内部 Row 的尺寸约束不足,导致 AutoAdComponent 计算出高度为 0,虽然广告加载成功但不可见。修改布局,直接给包裹容器一个明确高度即可解决。

精简后的代码修改如下(Banner 部分):

struct adsBannerComponent {
  // ... 其余代码不变 ...
  build() {
    // 使用 Column 替代 Stack,确保组件有确定的约束
    Column() {
      AutoAdComponent({
        adParam: this.adRequestParams,
        adOptions: this.adOptions,
        displayOptions: this.adDisplayOptions,
        interactionListener: { /* ... */ }
      })
        .width('100%')
        .height('100%')
    }
    .width('100%')
    .height(57)  // 或保持 aspectRatio,但必须给一个高度基准
    .visibility(this.visibilityState)
  }
}

对于插屏和激励视频广告,它们不应作为嵌入组件,需在 onAdLoad 中调用 ad.show() 进行全屏展示,不可内嵌到页面布局。

回到顶部