华为HarmonyOS打造开放、合规的广告生态 - 贴片广告

news2024/11/27 16:47:12

场景介绍

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

接口说明

接口名

描述

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监听广告状态回调。

开发步骤

  1. 获取OAID。

    如果想要为用户更精准的推送广告,可以在请求参数AdRequestParams中添加oaid属性。

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

    说明

    使用以下示例中提供的测试广告位必须先获取OAID信息。

  2. 请求单广告位广告。

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

    在请求贴片广告时,需要在AdOptions中设置两个参数:totalDuration和placementAdCountDownDesc。

    请求广告关键参数如下所示:

    请求广告参数名

    类型

    必填

    说明

    adType

    number

    请求广告类型,贴片广告类型为60。

    adId

    string

    广告位ID。

    • 如果仅调测广告,可使用测试广告位ID:testy3cglm3pj0。
    • 如果要接入正式广告,则需要申请正式的广告位ID。可在应用发布前进入流量变现官网,点击“开始变现”,登录鲸鸿动能媒体服务平台进行申请,具体操作详情请参见展示位创建。

    oaid

    string

    开放匿名设备标识符,用于精准推送广告。不填无法获取到个性化广告。

    示例代码如下所示:
     
      
    1. import { advertising, identifier } from '@kit.AdsKit';
    2. import { common } from '@kit.AbilityKit';
    3. import { hilog } from '@kit.PerformanceAnalysisKit';
    4. import { BusinessError } from '@kit.BasicServicesKit';
    5. import { router } from '@kit.ArkUI';
    6. @Entry
    7. @Component
    8. struct Index {
    9. private context: common.UIAbilityContext = getContext(this) as common.UIAbilityContext;
    10. // 获取到的OAID
    11. private oaid: string = '';
    12. aboutToAppear() {
    13. try {
    14. // 使用Promise回调方式获取OAID
    15. identifier.getOAID().then((data: string) => {
    16. this.oaid = data;
    17. hilog.info(0x0000, 'testTag', '%{public}s', 'Succeeded in getting adsIdentifierInfo by promise');
    18. }).catch((error: BusinessError) => {
    19. hilog.error(0x0000, 'testTag', '%{public}s',
    20. `Failed to get adsIdentifierInfo, code: ${error.code}, message: ${error.message}`);
    21. })
    22. } catch (error) {
    23. hilog.error(0x0000, 'testTag', '%{public}s', `Catch err, code: ${error.code}, message: ${error.message}`);
    24. }
    25. }
    26. build() {
    27. Row() {
    28. Button('加载广告', { type: ButtonType.Normal, stateEffect: true })
    29. .onClick(() => {
    30. // 调用加载广告方法
    31. requestAd(this.context, this.oaid);
    32. })
    33. .borderRadius(8)
    34. .backgroundColor(0x317aff)
    35. .width(90)
    36. .height(40)
    37. }
    38. .height('100%')
    39. }
    40. }
    41. /**
    42. * 加载广告
    43. *
    44. * @param context 上下文环境
    45. * @param oaid OAID信息
    46. */
    47. function requestAd(context: common.Context, oaid: string): void {
    48. const adRequestParam: advertising.AdRequestParams = {
    49. // 广告类型
    50. adType: 60,
    51. // 'testy3cglm3pj0'为测试专用的广告位ID,App正式发布时需要改为正式的广告位ID
    52. adId: 'testy3cglm3pj0',
    53. // 在AdRequestParams中添加oaid参数
    54. oaid: oaid,
    55. // 用于区分普通请求和预加载请求,默认值false代表普通请求,true代表预加载请求
    56. isPreload: false
    57. };
    58. const adOptions: advertising.AdOptions = {
    59. // 在AdOptions中添加totalDuration参数,用于设置贴片广告展示时长(贴片广告必填)
    60. totalDuration: 30,
    61. // 在AdOptions中添加placementAdCountDownDesc参数,设置贴片广告倒计时文案(可选,填写了则展示文案,不填写则只展示倒计时)
    62. placementAdCountDownDesc: encodeURI('VIP免广告'),
    63. // 是否允许流量下载 0不允许 1允许,不设置以广告主设置为准
    64. allowMobileTraffic: 0,
    65. // 是否希望根据 COPPA 的规定将您的内容视为面向儿童的内容: -1默认值,不确定 0不希望 1希望
    66. tagForChildProtection: -1,
    67. // 是否希望按适合未达到法定承诺年龄的欧洲经济区 (EEA) 用户的方式处理该广告请求: -1默认值,不确定 0不希望 1希望
    68. tagForUnderAgeOfPromise: -1,
    69. // 设置广告内容分级上限: W: 3+,所有受众 PI: 7+,家长指导 J:12+,青少年 A: 16+/18+,成人受众
    70. adContentClassification: 'A'
    71. };
    72. // 广告请求回调监听
    73. const adLoaderListener: advertising.AdLoadListener = {
    74. // 广告请求失败回调
    75. onAdLoadFailure: (errorCode: number, errorMsg: string) => {
    76. hilog.error(0x0000, 'testTag', '%{public}s',
    77. `Failed to request single ad, errorCode is: ${errorCode}, errorMsg is: ${errorMsg}`);
    78. },
    79. // 广告请求成功回调
    80. onAdLoadSuccess: (ads: Array<advertising.Advertisement>) => {
    81. hilog.info(0x0000, 'testTag', '%{public}s', 'Succeeded in requesting single ad!');
    82. // 保存请求到的广告内容用于展示
    83. const returnAds = ads;
    84. // 路由到广告展示页面
    85. routePage('pages/PlacementAdPage', returnAds);
    86. }
    87. };
    88. // 创建AdLoader广告对象
    89. const load: advertising.AdLoader = new advertising.AdLoader(context);
    90. // 调用广告请求接口
    91. hilog.info(0x0000, 'testTag', '%{public}s', 'Request single ad!');
    92. load.loadAd(adRequestParam, adOptions, adLoaderListener);
    93. }
    94. /**
    95. * 路由跳转
    96. *
    97. * @param pageUri 要路由到的页面
    98. */
    99. async function routePage(pageUri: string, ads: Array<advertising.Advertisement | null>) {
    100. let options: router.RouterOptions = {
    101. url: pageUri,
    102. params: {
    103. ads: ads
    104. }
    105. }
    106. try {
    107. hilog.info(0x0000, 'testTag', '%{public}s', `RoutePage: ${pageUri}`);
    108. router.pushUrl(options);
    109. } catch (error) {
    110. hilog.error(0x0000, 'testTag', '%{public}s',
    111. `Failed to routePage callback, code: ${error.code}, msg: ${error.message}`);
    112. }
    113. }

  3. 展示广告。

    在您的页面中使用AdComponent组件展示贴片广告,由媒体判断流量场景下,可以自动播放则展示广告,反之则不展示。以前贴广告为例,前贴广告播放完成后进入正片播放。您需要在entry/src/main/resources/base/profile/main_pages.json文件中添加页面,如下图所示。

    您需要在media和rawfile目录下分别指定正片未播放时的预览图video_preview.PNG和对应的正片文件videoTest.mp4,如下图所示。

    示例代码如下所示:
     
      
    1. import { router, window } from '@kit.ArkUI';
    2. import { BusinessError } from '@kit.BasicServicesKit';
    3. import { advertising, AdComponent } from '@kit.AdsKit';
    4. import { hilog } from '@kit.PerformanceAnalysisKit';
    5. @Entry
    6. @Component
    7. export struct PlacementAdPage {
    8. // 是否竖屏
    9. private portrait: boolean = true;
    10. // 请求到的广告内容
    11. private ads: Array<advertising.Advertisement> = [];
    12. // 广告展示参数
    13. private adDisplayOptions: advertising.AdDisplayOptions = {
    14. // 是否静音,默认不静音
    15. mute: false
    16. }
    17. // 广告参数
    18. private adOptions: advertising.AdOptions = {
    19. // 设置贴片广告展示时长(贴片广告必填)
    20. totalDuration: 30,
    21. // 设置贴片广告倒计时文案,文案需要使用encodeURI编码(可选,填写了则展示文案,不填写则只展示倒计时)
    22. placementAdCountDownDesc: encodeURI('VIP免广告'),
    23. // 是否希望根据 COPPA 的规定将您的内容视为面向儿童的内容: -1默认值,不确定 0不希望 1希望
    24. tagForChildProtection: -1,
    25. // 是否希望按适合未达到法定承诺年龄的欧洲经济区 (EEA) 用户的方式处理该广告请求: -1默认值,不确定 0不希望 1希望
    26. tagForUnderAgeOfPromise: -1,
    27. // 设置广告内容分级上限: W: 3+,所有受众 PI: 7+,家长指导 J:12+,青少年 A: 16+/18+,成人受众
    28. adContentClassification: 'A'
    29. }
    30. // 已经播放的贴片广告数量
    31. private playedAdSize: number = 0;
    32. // 是否播放正片
    33. @State isPlayVideo: boolean = false;
    34. // 视频播放控制器
    35. private controller: VideoController = new VideoController();
    36. // 指定视频未播放时的预览图片路径
    37. private previewUris: Resource = $r('app.media.video_preview');
    38. // 指定视频播放源的路径,这里取本地视频资源
    39. private innerResource: Resource = $rawfile('videoTest.mp4');
    40. // 用于渲染右上角倒计时
    41. private countDownTxtPlaceholder: string = '%d | %s';
    42. @State countDownTxt: string = '';
    43. aboutToAppear() {
    44. const params: Record<string, Object> = router.getParams() as Record<string, Object>;
    45. if (params && params.ads as Array<advertising.Advertisement>) {
    46. this.ads = params.ads as Array<advertising.Advertisement>;
    47. this.adOptions = params.adOptions as advertising.AdOptions;
    48. this.initData();
    49. }
    50. }
    51. build() {
    52. Stack({ alignContent: Alignment.TopEnd }) {
    53. // AdComponent组件用于展示非全屏广告
    54. AdComponent({
    55. ads: this.ads, displayOptions: this.adDisplayOptions,
    56. interactionListener: {
    57. // 广告状态变化回调
    58. onStatusChanged: (status: string, ad: advertising.Advertisement, data: string) => {
    59. switch (status) {
    60. case 'onPortrait':
    61. hilog.info(0x0000, 'testTag', '%{public}s', 'Status is onPortrait');
    62. // 设置屏幕方向为竖屏或返回上一页
    63. this.setWindowPortrait();
    64. break;
    65. case 'onLandscape':
    66. hilog.info(0x0000, 'testTag', '%{public}s', 'Status is onLandscape');
    67. // 设置屏幕方向为横屏
    68. this.setWindowLandscape();
    69. break;
    70. case 'onMediaProgress':
    71. hilog.info(0x0000, 'testTag', '%{public}s', 'Status is onMediaProgress');
    72. break;
    73. case 'onMediaStart':
    74. hilog.info(0x0000, 'testTag', '%{public}s', 'Status is onMediaStart');
    75. break;
    76. case 'onMediaPause':
    77. hilog.info(0x0000, 'testTag', '%{public}s', 'Status is onMediaPause');
    78. break;
    79. case 'onMediaStop':
    80. hilog.info(0x0000, 'testTag', '%{public}s', 'Status is onMediaStop');
    81. break;
    82. case 'onMediaComplete':
    83. hilog.info(0x0000, 'testTag', '%{public}s', 'Status is onMediaComplete');
    84. // 所有广告都播放完毕后,开始播放正片
    85. this.playedAdSize++;
    86. if (this.playedAdSize === this.ads.length) {
    87. this.isPlayVideo = true;
    88. }
    89. break;
    90. case 'onMediaError':
    91. hilog.error(0x0000, 'testTag', '%{public}s', 'Status is onMediaError');
    92. break;
    93. case 'onMediaCountdown':
    94. try {
    95. hilog.info(0x0000, 'testTag', '%{public}s', 'Status is onMediaCountdown');
    96. const parseData: Record<string, number> = JSON.parse(JSON.stringify(data));
    97. this.updateCountDownTxt(parseData.countdownTime);
    98. } catch (e) {
    99. hilog.error(0x0000, 'testTag', '%{public}s',
    100. `Failed to parse data, code: ${e.code}, msg: ${e.message}`);
    101. }
    102. break;
    103. }
    104. }
    105. }
    106. })
    107. .visibility(!this.isPlayVideo ? Visibility.Visible : Visibility.None)
    108. .width('100%')
    109. .height('100%')
    110. Row() {
    111. if (this.countDownTxt) {
    112. Text(this.countDownTxt.split('').join('\u200B'))
    113. .fontSize(12)
    114. .textAlign(TextAlign.Center)
    115. .maxLines(1)
    116. .fontColor(Color.White)
    117. .lineHeight(12)
    118. .textOverflow({ overflow: TextOverflow.Ellipsis })
    119. .maxLines(1)
    120. .backgroundColor('#66000000')
    121. .border({ radius: 25 })
    122. .padding({
    123. left: 8,
    124. right: 8,
    125. top: 6,
    126. bottom: 6
    127. })
    128. .margin({ right: 16, top: 16 })
    129. .height(24)
    130. .constraintSize({ minWidth: 60, maxWidth: 100 })
    131. .onClick((event: ClickEvent) => {
    132. hilog.info(0x0000, 'testTag', '%{public}s', 'OnVipClicked, do something...');
    133. })
    134. }
    135. }
    136. .alignItems(VerticalAlign.Top)
    137. .justifyContent(FlexAlign.End)
    138. Video({
    139. src: this.innerResource,
    140. previewUri: this.previewUris,
    141. controller: this.controller
    142. })
    143. .visibility(this.isPlayVideo ? Visibility.Visible : Visibility.None)
    144. .autoPlay(this.isPlayVideo ? true : false)
    145. .controls(false)
    146. .width('100%')
    147. .height('100%')
    148. }.width('100%').height('100%')
    149. }
    150. /**
    151. * 设置竖屏或返回上一页
    152. */
    153. private setWindowPortrait() {
    154. hilog.info(0x0000, 'testTag', '%{public}s', `Set WindowPortrait, portrait: ${this.portrait}`);
    155. if (!this.portrait) {
    156. window.getLastWindow(getContext(this), (err: BusinessError, win) => {
    157. win.setPreferredOrientation(window.Orientation.PORTRAIT)
    158. });
    159. this.portrait = true;
    160. } else {
    161. router.back();
    162. }
    163. }
    164. /**
    165. * 设置横屏(正向)
    166. */
    167. private setWindowLandscape() {
    168. hilog.info(0x0000, 'testTag', '%{public}s', `Set WindowLandscape, portrait: ${this.portrait}`);
    169. if (this.portrait) {
    170. window.getLastWindow(getContext(this), (err: BusinessError, win) => {
    171. win.setPreferredOrientation(window.Orientation.LANDSCAPE)
    172. });
    173. this.portrait = false;
    174. }
    175. }
    176. private initData() {
    177. this.initCountDownText();
    178. }
    179. private initCountDownText() {
    180. const decodeText = this.decodeString(this.adOptions?.placementAdCountDownDesc as string);
    181. if (!this.isBlank(decodeText)) {
    182. this.countDownTxtPlaceholder = this.countDownTxtPlaceholder.replace('%s', decodeText);
    183. } else {
    184. this.countDownTxtPlaceholder = '%d';
    185. }
    186. }
    187. private updateCountDownTxt(leftTime: number) {
    188. hilog.info(0x0000, 'testTag', '%{public}s', `Show LeftTime: ${leftTime}`);
    189. this.countDownTxt = this.countDownTxtPlaceholder.replace('%d', leftTime + '');
    190. }
    191. private decodeString(str: string): string {
    192. if (!str) {
    193. return str;
    194. }
    195. let decodeUrl = str;
    196. try {
    197. decodeUrl = decodeURIComponent(str.replace(/\+/g, '%20'));
    198. } catch (e) {
    199. hilog.error(0x0000, 'testTag', '%{public}s', `Failed to decodeURIComponent, code:${e.code}, msg: ${e.message}`);
    200. }
    201. return decodeUrl;
    202. }
    203. private isBlank(str: string): boolean {
    204. if (str === null || str === undefined) {
    205. return true;
    206. }
    207. if (typeof str === 'string') {
    208. return str.trim().length === 0;
    209. }
    210. return false;
    211. }
    212. }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2232531.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

