一键多环境构建——用 Hvigor 玩转 HarmonyOS Next

引言

在 HarmonyOS Next 的应用开发中,常常需要针对不同环境(测试、预发、线上)或不同签名(调试、正式)输出多个 APP/HAP 包。虽然 HarmonyOS 提供了多目标构建(Multi-Target Build)能力,可以在同一项目里配置多个 product 并生成不同包名的多个产物,但某些深度定制(如动态修改 module.json5 中的 client_idapp_id,或基于构建时间改写输出包名)仍需借助自定义 Hvigor 插件来完成。

结合示例项目,演示如何通过 Hvigor 插件配合多目标构建,实现:

  1. 统一管理各环境的 API 地址、埋点地址等配置;
  2. 动态注入 clientIdappId 等应用信息;
  3. 基于构建时间和 product 名称,定制化输出包名,便于后续上架和线上排查。

一、在项目中使用 Hvigor 自定义插件

1. Hvigor 插件的入口

在 HarmonyOS 项目根目录存在入口文件 hvigorfile.ts,将自定义 task 注册到 plugins 中:

// 文件:hvigorfile.ts
import { buildSchemaProcessing } from './scripts/build-schema-processing';export default {system: appTasks,             // Hvigor 内置任务,不可修改plugins: [buildSchemaProcessing()     // 自定义插件:动态修改 module.json5、build-profile.json5 等]
};

点击 DevEco Studio 上方的 Sync Now 或执行 hvigor sync,即可将插件加载到构建流程中。


2. Hvigor 常用 API 概览

在自定义插件代码中,我们通常会用到以下核心 API:

  • hvigor.getRootNode():获取根节点,进而拿到各插件上下文
  • rootNode.getContext(pluginId):获取指定插件的上下文对象,例如 OHOS_APP_PLUGINOHOS_HAP_PLUGIN
  • context.getAppJsonOpt() / getModuleJsonOpt():读取 app.json5module.json5 的 AST 对象
  • context.getBuildProfileOpt():读取根目录 build-profile.json5 的 AST 对象
  • context.setAppJsonOpt() / setBuildProfileOpt():将修改后的 AST 写回,生效于后续构建
// 示例:读取上下文
const root = hvigor.getRootNode();
const appCtx = root.getContext(OhosPluginId.OHOS_APP_PLUGIN) as OhosAppContext;
const hapCtx = root.getContext(OhosPluginId.OHOS_HAP_PLUGIN) as OhosAppContext;
const appJson = appCtx.getAppJsonOpt();
const modJson = hapCtx.getModuleJsonOpt();
const buildProfile = appCtx.getBuildProfileOpt();// 修改后需要重新 set 回去
appCtx.setAppJsonOpt(appJson);
appCtx.setBuildProfileOpt(buildProfile);

在这里插入图片描述


二、结合多目标构建与自定义插件 实现环境切换

1. 规范 Product 命名

为了脚本中便于解析,我们约定 productname 采用下划线分隔、固定格式:

<应用标识>_<签名标识>_<环境标识>
例如:demo1_debug_test、demo1_release_preRelease、demo2_debug_official

build-profile.json5 中配置多个 product:

"products": [{"name": "demo1_debug_test","signingConfig": "debug","buildOption": {"arkOptions": {"buildProfileFields": {"productsName": "demo1","buildTime": "","apiUrl": "","trackApiUrl": ""}}}},{"name": "demo1_release_officiallyReleased","signingConfig": "release","buildOption": { /* 同上 */ }},/* 更多 product 配置… */
]

TipbuildProfileFields 下的字段会被注入到应用运行时,便于在代码中读取环境信息。


2. 本地配置文件:config.json

将各环境的 API 地址,以及各应用的 clientId/appId 信息集中管理:

{"environmentInfo": {"test": {"apiUrl": "https://api.test.com","trackApiUrl": "https://stat.test.com"},"preRelease": {"apiUrl": "https://api-pre.example.com","trackApiUrl": "https://stat-pre.example.com"},"officiallyReleased": {"apiUrl": "https://api.prod.com","trackApiUrl": "https://stat.prod.com"}},"appConfigInfo": {"demo1": {"clientId": "111898773","appId": "5765880207855284373"},"demo2": {"clientId": "6917571239128090930","appId": "6917571239128090930"}}
}

并提供两个辅助函数,在插件中使用:

// scripts/config.ts
import cfgRaw from '../config.json';
import { format } from 'date-fns';export function formatBuildTime(date = new Date()): string {const pad = (n: number) => String(n).padStart(2, '0');return `${date.getFullYear()}-${pad(date.getMonth()+1)}-${pad(date.getDate())}`+ `_${pad(date.getHours())}-${pad(date.getMinutes())}-${pad(date.getSeconds())}`;
}export function getLocalConfig() {const cfg = JSON.parse(JSON.stringify(cfgRaw));cfg.buildTime = formatBuildTime();return cfg;
}

3. 插件实现核心逻辑

build-schema-processing.ts 中,利用 Hvigor 生命周期钩子完成配置注入与产物重命名。

// scripts/build-schema-processing.ts
import { getLocalConfig } from './config';export function buildSchemaProcessing() {const localCfg = getLocalConfig();let currentProduct = '', versionName = '', bundleName = '', appConfig: any;return {pluginId: 'custom-build-processor',apply(hvigor) {hvigor.getRootNode().afterNodeEvaluate(root => {// 获取上下文const appCtx = root.getContext(OhosPluginId.OHOS_APP_PLUGIN) as OhosAppContext;const hapCtx = root.getContext(OhosPluginId.OHOS_HAP_PLUGIN) as OhosAppContext;const buildProfile = appCtx.getBuildProfileOpt();const appJson = appCtx.getAppJsonOpt();const modJson = hapCtx.getModuleJsonOpt();// 当前 product 信息currentProduct = appCtx.getCurrentProduct().getProductName() || '';versionName = appJson.app.versionName;const productKeys = currentProduct.split('_');const appKey = productKeys[0];const envKey = productKeys[2];appConfig = localCfg.appConfigInfo[appKey];const envConfig = localCfg.environmentInfo[envKey];// 注入 app.json5 中的 clientId、appIdif (modJson) {modJson['module']['appId'] = appConfig.appId;modJson['module']['clientId'] = appConfig.clientId;hapCtx.setModuleJsonOpt(modJson);}// 遍历各 product,注入环境 & 时间 & 重命名 artifact(buildProfile.app.products || []).forEach((prd: any) => {prd.buildOption.arkOptions.buildProfileFields.buildTime  = localCfg.buildTime;prd.buildOption.arkOptions.buildProfileFields.apiUrl     = envConfig.apiUrl;prd.buildOption.arkOptions.buildProfileFields.trackApiUrl= envConfig.trackApiUrl;const suffix = `${appKey}_${versionName}_${localCfg.buildTime}`;if (prd.name === currentProduct) {bundleName = prd.bundleName || appJson.app.bundleName;}prd.output.artifactName = `AtomicPlatform-${suffix}`;});appCtx.setBuildProfileOpt(buildProfile);});hvigor.buildFinished(() => {console.log(`📅 构建时间: ${localCfg.buildTime}`);console.log(`📦 当前产物: ${currentProduct}`);console.log(`🔖 包名(bundleName): ${bundleName}`);console.log(`🆔 ClientID: ${appConfig.clientId}`);console.log(`🆔 AppID: ${appConfig.appId}`);});}};
}

在这里插入图片描述


三、运行效果与日志验证

执行 hvigor build,在日志中即可看到注入与重命名结果:

====================== 编译包信息 ======================
📅 构建时间:  2025-04-24_09-32-05
📦 当前产物: demo2_debug_test
🔖 包名: com.atomicservice.6917571239128090930
🆔 ClientID: 6917571239128090930
🆔 AppID: 6917571239128090930
====================================================

同时,输出的 HAP 包会命名为:

AtomicPlatform-demo2_1.0.0_2025-04-24_09-32-05.hap

通过上述方式,每次在不同 product 与环境下编译,都能自动完成配置注入与产物重命名,极大提升了多环境多签名的开发与发布效率。


四、总结

  • 统一管理:将环境信息、应用信息集中在 config.json,便于维护与扩展;
  • 自动注入:借助 Hvigor 插件,在构建阶段动态修改 module.json5build-profile.json5,免去手动切换;
  • 定制产物:基于构建时间与 product 名称,自定义输出包名,方便版本追踪与线上排查。

未来可在插件中进一步添加:

  1. 构建报告自动上传到 CI/CD 平台;
  2. 自动生成构建差异对比的 HTML 报告;
  3. 与 Git 提交、发布流程集成,构建完成自动触发审核或推送。

五、源码仓库

仓库分支参考:feature/hvigorfileBuild

仓库地址:MultiBuildDemo: 构建多目标产物 - Gitee.com

六、参考文档

扩展构建-编译构建-DevEco Studio - 华为HarmonyOS开发者

HarmonyOS Next 编译之如何构建不同包名应用在日常的开发中涉及到多签名和多产物构建输出时手动切换签名文件和包 - 掘金

HarmonyOS多环境+多渠道+自定义路径输出+自定义名称一键打app和hap包前言 做移动端开发时,不可避免的会遇到 - 掘金
sumer/cn/doc/harmonyos-guides/ide-build-expanding)

HarmonyOS Next 编译之如何构建不同包名应用在日常的开发中涉及到多签名和多产物构建输出时手动切换签名文件和包 - 掘金

HarmonyOS多环境+多渠道+自定义路径输出+自定义名称一键打app和hap包前言 做移动端开发时,不可避免的会遇到 - 掘金

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

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

相关文章

qt/c++云对象浏览器

简介 本项目为基于QT5和C11的云对象存储可视化管理工具 源码获取 int main(){ printf("源码联系绿泡泡:%s","joyfelic"); return 0; }

【Ubuntu】提升 docker ps -a 输出的可读性:让 Docker 容器状态更清晰

提升 docker ps -a 输出的可读性&#xff1a;让 Docker 容器状态更清晰 当我们使用 docker ps -a 查看所有 Docker 容器时&#xff0c;输出的信息通常会非常多&#xff0c;尤其是在容器数量较多时。默认输出中包含容器 ID、名称、镜像、状态、端口等信息&#xff0c;容易让人眼…

Spring Security自定义身份认证

尽管项目启动时&#xff0c;Spring Security会提供了默认的用户信息&#xff0c;可以快速认证和启动&#xff0c;但大多数应用程序都希望使用自定义的用户认证。对于自定义用户认证&#xff0c;Spring Security提供了多种认证方式&#xff0c;常用的有In-Memory Authentication…

在亚马逊云服务器上部署WordPress服务

在亚马逊云服务器上部署WordPress服务第一步&#xff1a;创建EC2实例第二步&#xff1a;初始设置与安装第三步&#xff1a;配置MySQL与WordPress第四步&#xff1a;配置Apache与WordPress第五步&#xff1a;访问WordPress第六步&#xff1a;测试数据库连接第七步&#xff1a;使…

Web3.0的认知补充(去中心化)

涉及开发技术&#xff1a; Vue Web3.js Solidity 基本认知 Web3.0含义&#xff1a; 新一代互联网思想&#xff1a;去中心化及用户为中心的互联网 数据&#xff1a;可读可写可授权 核心技术&#xff1a;区块链、NFT 应用&#xff1a;互联网上应用 NFT &…

如何修复宝可梦时时刻刻冒险无法正常工作

宝可梦的时时刻刻冒险模式是一项强大的功能&#xff0c;即使应用程序关闭&#xff0c;它也能追踪你的步行距离。它的工作原理是将你的步数与 iOS 上的 Apple Health 或 Android 上的 Google Fit 同步。它对于孵化宝可梦蛋和赚取好友糖果至关重要&#xff0c;但一旦它停止工作&a…

redis常用集合操作命令

在 Redis 的命令行界面&#xff08;redis-cli&#xff09;中&#xff0c; Redis 的集合&#xff08;Set&#xff09;是无序的&#xff0c;且集合中的元素是唯一的。Redis 本身没有直接提供获取集合中某个特定属性的命令&#xff0c;因为集合中的元素是简单的值&#xff0c;而不…

初识数据结构——二叉树从基础概念到实践应用

数据结构专栏 ⬅(click) 初识二叉树&#xff1a;从基础概念到实践应用&#x1f333; 一、树型结构基础 1.1 树的基本概念 树是一种非线性的数据结构&#xff0c;由n(n>0)个有限节点组成一个具有层次关系的集合。它看起来像一棵倒挂的树&#xff0c;根朝上而叶朝下。 关键特…

驼峰命名法(Camel Case)与匈牙利命名法(Hungarian Notation)详解

驼峰命名法&#xff08;Camel Case&#xff09;与匈牙利命名法&#xff08;Hungarian Notation&#xff09;详解及对比‌ ‌1. 驼峰命名法&#xff08;Camel Case&#xff09;‌ ‌定义‌ 驼峰命名法&#xff08;Camel Case&#xff09;是一种变量、函数、类等标识符的命名方…

keil 中优化等级的bug

一&#xff0c;问题描述 程序中代码有的执行&#xff0c;有的不执行&#xff0c;仔细研究&#xff0c;查询人工智能。 程序中printf打印后面的代码不执行&#xff0c; 然后过几十个函数又开始正常了。 二.分析问题 跳过函数一般又判断和Goto等语句&#xff0c;其它的溢出和错误…

织梦dedecms网站如何修改上一篇下一篇的标题字数

一般情况下&#xff0c;如果你的上一篇和下一篇是2行布局就不需要限制标题的字数了&#xff0c;如果你要一行布局上一篇和下一篇标题过长就会打乱网页布局&#xff0c;那么限制上一篇和下一篇的标题字数是需要的&#xff0c;避免页面看起来杂乱不堪。 织梦dedecms网站如何修改…

信创系统 sudoers 权限配置实战!从小白到高手

好文链接&#xff1a;实战&#xff01;银河麒麟 KYSEC 安全中心执行控制高级配置指南 Hello&#xff0c;大家好啊&#xff01;今天给大家带来一篇关于信创终端操作系统中 sudoers 文件详解的实用文章&#xff01;在 Linux 系统中&#xff0c;sudo 是一项非常重要的权限控制机制…

《明解C语言入门篇》读书笔记四

目录 第四章&#xff1a;程序的循环控制 第一节&#xff1a;do语句 do语句 复合语句&#xff08;程序块&#xff09;中的声明 读取一定范围内的值 逻辑非运算符 德摩根定律 德摩根定律 求多个整数的和及平均值 复合赋值运算符 后置递增运算符和后置递减运算符 练习…

vite+vue2+elementui构建之 vite.config.js

webpack版本太低&#xff0c;构建依赖太多&#xff0c;头大。 各种查阅资料&#xff0c;弄了一份直通构建vite构建elementUi核心文件&#xff0c; 构建基于开源若依vue2vue3版本改造&#xff0c;感谢开源&#xff0c;感谢若依。 package.json 地址 vitevue2elementui构建之…

超参数详解:从基础概念到优化策略的全面指南

摘要 本文深入解析机器学习中超参数的核心概念&#xff0c;详细对比参数与超参数的本质区别&#xff0c;系统介绍学习率、隐含层数量等常见超参数类型&#xff0c;以及网格搜索、贝叶斯优化等主流寻优方法。结合超参数搜索的标准流程&#xff0c;通过具体案例演示如何高效调整…

计算机视觉与深度学习 | LSTM原理及与卡尔曼滤波的融合

长短期记忆网络(LSTM)是一种特殊的循环神经网络(RNN),旨在解决传统RNN在处理长序列数据时出现的梯度消失和梯度爆炸问题。以下为你详细介绍其基本原理: 核心思想:LSTM的核心思想是引入记忆单元和门控机制来控制信息的流动,从而解决传统RNN的梯度消失问题。记忆单元类似…

EXCEL常用函数公式和VBA汇总第二篇

系列文章目录 文章目录 系列文章目录前言一、excel公式应用1.rand函数2.rand函数随机排序3.rand函数提取数据4.correl函数5.SUBSTITUTE函数6.MAX组合函数7.分析下班时间8.柏拉图自动排序 总结 前言 一、excel公式应用 1.rand函数 用excel生成1-5的随机数字&#xff0c;其中对…

iOS 类与对象底层原理

iOS 类与对象底层原理 文章目录 iOS 类与对象底层原理探索对象本质objc_setProperty 源码cls与类的关联原理联合体isa的类型isa_t 原理探索initIsa方法通过setClass方法中的shiftcls来验证绑定的一个流程通过 isa & ISA_MSAK通过object_getClass通过位运算 类&类的结构…

浮点数:IEEE 754标准

IEEE 754 标准是一种由电气和电子工程师协会&#xff08;IEEE&#xff09;制定的浮点数表示的标准&#xff0c;广泛应用于计算机系统中&#xff0c;下面是详细介绍&#xff1a; 历史背景 在 IEEE 754 标准出现之前&#xff0c;不同的计算机系统采用各自的浮点数表示方法&…

centos7部署k8s集群

环境准备 服务器三台 10.0.0.70master 10.0.0.71worker1 10.0.0.72worker2 配置yum源&#xff08;集群机器执行&#xff09; wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo 安装常用软件 yum -y install lrzsz vim net-tools关闭f…