基于 Transformer 的语言模型

基于 Transformer 的语言模型 Transformer 是一类基于注意力机制&#xff08;Attention&#xff09;的模块化构建的神经网络结构。给定一个序列&#xff0c;Transformer 将一定数量的历史状态和当前状态同时输入&#xff0c;然后进行加权相加。对历史状态和当前状态进行“通盘…

【天线&运输】冲浪者检测系统源码&数据集全套:改进yolo11-DySnakeConv

改进yolo11-SCConv等200全套创新点大全&#xff1a;冲浪者检测系统源码&#xff06;数据集全套 1.图片效果展示 项目来源 人工智能促进会 2024.11.03 注意&#xff1a;由于项目一直在更新迭代&#xff0c;上面“1.图片效果展示”和“2.视频效果展示”展示的系统图片或者视频可…

计算机毕业设计Hadoop+Spark大模型微博情感分析 微博舆情分析 微博爬虫 微博可视化 微博大数据分析 微博大数据 大数据毕业设计 Hive数据仓库

温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 作者简介&#xff1a;Java领…

WPF中如何简单的使用MvvmLight创建一个项目并进行 增删改查

第一步&#xff1a;创建项目后下载如下两个NuGet程序包&#xff0c;然后删除删掉using Microsoft.Practices.ServiceLocation; 并且引入using CommonServiceLocator; 第二步&#xff1a;删除原来的XAML文件并创建如下的包结构然后创建一个在View文件夹中创建一个Main窗体 再将…

java项目之校园资料分享平台(springboot)

风定落花生&#xff0c;歌声逐流水&#xff0c;大家好我是风歌&#xff0c;混迹在java圈的辛苦码农。今天要和大家聊的是一款基于springboot的校园资料分享平台。项目源码以及部署相关请联系风歌&#xff0c;文末附上联系信息 。 项目简介&#xff1a; 校园资料分享平台的主要…

Spring Security-02-Spring Security认证方式-HTTP基本认证、Form表单认证、HTTP摘要认证、前后端分离安全处理方案

Lison <dreamlison163.com>, v1.0.0, 2024.06.01 Spring Security-02-Spring Security认证方式-HTTP基本认证、Form表单认证、HTTP摘要认证、前后端分离安全处理方案 文章目录 Spring Security-02-Spring Security认证方式-HTTP基本认证、Form表单认证、HTTP摘要认证、…

2-9 存储管理

9.1 传统磁盘管理 1.添加磁盘 在关闭虚拟机情况下添加磁盘(SATA) 别忘记点确定&#xff01;&#xff01;&#xff01; 重启虚拟机&#xff0c;并查看磁盘情况 [rootlocalhost ~]# lsblk NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS sda 8:0 0 20G…

word及Excel常见功能使用

最近一直在整理需规文档及表格&#xff0c;Word及Excel需要熟练使用。 Word文档 清除复制过来的样式 当复制文字时&#xff0c;一般会带着字体样式&#xff0c;此时可选中该文字 并使用 ctrlshiftN 快捷键进行清除。 批注 插入->批注&#xff0c;选中文本 点击“批注”…

【Linux 27】HTTP 协议中的 cookie 和 session

文章目录 &#x1f308;一、Cookie 的相关概念⭐ 1. Cookie 的概念⭐ 2. Cookie 的工作原理⭐ 3. Cookie 的分类⭐ 4. Cookie 的用途⭐ 5. Cookie 设置的基本格式⭐ 6. Cookie 设置时的注意事项⭐ 7. Cookie 的生命周期⭐ 8. Cookie 的安全性问题 &#x1f308; 二、Session 的…

SQL用一个字段查询出数据的交集

出个SQL查询的题吧&#xff0c;有兴趣的可以看看 1、问题 下面有一份数据&#xff08;图1&#xff09;&#xff0c;由两部分组成&#xff1a;分析数据和基准数据 分析数据标识列为1&#xff0c;基准数据标识列为1&#xff0c;两字段0,1互斥 要求&#xff1a;按找出两部分数据…

后端java——如何为你的网页设置一个验证码

目录 1、工具的准备 2.基本方法 3.实现类 4.实践 HTML文件&#xff1a; Java文件1:创建验证码 Java文件2:验证验证码 本文通过HUTOOL实现&#xff1a;Hutool参考文档Hutool&#xff0c;Java工具集https://hutool.cn/docs/#/ 1、工具的准备 如果我们通过hutool来实现这个…

【Python单元测试】pytest框架单元测试 配置 命令行操作 测试报告 覆盖率

单元测试&#xff08;unit test&#xff09;&#xff0c;简称UT。本文将介绍在Python项目中&#xff0c;pytest测试框架的安装&#xff0c;配置&#xff0c;执行&#xff0c;测试报告与覆盖率 pytest简介 pytest是一款流行的&#xff0c;简单易上手的单元测试框架&#xff0c;…

HTMLCSS:呈现的3D树之美

效果演示 这段代码通过HTML和CSS创建了一个具有3D效果的树的图形&#xff0c;包括分支、树干和阴影&#xff0c;通过自定义属性和复杂的变换实现了较为逼真的立体效果。 HTML <div class"container"><div class"tree"><div class"…

练习LabVIEW第三十八题

学习目标&#xff1a; 刚学了LabVIEW&#xff0c;在网上找了些题&#xff0c;练习一下LabVIEW&#xff0c;有不对不好不足的地方欢迎指正&#xff01; 第三十八题&#xff1a; 创建一个VI&#xff0c;实现对按钮状态的指示和按钮“按下”持续时间简单计算功能&#xff0c;按…

HomeAssistant自定义组件学习-【二】

#要说的话# 前面把中盛科技的控制器组件写完了。稍稍熟悉了一些HA&#xff0c;现在准备写窗帘控制组件&#xff0c;构想的东西会比较多&#xff0c;估计有些难度&#xff0c;过程会比较长&#xff0c;边写边记录吧&#xff01; #设备和场景环境# 使用的是Novo的电机&#xf…

Linux脚本数组与字符串

文章目录 打印数组与长度数组遍历数组赋值下标索引访问切片追加()删除关联数组(像map)字符串字符拼接截取子串字符串长度字符串替换模式匹配截取分割字符串大小写转换 打印数组与长度 ${arrayName[*]} 打印数组${arrayName[]} 打印数组${#arrayName[*]} 打印数组长度${#arrayN…

闯关leetcode——3289. The Two Sneaky Numbers of Digitville

大纲 题目地址内容 解题代码地址 题目 地址 https://leetcode.com/problems/the-two-sneaky-numbers-of-digitville/description/ 内容 In the town of Digitville, there was a list of numbers called nums containing integers from 0 to n - 1. Each number was suppos…

#Jest进阶知识:整合 webpack 综合练习

这一小节&#xff0c;我们来做一个综合的练习&#xff0c;该练习会整合&#xff1a; typescriptwebpackjest 准备工作 首先创建项目目录&#xff0c;通过 npm init -y 进行初始化。 整个项目我们打算使用 typescript 进行开发&#xff0c;因此需要安装 typescript npm i t…

MATLAB——矩阵操作

内容源于b站清风数学建模 数学建模清风老师《MATLAB教程新手入门篇》https://www.bilibili.com/video/BV1dN4y1Q7Kt/ 目录 1.MATLAB中的向量 1.1向量创建方法 1.2向量元素的引用 1.3向量元素修改和删除 2.MATLAB矩阵操作 2.1矩阵创建方法 2.2矩阵元素的引用 2.3矩阵…

原生鸿蒙应用市场开发者服务的技术解析:从集成到应用发布的完整体验

文章目录 引言一、鸿蒙原生应用的高效开发二、用户隐私保护&#xff1a;安全访问管理三、开发者实用工具&#xff1a;应用分析与A/B测试四、应用审核与分发&#xff1a;快速上线4.1 应用加密&#xff1a;保护代码安全4.2 自动化测试与检测前移&#xff1a;提升应用质量 五、结语…