基于鸿蒙OS开发静脉输液智能监控系统(2)-开发环境搭建与项目构建
基于鸿蒙OS开发静脉输液智能监控系统(2)-开发环境搭建与项目构建
目录
- 1. HarmonyOS 平台概述
- 2. DevEco Studio 环境搭建
- 3. 项目创建流程
- 4. 项目配置文件深度解析
- 5. 构建流程详解
- 6. IVGuard 项目构建实践
- 7. 常见构建问题与解决方案
- 8. CI/CD 集成建议
1. HarmonyOS 平台概述
1.1 OpenHarmony vs HarmonyOS
HarmonyOS 生态中存在两个密切相关但定位不同的操作系统版本:OpenHarmony 和 HarmonyOS。理解二者的区别对于项目选型和技术决策至关重要。
1.1.1 OpenHarmony:开源基础
OpenHarmony 是由开放原子开源基金会(OpenAtom Foundation)托管的开源项目,是 HarmonyOS 的开源基础底座。它具备以下核心特征:
- 完全开源:代码托管在 Gitee,遵循 Apache License 2.0 协议,任何人都可以自由使用、修改和分发
- 社区驱动:由华为、润和软件、软通动力等多家企业共同参与共建,采用社区治理模式
- 基础能力:提供了分布式软总线、分布式数据管理、分布式任务调度等核心分布式能力,以及基础的 UI 框架、应用框架和安全机制
- 设备适配:主要面向轻量级 IoT 设备(如智能手表、智能家居)、小型设备以及部分标准设备
- SDK 独立性:OpenHarmony 提供独立的 SDK,可通过 DevEco Studio 下载使用,API 以
@ohos.*命名空间为主
1.1.2 HarmonyOS:华为商业版
HarmonyOS 是华为基于 OpenHarmony 内核打造的商业操作系统,在开源基础上增加了大量华为专有的商业能力和服务:
- 闭源扩展:在 OpenHarmony 基础上叠加了华为专有的闭源模块,包括 HMS Core(华为移动服务)、华为云服务集成、华为账号体系等
- 商业服务:集成华为应用市场(AppGallery)、华为钱包、华为支付等商业生态
- 高级 API:提供了
@kit.*命名空间下的高级 Kit API,如@kit.AbilityKit、@kit.ArkData、@kit.CameraKit等,这些 API 在纯 OpenHarmony 环境中不可用 - 安全增强:增加了更严格的安全审核机制、应用签名校验、数字盾服务等企业级安全能力
- 多设备协同:深度融合华为"1+8+N"全场景战略,实现手机、平板、PC、手表、车机等设备间的无缝协同
- 应用市场分发:通过华为 AppGallery 进行应用分发,需要遵循华为的上架审核规范
1.1.3 IVGuard 的选择
IVGuard 项目选择基于 HarmonyOS 商业版进行开发,主要原因如下:
| 维度 | OpenHarmony | HarmonyOS | IVGuard 选择理由 |
|---|---|---|---|
| API 丰富度 | 基础 API | 基础 + Kit API | 需要 @kit.CameraKit(相机监控)、@kit.ArkData(数据持久化)等 Kit API |
| 设备适配 | IoT / 小型设备为主 | 全品类设备 | 目标运行在华为手机/平板上 |
| 分发渠道 | 侧载安装 | AppGallery | 计划通过 AppGallery 分发给医院和患者 |
| NFC 支持 | 基础 NFC API | 增强的 NFC 标签读取 | 需要读取 NFC 贴纸中的药物信息 |
| 通知服务 | 基础通知 | 增强通知 + 后台保活 | 输液结束提醒需要可靠的后台通知 |
1.2 API 版本演进
HarmonyOS 的 API Level 体系经历了从 API 9 到 API 24 的重大演进,每次版本迭代都带来了新的能力和架构变化。
1.2.1 关键版本里程碑
API 9 (OpenHarmony 3.2) ─── Stage 模型成熟,ArkUI 声明式范式确立
│
API 10 (OpenHarmony 4.0) ─── ArkTS 语言正式定名,strict mode 引入
│
API 11 (HarmonyOS 4.0) ─── @kit 命名空间引入,Kit 化 API 架构
│
API 12 (HarmonyOS 4.1) ─── ArkTS 严格模式全面推行,性能优化
│
API 13-14 ─── 过渡版本,安全增强
│
API 24 (SDK 6.1.1) ─── HarmonyOS 5.0,IVGuard 使用版本
1.2.2 API 9 到 API 12 的重大变化
API 9 是 Stage 模型(Stage Model)走向成熟的标志版本。在这个版本中:
- Stage 模型成为推荐的应用开发模型,替代了早期的 FA(Feature Ability)模型
- ArkUI 声明式开发范式确立,
@Component、@State、@Entry等装饰器成为标准 - module.json5 替代了 FA 模型中的
config.json,成为模块配置的标准文件 - UIAbility 替代了 Ability,生命周期管理更加清晰
API 10 带来了 ArkTS 语言的正式定名:
- ArkTS 作为 TypeScript 的超集被正式命名,增加了静态类型约束和性能优化
- @ohos. API* 命名空间基本定型
- hvigor 构建系统替代了早期的 Gradle 构建方案
API 11 引入了 Kit 化 API 架构:
- @kit. 命名空间*引入,将 API 按 Kit 分组,如
@kit.AbilityKit、@kit.ArkUI、@kit.ArkData - 旧的
@ohos.*API 仍可使用,但新 API 优先以 Kit 形式提供 - 引入了更严格的安全沙箱机制
API 12 推行了 ArkTS 严格模式:
- arkts-no-standalone-this:禁止在
@Component外使用this - arkts-no-any-unknown:禁止使用
any和unknown类型 - arkts-no-structural-type:禁止结构类型,强制使用类(class)
- arkts-no-destructuring:限制解构赋值的使用
- 这些限制确保了 ArkTS 代码在方舟编译器(Ark Compiler)上的高效执行
1.2.3 API Level 24 的核心变化
IVGuard 使用的 API Level 24(对应 SDK 版本 6.1.1(24))是 HarmonyOS 5.0 的 API 版本,带来了以下重要变化:
Ability Kit 增强:
- AbilityStage 组件管理器新增 AbilityStage 即将创建第一个 Ability 的回调
- 新增进程从应用快照启动时的回调
- Ability 上次退出的信息字段新增支持获取退出原因
ArkTS 语言增强:
- 新增
enableLocalHandleDetection接口,保证 EventHandler 和 libuv 机制的任务在 scope 范围内执行,避免内存泄漏 - XML 解析新增支持
XmlSAXHandler - 虚拟机维测能力增强:新增获取所有虚拟机线程的堆内存信息
- taskpool 的 execute 方法增强,支持指定任务超时时长
Camera Kit 专业能力扩展(对 IVGuard 的视觉监控功能尤其重要):
- 新增闪光灯状态变化事件回调的订阅/取消订阅
- 新增光学防抖(OIS)相关参数的查询和设置
- 相机设备定义中新增镜头焦距、等效焦距、最小对焦距离等详细信息
- 新增逻辑摄像头管理能力
- 相机曝光设置增强:新增自动曝光和手动曝光能力
- 新增手动对焦、手动 ISO 感光度、物理光圈设置能力
- 新增延迟预览输出对象
ArkUI 组件增强:
- 自定义组件支持跨 Ability 迁移
- Tabs 组件新增支持嵌套滚动
- 新增动态布局容器组件,支持运行时动态切换布局算法
- Text 组件新增支持根据坐标获取最近字符位置
- 新增拖拽异步通知接口
- 新增
onNeedSoftkeyboard回调,支持焦点转移后不关闭软键盘
ArkData 数据能力:
- 新增创建或打开关系型数据库的同步方法
1.2.4 IVGuard 的 API 版本配置
在 IVGuard 项目的 build-profile.json5 中,API 版本配置如下:
{
"app": {
"products": [
{
"name": "default",
"signingConfig": "default",
"targetSdkVersion": "6.1.1(24)",
"compatibleSdkVersion": "6.1.1(24)",
"runtimeOS": "HarmonyOS"
}
]
}
}
- targetSdkVersion:指定编译时使用的 SDK 版本,决定了可以使用的 API 集合
- compatibleSdkVersion:指定应用最低兼容的 SDK 版本,低于此版本的设备无法安装应用
- IVGuard 将两者都设为
6.1.1(24),意味着应用仅在 HarmonyOS 5.0 及以上版本运行,不需要向后兼容旧版本
1.3 ArkTS 在 HarmonyOS 生态中的定位
1.3.1 ArkTS 是什么
ArkTS 是华为基于 TypeScript 扩展的编程语言,是 HarmonyOS 应用开发的首选和推荐语言。它在 TypeScript 的基础上增加了以下关键特性:
- 静态类型强化:通过严格模式(strict mode)禁止
any、unknown等动态类型,确保编译期类型安全 - 声明式 UI:通过
@Component、@Builder等装饰器和声明式语法,实现 UI 与状态的绑定 - 高性能编译:方舟编译器(Ark Compiler)将 ArkTS 直接编译为机器码,跳过传统 JS 引擎的解释执行和 JIT 编译
- 并发模型:通过 TaskPool 和 Worker 实现高效的多线程并发
ArkTS 与 TypeScript 的关系可以概括为:
TypeScript(超集)──→ ArkTS(约束子集 + 扩展)
│
├── 增加的:@Component/@State/@Entry 装饰器
│ 声明式 UI 语法
│ Sendable 类型系统
│
└── 约束的:禁止 any/unknown
禁止结构类型
限制解构赋值
禁止 standalone this
1.3.2 ArkUI 声明式框架
ArkUI 是 HarmonyOS 的声明式 UI 开发框架,其核心设计理念是状态驱动 UI 更新。当状态变量发生变化时,框架自动重新渲染依赖该状态的 UI 组件,无需手动操作 DOM。
ArkUI 的核心装饰器:
| 装饰器 | 作用 | 使用场景 |
|---|---|---|
@Entry |
标记页面入口组件 | 每个 page 文件的根组件 |
@Component |
标记自定义组件 | 所有自定义组件必须添加 |
@State |
响应式状态变量 | 组件内部状态,变化触发 UI 更新 |
@Prop |
单向数据传递 | 父组件向子组件传递数据 |
@Link |
双向数据绑定 | 父子组件间双向同步数据 |
@Provide/@Consume |
跨层级数据传递 | 祖先组件与后代组件间通信 |
@Watch |
状态变化监听 | 需要在状态变化时执行逻辑 |
@Builder |
轻量 UI 复用 | 封装可复用的 UI 片段 |
以 IVGuard 的 Index 页面为例:
@Entry
@Component
struct Index {
@State currentRole: string = ''
aboutToAppear(): void {
const context = getContext(this) as common.UIAbilityContext
DataStore.init(context).then(() => {
const settings = DataStore.loadSettings()
this.currentRole = settings.role
})
}
build() {
Column() {
Text('IVGuard')
.fontSize(32)
.fontWeight(FontWeight.Bold)
.fontColor('#2196F3')
}
}
}
当 currentRole 被 @State 标记后,任何对其的修改都会自动触发 build() 方法的重新执行,更新对应的 UI 组件。
1.3.3 ArkTS 严格模式
从 API 12 开始,ArkTS 严格模式成为默认编译选项。严格模式下的主要限制包括:
arkts-no-any-unknown:禁止使用 any 和 unknown 类型。所有变量必须有明确的类型声明。
// 错误
let data: any = fetchData()
let result: unknown = parseData()
// 正确
let data: string = fetchData()
let result: Record<string, Object> = parseData()
arkts-no-standalone-this:禁止在 @Component 外部使用 this。在 ArkTS 中,this 只能在 struct 方法内使用。
// 错误
function helper() {
console.log(this.name)
}
// 正确
@Component
struct MyComponent {
@State name: string = ''
build() {
Text(this.name)
}
}
arkts-no-structural-type:禁止使用结构类型,必须使用类(class)进行类型定义。
// 错误 - 使用对象字面量类型
type Person = { name: string; age: number }
// 正确 - 使用 class
class Person {
name: string = ''
age: number = 0
}
arkts-no-destructuring:限制解构赋值的使用,仅允许在特定场景下使用。
// 错误 - 在 build() 方法中使用 const 解构
build() {
const { width, height } = this.dimensions
}
// 正确 - 直接访问属性或使用 @State
build() {
Text(`${this.dimensions.width}`)
}
1.4 HarmonyOS 5.0 新特性
HarmonyOS 5.0(对应 API Level 24)是 2024-2025 年华为发布的最新大版本,带来了以下重要特性:
1.4.1 纯血鸿蒙(Pure HarmonyOS)
HarmonyOS 5.0 彻底移除了 Android AOSP 代码,成为完全自主的操作系统:
- 不再支持 Android 应用兼容运行
- 所有应用必须使用 ArkTS/ArkUI 原生开发
- 系统更加轻量、安全、高效
- 对 IVGuard 而言,这意味着必须使用原生 ArkTS 开发,不存在 Android 兼容的捷径
1.4.2 原生智能
HarmonyOS 5.0 将 AI 能力深度集成到系统层面:
- 小艺智慧助手升级,支持更复杂的自然语言交互
- AI 文本处理:系统级文本摘要、翻译、润色能力
- AI 图像处理:图像识别、图像生成、图像增强能力
- 对 IVGuard 而言,可以利用系统级 AI 能力增强输液瓶液位的视觉识别精度
1.4.3 原生安全
安全能力的全面增强:
- 应用签名校验更严格,未签名应用无法安装
- 数字盾服务扩展到 Tablet、PC 设备
- 代码签名信息查询功能,可获取设备上已签名文件的签名信息
- 系统安全事件监控:进程提权、异常调试、异常崩溃等事件监控
- 对 IVGuard 而言,涉及患者数据的处理必须遵循这些安全规范
1.4.4 原生精致
UI/UX 能力的全面提升:
- 动态布局容器:支持运行时动态切换布局算法
- 自定义组件跨 Ability 迁移:提升多窗口场景的用户体验
- HDR 提亮效果:为组件内容添加高动态范围成像提亮
- 分段按钮状态动画:更好的交互反馈
2. DevEco Studio 环境搭建
2.1 安装与配置
2.1.1 系统要求
DevEco Studio 是 HarmonyOS 应用开发的官方集成开发环境(IDE),基于 IntelliJ IDEA 社区版定制。
Windows 系统要求:
| 项目 | 最低要求 | 推荐配置 |
|---|---|---|
| 操作系统 | Windows 10 64 位 | Windows 11 64 位 |
| 内存 | 8 GB | 16 GB 及以上 |
| 硬盘空间 | 10 GB(IDE + SDK) | 30 GB 及以上(含模拟器镜像) |
| 分辨率 | 1280×800 | 1920×1080 及以上 |
| CPU | x86_64,4 核 | x86_64,8 核及以上 |
macOS 系统要求:
| 项目 | 最低要求 | 推荐配置 |
|---|---|---|
| 操作系统 | macOS 10.14 | macOS 12 及以上 |
| 内存 | 8 GB | 16 GB 及以上 |
| 硬盘空间 | 10 GB | 30 GB 及以上 |
| 架构 | Intel / Apple Silicon | Apple Silicon (M1/M2/M3) |
2.1.2 下载与安装
DevEco Studio 的下载地址为华为开发者官网:https://developer.huawei.com/consumer/cn/deveco-studio/
安装步骤(Windows):
- 下载安装包
DevEco-Studio-xxx-windows.exe - 双击运行安装程序,选择安装路径(路径中不要包含中文、空格和特殊字符)
- 建议安装路径示例:
F:\DevEco Studio(避免C:\Program Files等带空格的路径) - 安装完成后首次启动,DevEco Studio 会自动引导下载 HarmonyOS SDK
- 在 SDK Setup 界面,选择 SDK 安装路径(建议与 IDE 分开存放,如
F:\HarmonyOS\Sdk)
2.1.3 首次启动配置
首次启动 DevEco Studio 后,需要完成以下配置:
- 同意用户协议:阅读并同意 Huawei Developer Terms of Service
- SDK 下载:选择需要下载的 SDK 组件,至少包含:
- HarmonyOS SDK(API 24)
- OpenHarmony SDK(可选)
- SDK Tools(包含 ohpm、hvigor 等工具链)
- Node.js 配置:DevEco Studio 内置了 Node.js 环境,无需单独安装
- ohpm 配置:OpenHarmony Package Manager 会随 SDK 自动安装
2.1.4 环境变量验证
安装完成后,可通过命令行验证关键工具是否可用:
# 检查 Node.js 版本(DevEco Studio 内置)
node --version
# 预期输出:v18.x.x 或更高
# 检查 ohpm 版本
ohpm --version
# 检查 hdc 版本(HarmonyOS Device Connector)
hdc version
# 检查 hvigorw 是否可执行(在项目目录下)
.\hvigorw.bat --version
2.2 SDK 管理
2.2.1 SDK 目录结构
HarmonyOS SDK 安装后的目录结构如下:
HarmonyOS/Sdk/
├── openharmony/ # OpenHarmony SDK
│ └── 24/ # API Level
│ ├── native/ # Native 开发头文件和库
│ └── ets/ # ArkTS/JS API 声明文件
├── harmonyos/ # HarmonyOS SDK
│ └── 24/
│ ├── native/
│ └── ets/
└── toolchains/ # 工具链
├── hdc.exe # HarmonyOS Device Connector
├── ohpm/ # 包管理器
└── hvigor/ # 构建工具
2.2.2 sdk-pkg.json 的作用
sdk-pkg.json 是 SDK 包的元数据描述文件,定义了每个 SDK 组件的版本、依赖关系和下载地址。其核心作用包括:
- 版本管理:记录每个 SDK 组件的版本号和 API Level 对应关系
- 依赖声明:定义组件间的依赖关系,确保安装完整性
- 下载配置:指定组件的下载源和校验信息
当 DevEco Studio 的 SDK Manager 界面展示可用 SDK 列表时,实际上就是读取了远程的 sdk-pkg.json 来获取最新版本信息。
2.2.3 API 24 SDK 安装
IVGuard 需要 API Level 24 的 SDK,安装步骤如下:
- 打开 DevEco Studio
- 进入
File > Settings > HarmonyOS SDK - 在 SDK Platforms 标签页中,勾选
API 24 (6.1.1) - 在 SDK Tools 标签页中,确保以下工具已安装:
HarmonyOS SDK Build ToolsHarmonyOS SDK Platform ToolsOhpmHvigor
- 点击 Apply 开始下载安装
安装完成后,可以在项目的 build-profile.json5 中确认 SDK 版本:
{
"app": {
"products": [
{
"targetSdkVersion": "6.1.1(24)",
"compatibleSdkVersion": "6.1.1(24)"
}
]
}
}
2.2.4 SDK 版本切换
如果需要在多个 API Level 之间切换开发,需要注意:
targetSdkVersion决定了编译时可用的 API 集合compatibleSdkVersion决定了应用可安装的最低系统版本- 降低
compatibleSdkVersion后,需要确保代码中没有使用高版本才有的 API,否则低版本设备会崩溃 - IVGuard 将两者都设为 API 24,意味着不需要处理低版本兼容问题
2.3 模拟器与真机调试
2.3.1 Local Emulator(本地模拟器)
Local Emulator 是运行在开发者本地电脑上的模拟器,使用硬件虚拟化技术(Windows 上使用 Hyper-V 或 Intel HAXM):
优点:
- 响应速度快,与本地网络无延迟
- 不需要华为开发者账号
- 支持断点调试、性能分析等全套开发工具
缺点:
- 需要电脑支持硬件虚拟化(CPU 支持且 BIOS 已开启)
- 消耗本地内存和 CPU 资源(至少分配 4 GB 内存给模拟器)
- 不支持某些需要真机硬件的功能(如 NFC、实际相机传感器)
- 部分系统 API 行为与真机有差异
创建 Local Emulator 的步骤:
- 打开 DevEco Studio,进入
Tools > Device Manager - 点击
New Emulator按钮 - 选择设备类型(Phone / Tablet / Wearable / TV)
- 选择系统镜像(API 24)
- 配置模拟器参数:名称、内存大小、存储大小
- 点击 Create 完成创建
- 点击启动按钮运行模拟器
2.3.2 Remote Simulator(远程模拟器)
Remote Simulator 是运行在华为云端的模拟器,通过网络连接使用:
优点:
- 不消耗本地计算资源
- 无需本地硬件虚拟化支持
- 系统版本与真机一致
缺点:
- 需要华为开发者账号登录
- 网络延迟明显,操作体验不如本地模拟器
- 有使用时长限制
- 不支持某些硬件相关功能
2.3.3 真机调试
真机调试是最接近真实用户体验的调试方式,也是 IVGuard 项目推荐的调试方式(因为项目依赖相机、NFC 等硬件能力):
前置条件:
- 华为手机/平板已升级到 HarmonyOS 5.0
- 设备已开启开发者模式:
设置 > 关于手机 > 连续点击版本号 7 次 - 已开启 USB 调试:
设置 > 系统 > 开发者选项 > USB 调试 - 通过 USB 数据线连接电脑
- 在 DevEco Studio 中配置签名(真机调试必须签名)
连接验证:
# 查看已连接设备
hdc list targets
# 预期输出(设备序列号)
1234567890ABCDEF # 真机设备
签名配置(真机调试必需):
- 在 DevEco Studio 中打开
File > Project Structure > Project > Signing Configs - 勾选
Automatically generate signature - 登录华为开发者账号
- 选择或创建调试证书和 Profile
- 签名信息会自动写入
build-profile.json5的signingConfigs字段
2.3.4 调试方式对比
| 特性 | Local Emulator | Remote Simulator | 真机调试 |
|---|---|---|---|
| 响应速度 | 快 | 中(受网络影响) | 快 |
| 硬件能力 | 部分(虚拟相机) | 部分 | 完整 |
| NFC 支持 | 不支持 | 不支持 | 支持 |
| 相机支持 | 虚拟相机 | 不支持 | 真实相机 |
| 签名要求 | 不需要 | 不需要 | 必须签名 |
| 适用场景 | UI 开发调试 | 临时验证 | 功能完整性验证 |
| IVGuard 适用性 | UI 布局调试 | 不推荐 | 推荐 |
2.4 HDC 工具
2.4.1 HDC 概述
HDC(HarmonyOS Device Connector)是 HarmonyOS 的命令行设备管理工具,功能类似 Android 的 ADB(Android Debug Bridge)。它提供了与 HarmonyOS 设备通信的能力,是开发调试中不可或缺的工具。
HDC 的主要功能包括:
- 设备管理:列出连接的设备、查看设备信息
- 应用管理:安装、卸载、启动应用
- 文件操作:在电脑和设备间推送/拉取文件
- 日志收集:获取设备运行日志(hilog)
- Shell 命令:在设备上执行 shell 命令
- 端口转发:设置端口映射,支持网络调试
2.4.2 常用 HDC 命令
# 设备管理
hdc list targets # 列出所有连接的设备
hdc -t <deviceId> shell # 连接指定设备
# 应用安装与运行
hdc install <hap_path> # 安装 HAP 包
hdc install -r <hap_path> # 覆盖安装
hdc uninstall <bundleName> # 卸载应用
hdc shell aa start -a EntryAbility -b com.example.ivguard # 启动应用
# 日志收集
hdc hilog # 实时查看日志
hdc hilog -T IVGuard # 按 tag 过滤日志
hdc hilog -x # 清除日志缓冲区
# 文件操作
hdc file send <local_path> <remote_path> # 推送文件到设备
hdc file recv <remote_path> <local_path> # 从设备拉取文件
# 端口转发
hdc fport tcp:8080 tcp:8080 # 设置端口转发
# 设备信息
hdc shell param get const.ohos.apiversion # 查看设备 API 版本
hdc shell param get const.product.devicetype # 查看设备类型
2.4.3 IVGuard 开发中的 HDC 使用场景
在 IVGuard 的开发调试中,HDC 主要用于以下场景:
-
安装调试包:将编译好的 HAP 推送到真机进行测试
hdc install F:\projects\IVGuard\entry\build\default\outputs\default\entry-default.hap -
收集运行日志:监控 IVGuard 运行时的日志输出
hdc hilog -T IVGuard -
调试相机功能:查看相机 API 的调用日志
hdc hilog | findstr "Camera" -
调试 NFC 读取:查看 NFC 标签读取的日志
hdc hilog | findstr "NFC"
3. 项目创建流程
3.1 copy-template.mjs 脚本原理
IVGuard 项目使用 DevEco CLI 提供的 copy-template.mjs 脚本进行项目脚手架生成。该脚本的核心原理是一个"复制 → 替换 → 生成"的三步流程。
3.1.1 模板仓库结构
DevEco CLI 维护了一套标准化的 HarmonyOS 项目模板,模板中的关键文件使用占位符标记需要替换的内容:
template/
├── AppScope/
│ ├── app.json5 # 包含 {{BUNDLE_NAME}} 占位符
│ └── resources/base/element/
│ └── string.json # 包含 {{APP_NAME}} 占位符
├── entry/
│ ├── build-profile.json5
│ ├── src/main/
│ │ ├── module.json5
│ │ ├── ets/
│ │ │ ├── entryability/
│ │ │ │ └── EntryAbility.ets
│ │ │ └── pages/
│ │ │ └── Index.ets
│ │ └── resources/
│ │ └── base/
│ │ ├── profile/
│ │ │ └── main_pages.json
│ │ └── element/
│ │ └── string.json
│ └── oh-package.json5
├── build-profile.json5 # 包含 {{SDK_VERSION}} 占位符
├── oh-package.json5
├── hvigorfile.ts
└── hvigor/
└── hvigor-config.json5
3.1.2 三步流程详解
第一步:复制模板(Copy)
脚本首先将模板目录整体复制到目标路径。以 IVGuard 为例:
// 简化的复制逻辑
const templateDir = path.join(__dirname, 'templates', 'empty');
const targetDir = 'F:/projects/IVGuard';
fs.cpSync(templateDir, targetDir, { recursive: true });
这一步生成的是"原始模板",所有占位符尚未替换。
第二步:替换占位符(Replace)
脚本遍历目标目录中的所有文本文件,将占位符替换为用户提供的实际值:
// 简化的替换逻辑
const replacements = {
'{{BUNDLE_NAME}}': 'com.example.ivguard',
'{{APP_NAME}}': 'IVGuard',
'{{SDK_VERSION}}': '6.1.1(24)',
'{{MODULE_NAME}}': 'entry',
};
function replaceInFile(filePath: string): void {
let content = fs.readFileSync(filePath, 'utf-8');
for (const [placeholder, value] of Object.entries(replacements)) {
content = content.replaceAll(placeholder, value);
}
fs.writeFileSync(filePath, content, 'utf-8');
}
第三步:生成项目(Generate)
替换完成后,脚本执行额外的初始化操作:
- 生成
oh-package-lock.json5:运行ohpm install生成依赖锁文件 - 创建
.gitignore:写入 HarmonyOS 项目的标准忽略规则 - 验证项目结构:检查关键文件是否存在且内容合法
3.1.3 IVGuard 项目创建的实际调用
IVGuard 项目的创建命令格式如下:
# 通过 DevEco CLI 创建
devecocli create --name IVGuard --bundle com.example.ivguard --api 24
# 或通过 copy-template.mjs 直接调用
node copy-template.mjs --name IVGuard --bundle com.example.ivguard --api 24 --output F:/projects/IVGuard
创建成功后,会在 F:\projects\IVGuard 目录下生成完整的项目结构。
3.2 模板项目结构解析
通过 copy-template.mjs 生成的 IVGuard 基础项目结构如下:
F:\projects\IVGuard\
├── AppScope/ # 应用级配置与资源
│ ├── app.json5 # 应用标识配置
│ └── resources/ # 应用级资源
│ └── base/
│ ├── element/
│ │ └── string.json # 应用级字符串资源
│ └── media/
│ ├── layered_image.json # 分层图标配置
│ ├── foreground.png # 前景图标
│ └── background.png # 背景图标
├── entry/ # 主模块(HAP)
│ ├── build-profile.json5 # 模块级构建配置
│ ├── hvigorfile.ts # 模块级构建脚本
│ ├── oh-package.json5 # 模块级依赖配置
│ ├── obfuscation-rules.txt # 混淆规则
│ ├── src/
│ │ └── main/
│ │ ├── module.json5 # 模块声明配置
│ │ ├── ets/ # ArkTS 源码
│ │ │ ├── entryability/
│ │ │ │ └── EntryAbility.ets # 入口 Ability
│ │ │ ├── entrybackupability/
│ │ │ │ └── EntryBackupAbility.ets # 备份扩展
│ │ │ └── pages/
│ │ │ └── Index.ets # 首页
│ │ └── resources/ # 模块级资源
│ │ └── base/
│ │ ├── element/
│ │ │ ├── string.json # 字符串资源
│ │ │ ├── color.json # 颜色资源
│ │ │ └── float.json # 尺寸资源
│ │ ├── media/
│ │ │ ├── startIcon.png # 启动图标
│ │ │ ├── layered_image.json
│ │ │ ├── foreground.png
│ │ │ └── background.png
│ │ └── profile/
│ │ ├── main_pages.json # 页面路由
│ │ └── backup_config.json # 备份配置
│ └── .gitignore
├── build-profile.json5 # 工程级构建配置
├── hvigorfile.ts # 工程级构建脚本
├── oh-package.json5 # 工程级依赖配置
├── oh-package-lock.json5 # 依赖锁文件
├── code-linter.json5 # 代码检查配置
├── hvigor/ # Hvigor 构建工具配置
│ └── hvigor-config.json5 # 构建工具版本与参数
└── .gitignore # Git 忽略规则
3.2.1 目录职责说明
AppScope/:应用级作用域,存放全局性的配置和资源。该目录的内容对所有模块可见:
app.json5:定义应用的唯一标识(bundleName)、版本号、图标和名称resources/:应用级资源,如应用图标、应用名称等
entry/:主模块目录,HarmonyOS 中的"入口模块"(entry module),每个应用至少有一个 entry 模块:
build-profile.json5:模块级构建配置,定义编译选项、混淆规则等src/main/ets/:ArkTS 源码目录,所有页面、组件、服务代码都在此处src/main/resources/:模块级资源,包括字符串、颜色、图片、配置文件等module.json5:模块声明文件,定义 Ability、权限、页面路由等
hvigor/:Hvigor 构建工具的配置目录,存放构建工具的版本和运行参数。
根目录文件:
build-profile.json5:工程级构建配置,定义签名、SDK 版本、模块列表等hvigorfile.ts:工程级构建脚本,注册 Hvigor 插件oh-package.json5:工程级依赖声明,类似 npm 的 package.json
3.3 build-profile.json5 配置详解
build-profile.json5 是 HarmonyOS 项目中最核心的构建配置文件,分为工程级和模块级两个层级。
3.3.1 工程级 build-profile.json5
IVGuard 的工程级 build-profile.json5 位于项目根目录,完整内容如下:
{
"app": {
"signingConfigs": [],
"products": [
{
"name": "default",
"signingConfig": "default",
"targetSdkVersion": "6.1.1(24)",
"compatibleSdkVersion": "6.1.1(24)",
"runtimeOS": "HarmonyOS",
"buildOption": {
"strictMode": {
"caseSensitiveCheck": true,
"useNormalizedOHMUrl": true
}
}
}
],
"buildModeSet": [
{
"name": "debug"
},
{
"name": "release"
}
]
},
"modules": [
{
"name": "entry",
"srcPath": "./entry",
"targets": [
{
"name": "default",
"applyToProducts": [
"default"
]
}
]
}
]
}
字段详解:
app.signingConfigs:签名方案配置数组。当前为空数组 [],表示未配置签名,构建时会产生以下警告:
WARN: Will skip sign 'hos_hap'. No signingConfigs profile is configured in current project.
真机调试或应用发布时必须配置签名,典型配置如下:
{
"signingConfigs": [
{
"name": "default",
"type": "HarmonyOS",
"material": {
"certpath": "D:/SigningConfig/debug_hos.cer",
"storePassword": "加密后的密码",
"keyAlias": "debugKey",
"keyPassword": "加密后的密码",
"profile": "D:/SigningConfig/debug_hos.p7b",
"signAlg": "SHA256withECDSA",
"storeFile": "D:/SigningConfig/debug_hos.p12"
}
}
]
}
各字段含义:
| 字段 | 说明 |
|---|---|
name |
签名方案名称,仅支持字母和数字 |
type |
签名类型:HarmonyOS 或 OpenHarmony |
material.certpath |
证书文件路径(.cer 后缀) |
material.storePassword |
密钥库密码(密文存储) |
material.keyAlias |
密钥别名 |
material.keyPassword |
密钥密码(密文存储) |
material.profile |
Profile 文件路径(.p7b 后缀) |
material.signAlg |
签名算法,当前仅支持 SHA256withECDSA |
material.storeFile |
密钥库文件路径(.p12 后缀) |
app.products:产品品类配置数组,可配置多个 product 以实现多目标构建:
| 字段 | 说明 |
|---|---|
name |
Product 名称,如 default |
signingConfig |
关联的签名方案名称 |
targetSdkVersion |
目标 SDK 版本 |
compatibleSdkVersion |
最低兼容 SDK 版本 |
runtimeOS |
运行时操作系统:HarmonyOS 或 OpenHarmony |
buildOption.strictMode |
严格模式选项 |
buildOption.strictMode.caseSensitiveCheck |
大小写敏感检查 |
buildOption.strictMode.useNormalizedOHMUrl |
使用标准化的 OHM URL |
app.buildModeSet:构建模式集合,定义可用的构建模式:
"buildModeSet": [
{ "name": "debug" }, // 调试模式,包含调试信息
{ "name": "release" } // 发布模式,优化性能和包大小
]
modules:模块配置数组,声明项目中包含的所有模块:
| 字段 | 说明 |
|---|---|
name |
模块名称,需与 module.json5 中的 module.name 一致 |
srcPath |
模块源码路径,相对工程根目录 |
targets |
模块 target 列表,用于多目标构建 |
targets[].name |
Target 名称,对应模块级 build-profile.json5 中的 targets |
targets[].applyToProducts |
该 Target 关联的 Product 列表 |
3.3.2 模块级 build-profile.json5
IVGuard 的模块级 build-profile.json5 位于 entry/ 目录下:
{
"apiType": "stageMode",
"buildOption": {
"resOptions": {
"copyCodeResource": {
"enable": false
}
}
},
"buildOptionSet": [
{
"name": "release",
"arkOptions": {
"obfuscation": {
"ruleOptions": {
"enable": false,
"files": [
"./obfuscation-rules.txt"
]
}
}
}
}
],
"targets": [
{
"name": "default"
},
{
"name": "ohosTest"
}
]
}
字段详解:
| 字段 | 说明 |
|---|---|
apiType |
API 模型类型:stageMode(Stage 模型)或 faMode(FA 模型,已弃用) |
buildOption.resOptions.copyCodeResource.enable |
是否复制代码资源,默认 false |
buildOptionSet |
针对特定构建模式的选项集合 |
buildOptionSet[].name |
构建模式名称,如 release |
buildOptionSet[].arkOptions.obfuscation.ruleOptions.enable |
是否启用混淆 |
buildOptionSet[].arkOptions.obfuscation.ruleOptions.files |
混淆规则文件列表 |
targets |
模块的 Target 列表 |
targets[].name |
Target 名称,default 为默认目标,ohosTest 为测试目标 |
3.4 hvigor 构建系统原理
3.4.1 Hvigor 概述
Hvigor(Harmony vigor)是 HarmonyOS 生态中基于 TypeScript 实现的全新构建工具,专为提升 ArkTS/JS 开发效率而设计。它替代了早期版本中使用的 Gradle 构建系统,成为 API 9 及以上版本的标准构建工具。
Hvigor 的核心设计理念:
- 任务编排:通过任务图(Task Graph)管理构建流程的执行顺序和依赖关系
- 增量构建:通过检测输入输出变化,跳过未修改的任务,显著提升构建速度
- 插件化:通过插件机制扩展构建能力,如
@ohos/hvigor-ohos-plugin - 跨平台:基于 Node.js 实现,可在 Windows、macOS、Linux 上运行
- CLI 优先:所有构建操作都可通过命令行执行,天然适配 CI/CD
3.4.2 核心概念
Task(任务):
Task 是 Hvigor 构建的基本执行单元,每个 Task 负责一个具体的构建操作。IVGuard 项目构建过程中的关键 Task 包括:
| Task 名称 | 职责 | 耗时参考 |
|---|---|---|
PreBuild |
预构建检查,验证项目配置 | ~189 ms |
CreateModuleInfo |
创建模块信息 | ~1 ms |
GenerateMetadata |
生成元数据 | ~5 ms |
MergeProfile |
合并配置文件 | ~5 ms |
ProcessResource |
处理资源文件 | ~11 ms |
CompileResource |
编译资源 | ~1030 ms |
CompileArkTS |
编译 ArkTS 源码 | ~8726 ms |
PackageHap |
打包 HAP | ~704 ms |
SignHap |
签名 HAP | ~3 ms |
assembleHap |
组装 HAP 包 | ~1 ms |
PackageApp |
打包 APP | ~594 ms |
Task Graph(任务图):
Hvigor 在执行构建时,会自动分析 Task 之间的依赖关系,构建一个有向无环图(DAG),然后按拓扑排序执行。例如:
PreBuild ──→ CreateModuleInfo ──→ GenerateMetadata
│
▼
ProcessResource ──→ CompileResource
│
▼
CompileArkTS ──→ PackageHap ──→ SignHap
Plugin(插件):
Hvigor 通过插件机制提供不同类型的构建能力:
appTasks:应用级构建任务(来自@ohos/hvigor-ohos-plugin),在工程级hvigorfile.ts中引用hapTasks:HAP 模块构建任务,在模块级hvigorfile.ts中引用- 自定义插件:开发者可编写自己的 Hvigor 插件扩展构建流程
IVGuard 的工程级 hvigorfile.ts:
import { appTasks } from '@ohos/hvigor-ohos-plugin';
export default {
system: appTasks, // 内置应用级构建插件
plugins: [] // 自定义插件列表(当前为空)
}
IVGuard 的模块级 hvigorfile.ts:
import { hapTasks } from '@ohos/hvigor-ohos-plugin';
export default {
system: hapTasks, // 内置 HAP 模块构建插件
plugins: [] // 自定义插件列表(当前为空)
}
Hvigor Wrapper(hvigorw):
hvigorw(Windows 上为 hvigorw.bat)是 Hvigor 的包装脚本,类似于 Gradle 的 gradlew。它的作用是:
- 自动下载和安装正确版本的 Hvigor
- 确保所有开发者使用相同的构建工具版本
- 无需全局安装 Hvigor,项目自包含
3.4.3 hvigor-config.json5 配置
hvigor/hvigor-config.json5 定义了 Hvigor 构建工具的版本和运行参数:
{
"modelVersion": "6.1.1",
"dependencies": {},
"execution": {
// "analyze": "normal",
// "daemon": true,
// "incremental": true,
// "parallel": true,
// "typeCheck": false,
// "optimizationStrategy": "memory"
},
"logging": {
// "level": "info"
},
"debugging": {
// "stacktrace": false
},
"nodeOptions": {
// "maxOldSpaceSize": 8192
// "exposeGC": true
}
}
关键配置项详解:
| 配置项 | 默认值 | 说明 |
|---|---|---|
execution.analyze |
"normal" |
构建分析模式:normal/advanced/ultrafine/false |
execution.daemon |
true |
启用守护进程,加速后续构建 |
execution.incremental |
true |
启用增量编译,仅编译变更部分 |
execution.parallel |
true |
启用并行编译,利用多核 CPU |
execution.typeCheck |
false |
启用类型检查,更严格的编译检查 |
nodeOptions.maxOldSpaceSize |
8192 |
Node.js 守护进程的最大堆内存 |
3.4.4 构建缓存机制
Hvigor 的缓存机制是其增量构建能力的核心。缓存信息存储在 .hvigor/cache/ 目录下:
.hvigor/cache/
├── meta.json # 缓存元信息
├── last-build-info.json # 上次构建信息
├── file-cache.json # 文件缓存(记录文件哈希)
├── project-config.json # 项目配置缓存
└── task-cache.json # Task 执行缓存
当执行增量构建时,Hvigor 会:
- 读取
last-build-info.json获取上次构建的 Task 列表 - 对比当前源文件与
file-cache.json中的哈希值 - 对于未变化的文件,标记对应的 Task 为
UP-TO-DATE - 仅执行有变更的 Task 及其下游依赖 Task
从 IVGuard 的构建日志中可以观察到 UP-TO-DATE 标记:
> hvigor UP-TO-DATE :entry:default@PreBuild...
> hvigor UP-TO-DATE :entry:default@GenerateMetadata...
> hvigor UP-TO-DATE :entry:default@MergeProfile...
> hvigor UP-TO-DATE :entry:default@ProcessResource...
> hvigor UP-TO-DATE :entry:default@CompileResource...
> hvigor Finished :entry:default@CompileArkTS... after 8 s 726 ms
可以看到,大部分 Task 被标记为 UP-TO-DATE 跳过了,只有 CompileArkTS 因为源码变更而重新执行,整个构建仅耗时 16 秒(全量构建通常需要 30 秒以上)。
4. 项目配置文件深度解析
4.1 module.json5
module.json5 是 HarmonyOS 模块的核心声明文件,定义了模块的类型、Ability 配置、权限声明等关键信息。IVGuard 的 module.json5 位于 entry/src/main/module.json5。
4.1.1 模块基础配置
{
"module": {
"name": "entry",
"type": "entry",
"description": "$string:module_desc",
"mainElement": "EntryAbility",
"deviceTypes": [
"phone"
],
"deliveryWithInstall": true,
"installationFree": false,
"pages": "$profile:main_pages"
}
}
| 字段 | 值 | 说明 |
|---|---|---|
name |
"entry" |
模块名称,需与 build-profile.json5 中 modules.name 一致 |
type |
"entry" |
模块类型:entry(入口模块)、feature(特性模块)、har(静态共享库)、hsp(动态共享库) |
description |
"$string:module_desc" |
模块描述,引用字符串资源,值为"IVGuard 静脉输液智能监控系统" |
mainElement |
"EntryAbility" |
模块的主入口 Ability 名称 |
deviceTypes |
["phone"] |
支持的设备类型:phone、tablet、tv、wearable、car 等 |
deliveryWithInstall |
true |
是否随应用安装一起交付 |
installationFree |
false |
是否支持免安装(原子化服务) |
pages |
"$profile:main_pages" |
页面路由配置,引用 profile 资源文件 |
4.1.2 EntryAbility 配置详解
Ability 是 HarmonyOS 应用的基本功能单元,类似 Android 的 Activity。IVGuard 的 EntryAbility 配置:
{
"name": "EntryAbility",
"srcEntry": "./ets/entryability/EntryAbility.ets",
"description": "$string:EntryAbility_desc",
"icon": "$media:layered_image",
"label": "$string:EntryAbility_label",
"startWindowIcon": "$media:startIcon",
"startWindowBackground": "$color:start_window_background",
"exported": true,
"skills": [
{
"entities": [
"entity.system.home"
],
"actions": [
"ohos.want.action.home"
]
}
]
}
各字段详解:
- name:Ability 的类名,必须与源码中的
export default class EntryAbility一致 - srcEntry:Ability 的源码入口路径,相对于
ets/目录 - icon:Ability 图标,引用 media 资源
- label:Ability 名称,引用 string 资源,值为"IVGuard"
- startWindowIcon:启动窗口图标(应用启动到首帧渲染期间显示的图标)
- startWindowBackground:启动窗口背景色,引用 color 资源,值为
#FFFFFF - exported:
true表示该 Ability 可被其他应用调用。对于入口 Ability,必须设为true,否则应用无法从桌面启动 - skills:定义 Ability 可以响应的 Intent 类型
skills 配置详解:
skills 类似 Android 的 Intent Filter,定义了 Ability 可以接收的隐式 Intent:
- entities:
entity.system.home表示该 Ability 是应用的入口,可以从桌面图标启动 - actions:
ohos.want.action.home是系统定义的启动首页 Action
这个 skills 配置使得 IVGuard 的图标可以出现在设备桌面上,点击图标即可启动应用。
对应的源码实现(EntryAbility.ets):
import { AbilityConstant, ConfigurationConstant, UIAbility, Want } from '@kit.AbilityKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
import { window } from '@kit.ArkUI';
export default class EntryAbility extends UIAbility {
onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
this.context.getApplicationContext().setColorMode(
ConfigurationConstant.ColorMode.COLOR_MODE_NOT_SET
);
hilog.info(0x0000, 'testTag', 'Ability onCreate');
}
onDestroy(): void {
hilog.info(0x0000, 'testTag', 'Ability onDestroy');
}
onWindowStageCreate(windowStage: window.WindowStage): void {
hilog.info(0x0000, 'testTag', 'Ability onWindowStageCreate');
windowStage.loadContent('pages/Index', (err) => {
if (err.code) {
hilog.error(0x0000, 'testTag', 'Failed to load content');
return;
}
hilog.info(0x0000, 'testTag', 'Succeeded in loading content.');
});
}
onWindowStageDestroy(): void {
hilog.info(0x0000, 'testTag', 'Ability onWindowStageDestroy');
}
onForeground(): void {
hilog.info(0x0000, 'testTag', 'Ability onForeground');
}
onBackground(): void {
hilog.info(0x0000, 'testTag', 'Ability onBackground');
}
}
UIAbility 的生命周期回调包括:onCreate → onWindowStageCreate → onForeground → onBackground → onWindowStageDestroy → onDestroy。在 onWindowStageCreate 中,通过 windowStage.loadContent('pages/Index') 加载了 Index 首页。
4.1.3 ExtensionAbility(backup)配置
IVGuard 配置了一个 backup 类型的 ExtensionAbility:
{
"name": "EntryBackupAbility",
"srcEntry": "./ets/entrybackupability/EntryBackupAbility.ets",
"type": "backup",
"exported": false,
"metadata": [
{
"name": "ohos.extension.backup",
"resource": "$profile:backup_config"
}
]
}
各字段详解:
- type:
backup表示这是一个备份扩展能力 - exported:
false表示该 ExtensionAbility 不对外暴露 - metadata:声明元数据配置
- name:
ohos.extension.backup是备份扩展的固定标识 - resource:指向备份配置文件
backup_config.json
- name:
对应的源码实现:
import { BackupExtensionAbility, BundleVersion } from '@kit.CoreFileKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
export default class EntryBackupAbility extends BackupExtensionAbility {
async onBackup() {
hilog.info(0x0000, 'testTag', 'onBackup ok');
await Promise.resolve();
}
async onRestore(bundleVersion: BundleVersion) {
hilog.info(0x0000, 'testTag', 'onRestore ok %{public}s', JSON.stringify(bundleVersion));
await Promise.resolve();
}
}
备份配置文件 backup_config.json:
{
"allowToBackupRestore": true
}
这表示允许 IVGuard 应用参与系统的备份恢复流程,用户在更换设备或重装应用后可以恢复数据。当前配置是基础版本,仅允许备份恢复,未指定具体的 includes/excludes 路径。如需更精细的控制(例如排除临时缓存数据),可以扩展配置:
{
"allowToBackupRestore": true,
"includes": [
"/data/storage/el2/base/files/",
"/data/storage/el2/base/preferences/"
],
"excludes": [
"/data/storage/el2/base/files/cache/"
]
}
4.1.4 8 项 requestPermissions 权限声明
IVGuard 声明了 8 项权限,每项权限都与应用的特定功能紧密关联:
1. ohos.permission.CAMERA(相机权限)
{
"name": "ohos.permission.CAMERA",
"reason": "$string:camera_reason",
"usedScene": {
"abilities": ["EntryAbility"],
"when": "inuse"
}
}
用途:IVGuard 的核心功能是通过手机相机实时监控输液瓶的液位变化。VisionService 使用相机 API 捕获输液瓶图像,通过图像分析算法检测液位高度。
授权类型:user_grant(用户授权),安装后首次使用时系统会弹出授权弹窗。
2. ohos.permission.NFC_TAG(NFC 标签权限)
{
"name": "ohos.permission.NFC_TAG",
"reason": "$string:nfc_reason",
"usedScene": {
"abilities": ["EntryAbility"],
"when": "inuse"
}
}
用途:护士可以通过手机触碰输液瓶上的 NFC 贴纸,快速读取药物信息(药品名称、剂量、配伍禁忌等),避免手动输入的错误。
授权类型:user_grant。
3. ohos.permission.NOTIFICATION_CONTROLLER(通知控制权限)
{
"name": "ohos.permission.NOTIFICATION_CONTROLLER",
"reason": "$string:notify_reason",
"usedScene": {
"abilities": ["EntryAbility"],
"when": "inuse"
}
}
用途:当输液即将结束时,IVGuard 需要向护士和患者家属发送提醒通知。NotificationService 负责管理通知的发送。
授权类型:user_grant。
4. ohos.permission.KEEP_BACKGROUND_RUNNING(后台保活权限)
{
"name": "ohos.permission.KEEP_BACKGROUND_RUNNING",
"reason": "$string:bg_reason",
"usedScene": {
"abilities": ["EntryAbility"],
"when": "always"
}
}
用途:输液过程通常持续数小时,IVGuard 需要在后台持续监控输液进度,不能因为应用退到后台就停止监控。这是唯一一个 when: "always" 的权限。
授权类型:user_grant。
5. ohos.permission.VIBRATE(振动权限)
{
"name": "ohos.permission.VIBRATE"
}
用途:当输液异常或即将结束时,除了通知提醒外,还需要通过手机振动提供触觉反馈。
授权类型:system_grant(系统授权),安装时自动授予,无需用户确认。因此不需要 reason 和 usedScene 字段。
6. ohos.permission.LOCATION(精确定位权限)
{
"name": "ohos.permission.LOCATION",
"reason": "$string:location_reason",
"usedScene": {
"abilities": ["EntryAbility"],
"when": "inuse"
}
}
用途:IVGuard 的 HospitalNavPage 提供医院室内导航功能,帮助家属找到输液室位置,需要精确位置信息。
授权类型:user_grant。
7. ohos.permission.APPROXIMATELY_LOCATION(粗略定位权限)
{
"name": "ohos.permission.APPROXIMATELY_LOCATION",
"reason": "$string:location_reason",
"usedScene": {
"abilities": ["EntryAbility"],
"when": "inuse"
}
}
用途:作为 LOCATION 权限的补充,粗略定位可以在用户拒绝精确定位时提供基本的定位能力。
注意:在 HarmonyOS 中,申请 LOCATION 权限时通常需要同时申请 APPROXIMATELY_LOCATION。
8. ohos.permission.GET_WIFI_INFO(WiFi 信息权限)
{
"name": "ohos.permission.GET_WIFI_INFO"
}
用途:获取 WiFi 连接信息,可用于辅助室内定位(WiFi 指纹定位)或判断设备是否在医院网络环境中。
授权类型:system_grant,安装时自动授予。
4.1.5 权限分类总结
| 权限 | 授权类型 | 使用时机 | 关联功能 |
|---|---|---|---|
| CAMERA | user_grant | inuse | 液位视觉监控 |
| NFC_TAG | user_grant | inuse | NFC 药物信息读取 |
| NOTIFICATION_CONTROLLER | user_grant | inuse | 输液结束提醒 |
| KEEP_BACKGROUND_RUNNING | user_grant | always | 后台持续监控 |
| VIBRATE | system_grant | - | 振动提醒 |
| LOCATION | user_grant | inuse | 医院导航 |
| APPROXIMATELY_LOCATION | user_grant | inuse | 辅助定位 |
| GET_WIFI_INFO | system_grant | - | WiFi 辅助定位 |
user_grant 与 system_grant 的区别:
- system_grant:系统授权权限,应用安装时自动授予,用户无需确认。如 VIBRATE、GET_WIFI_INFO。配置时
reason和usedScene为选填字段。 - user_grant:用户授权权限,需要用户在弹窗中手动授权。如 CAMERA、LOCATION、NFC_TAG。配置时
reason和usedScene为必填字段,否则应用上架可能被驳回。
reason 字符串的重要性:
对于 user_grant 权限,reason 的内容会在系统授权弹窗中展示给用户。IVGuard 的 reason 字符串都在 string.json 中定义:
{
"name": "camera_reason",
"value": "需要使用相机监控输液瓶液位变化"
}
reason 的内容应直白、具体,建议句式为"用于做某事",建议长度小于 72 个字符(约 36 个汉字)。
4.2 main_pages.json
main_pages.json 定义了模块中的页面路由注册表。只有在此文件中注册的页面,才能通过路由进行导航。
IVGuard 的页面路由配置:
{
"src": [
"pages/Index",
"pages/HomePage",
"pages/MonitorPage",
"pages/MedicinePage",
"pages/MedicineDetailPage",
"pages/HistoryPage",
"pages/AnalysisPage",
"pages/CostPage",
"pages/CostDetailPage",
"pages/InsuranceSetupPage",
"pages/SettingsPage",
"pages/HospitalNavPage",
"pages/NurseHomePage",
"pages/PatientListPage",
"pages/NurseAnalysisPage",
"pages/FamilyHomePage",
"pages/FamilyAlertPage"
]
}
共注册了 17 个页面,按功能模块分类如下:
| 功能模块 | 页面 | 说明 |
|---|---|---|
| 通用 | Index | 启动页/角色选择 |
| 患者端 | HomePage | 患者首页(监控概览) |
| 患者端 | MonitorPage | 实时监控页面 |
| 患者端 | MedicinePage | 药物列表页 |
| 患者端 | MedicineDetailPage | 药物详情页 |
| 患者端 | HistoryPage | 历史记录页 |
| 患者端 | AnalysisPage | 分析报告页 |
| 患者端 | CostPage | 费用概览页 |
| 患者端 | CostDetailPage | 费用详情页 |
| 患者端 | InsuranceSetupPage | 医保配置页 |
| 通用 | SettingsPage | 设置页 |
| 通用 | HospitalNavPage | 医院导航页 |
| 护士端 | NurseHomePage | 护士工作台 |
| 护士端 | PatientListPage | 患者列表页 |
| 护士端 | NurseAnalysisPage | 护士聚合分析页 |
| 家属端 | FamilyHomePage | 家属远程监控页 |
| 家属端 | FamilyAlertPage | 家属预警记录页 |
重要规则:
- 页面路径格式为
pages/PageName,不需要写文件扩展名(.ets) - 所有页面文件必须位于
entry/src/main/ets/pages/目录下 - 每个页面文件必须有一个被
@Entry装饰器标记的struct - 未在
main_pages.json中注册的页面无法通过路由访问 pages数组中的第一个元素(Index)是应用的默认首页
页面路由导航:
在 ArkTS 代码中,页面导航通过 router 模块实现:
import { router } from '@kit.ArkUI';
// 跳转到指定页面
router.pushUrl({ url: 'pages/MonitorPage' });
// 替换当前页面(不可返回)
router.replaceUrl({ url: 'pages/HomePage' });
// 带参数跳转
router.pushUrl({
url: 'pages/MedicineDetailPage',
params: { medicineId: 'med_001' }
});
// 获取路由参数
const params = router.getParams() as Record<string, Object>;
4.3 string.json
string.json 是 HarmonyOS 的字符串资源文件,用于实现多语言支持和资源集中管理。IVGuard 项目有两级 string.json:
应用级(AppScope/resources/base/element/string.json):
{
"string": [
{
"name": "app_name",
"value": "IVGuard"
}
]
}
模块级(entry/src/main/resources/base/element/string.json)包含 22 个字符串资源,主要分为以下类别:
模块描述与 Ability 标识:
| name | value | 引用位置 |
|---|---|---|
module_desc |
IVGuard 静脉输液智能监控系统 | module.json5 → description |
EntryAbility_desc |
静脉输液智能监控与提醒 | module.json5 → abilities[].description |
EntryAbility_label |
IVGuard | module.json5 → abilities[].label |
权限说明字符串(reason):
| name | value | 对应权限 |
|---|---|---|
camera_reason |
需要使用相机监控输液瓶液位变化 | CAMERA |
nfc_reason |
需要读取NFC贴纸中的药物信息 | NFC_TAG |
notify_reason |
需要在输液快结束时发送提醒通知 | NOTIFICATION_CONTROLLER |
bg_reason |
需要在后台持续监控输液进度 | KEEP_BACKGROUND_RUNNING |
location_reason |
需要获取位置信息用于医院室内导航 | LOCATION / APPROXIMATELY_LOCATION |
页面标题字符串:
| name | value |
|---|---|
page_home |
监控 |
page_monitor |
实时监控 |
page_medicine |
药物 |
page_history |
历史 |
page_analysis |
分析 |
page_cost |
费用 |
page_settings |
设置 |
page_hospital_nav |
医院导航 |
page_nurse_home |
护士工作台 |
page_patient_list |
患者列表 |
page_nurse_analysis |
聚合分析 |
page_family_home |
远程监控 |
page_family_alert |
预警记录 |
免责声明:
| name | value |
|---|---|
disclaimer |
本应用仅为辅助提醒工具,不替代专业护理。费用估算仅供参考,以医院实际收费为准。 |
资源引用方式:
在配置文件中:$string:resource_name(如 $string:camera_reason)
在 ArkTS 代码中:$r('app.string.resource_name') 或 $r('entry.string.resource_name')
4.4 oh-package.json5
oh-package.json5 是 OpenHarmony 包管理器(ohpm)的配置文件,类似 npm 的 package.json。IVGuard 有两级配置:
工程级(oh-package.json5):
{
"modelVersion": "6.1.1",
"description": "Please describe the basic information.",
"dependencies": {},
"devDependencies": {
"@ohos/hypium": "1.0.25",
"@ohos/hamock": "1.0.0"
}
}
- modelVersion:SDK 模型版本号
- dependencies:运行时依赖(当前为空,IVGuard 没有使用第三方运行时库)
- devDependencies:开发依赖
@ohos/hypium:HarmonyOS 单元测试框架@ohos/hamock:HarmonyOS Mock 框架
模块级(entry/oh-package.json5):
{
"name": "entry",
"version": "1.0.0",
"description": "Please describe the basic information.",
"main": "",
"author": "",
"license": "",
"dependencies": {}
}
依赖锁文件(oh-package-lock.json5)记录了依赖的精确版本、完整性校验和下载地址:
{
"meta": {
"stableOrder": true,
"enableUnifiedLockfile": false
},
"lockfileVersion": 3,
"specifiers": {
"@ohos/hamock@1.0.0": "@ohos/hamock@1.0.0",
"@ohos/hypium@1.0.25": "@ohos/hypium@1.0.25"
},
"packages": {
"@ohos/hamock@1.0.0": {
"name": "@ohos/hamock",
"version": "1.0.0",
"integrity": "sha512-K6lDPYc6VkKe6...",
"resolved": "https://ohpm.openharmony.cn/ohpm/@ohos/hamock/-/hamock-1.0.0.har",
"registryType": "ohpm"
},
"@ohos/hypium@1.0.25": {
"name": "@ohos/hypium",
"version": "1.0.25",
"integrity": "sha512-l6uO2pjl8HyE...",
"resolved": "https://ohpm.openharmony.cn/ohpm/@ohos/hypium/-/hypium-1.0.25.har",
"registryType": "ohpm"
}
}
}
锁文件确保所有开发者使用完全一致的依赖版本。切勿手动编辑此文件,应通过 ohpm install 命令自动生成。
添加第三方依赖的流程:
# 安装依赖
ohpm install @ohos/lottie # 示例:安装 Lottie 动画库
# 这会自动更新 oh-package.json5 和 oh-package-lock.json5
4.5 app.json5
app.json5 是应用级标识配置文件,位于 AppScope/app.json5:
{
"app": {
"bundleName": "com.example.ivguard",
"vendor": "example",
"versionCode": 1000000,
"versionName": "1.0.0",
"icon": "$media:layered_image",
"label": "$string:app_name"
}
}
字段详解:
| 字段 | 值 | 说明 |
|---|---|---|
bundleName |
com.example.ivguard |
应用唯一标识包名,全局唯一,一旦发布不可更改 |
vendor |
example |
应用开发商名称 |
versionCode |
1000000 |
版本号(整数),每次发布必须递增。格式通常为 AABBCC,AA 为主版本,BB 为次版本,CC 为修订号 |
versionName |
"1.0.0" |
版本名称(字符串),面向用户的可见版本号 |
icon |
$media:layered_image |
应用图标,引用 media 资源 |
label |
$string:app_name |
应用名称,引用 string 资源,值为"IVGuard" |
bundleName 的命名规范:
- 采用反域名格式:
com.公司名.产品名 - IVGuard 使用
com.example.ivguard,其中example是开发阶段的占位符 - 正式发布前应替换为真实公司域名,如
com.yourcompany.ivguard - bundleName 一旦在 AppGallery 上发布,就不可更改,务必在发布前确认
4.6 其他配置文件
4.6.1 color.json
颜色资源文件,定义应用中使用的颜色:
{
"color": [
{
"name": "start_window_background",
"value": "#FFFFFF"
}
]
}
目前只定义了启动窗口背景色(白色)。后续可以扩展更多品牌色、主题色等。
4.6.2 float.json
尺寸资源文件,定义应用中使用的浮点数尺寸:
{
"float": [
{
"name": "page_text_font_size",
"value": "50fp"
}
]
}
使用 fp(font-independent pixel)单位,确保在不同屏幕密度的设备上显示效果一致。
4.6.3 code-linter.json5
代码检查配置文件,定义了 ArkTS 代码的静态分析规则:
{
"files": [
"**/*.ets"
],
"ignore": [
"**/src/ohosTest/**/*",
"**/src/test/**/*",
"**/src/mock/**/*",
"**/node_modules/**/*",
"**/oh_modules/**/*",
"**/build/**/*",
"**/.preview/**/*"
],
"ruleSet": [
"plugin:@performance/recommended",
"plugin:@typescript-eslint/recommended"
],
"rules": {
"@security/no-unsafe-aes": "error",
"@security/no-unsafe-hash": "error",
"@security/no-unsafe-mac": "warn",
"@security/no-unsafe-dh": "error",
"@security/no-unsafe-dsa": "error",
"@security/no-unsafe-ecdsa": "error",
"@security/no-unsafe-rsa-encrypt": "error",
"@security/no-unsafe-rsa-sign": "error",
"@security/no-unsafe-rsa-key": "error",
"@security/no-unsafe-dsa-key": "error",
"@security/no-unsafe-dh-key": "error",
"@security/no-unsafe-3des": "error"
}
}
关键配置:
- ruleSet:启用了性能推荐规则和 TypeScript ESLint 推荐规则
- security 规则:全面禁止不安全的加密算法,包括不安全的 AES、Hash、MAC、DH、DSA、ECDSA、RSA 以及 3DES。这对 IVGuard 这样涉及医疗数据的应用尤为重要——必须使用安全的加密算法保护患者隐私数据。
4.6.4 obfuscation-rules.txt
代码混淆规则文件,定义了 release 构建时的混淆策略:
-enable-property-obfuscation
-enable-toplevel-obfuscation
-enable-filename-obfuscation
-enable-export-obfuscation
当前启用了四种混淆:属性名混淆、顶层名称混淆、文件名混淆、导出名称混淆。但在模块级 build-profile.json5 中,混淆的 enable 设为 false,意味着当前 release 构建实际上未启用混淆。如果需要启用,将 ruleOptions.enable 改为 true 即可。
5. 构建流程详解
5.1 构建流水线概览
HarmonyOS 应用的构建过程是一个多阶段的流水线,从源码到最终可安装的安装包,需要经过以下核心阶段:
PreBuild → Compile → Package → Sign
5.1.1 PreBuild 阶段
PreBuild 阶段负责构建前的准备工作,包括:
工程级预构建:
PreBuildApp:工程级预构建检查(耗时约 1 ms)DuplicateDependencyCheck:重复依赖检查,确保没有依赖冲突
模块级预构建:
PreBuild:模块级预构建检查(耗时约 189 ms),验证项目配置的合法性CreateModuleInfo:创建模块信息对象(耗时约 1 ms)GenerateMetadata:生成模块元数据(耗时约 5 ms)ConfigureCmake:配置 CMake(如果包含 Native 代码)MergeProfile:合并各配置文件(耗时约 5 ms)CreateBuildProfile:创建构建配置(耗时约 5 ms)PreCheckSyscap:预检查系统能力(SysCap)GeneratePkgContextInfo:生成包上下文信息(耗时约 11 ms)GeneratePkgSdkInfo:生成包 SDK 信息(耗时约 6 ms)ProcessIntegratedHsp:处理集成的 HSP 模块
5.1.2 Compile 阶段
Compile 阶段是构建的核心,负责将源码编译为可执行的中间产物:
资源处理:
ProcessProfile:处理 profile 配置文件(耗时约 661 ms)ProcessRouterMap:处理路由映射(耗时约 5 ms)ProcessShareConfig:处理共享配置(耗时约 4 ms)ProcessStartupConfig:处理启动配置(耗时约 3 ms)ProcessResource:处理资源文件,编译图片、字符串等(耗时约 11 ms)CompileResource:编译资源为二进制格式(耗时约 1030 ms)
代码编译:
BuildJS:构建 JavaScript/ArkTS 基础环境(耗时约 4 ms)CompileArkTS:核心编译步骤,将 ArkTS 源码编译为字节码(耗时约 8726 ms,占总构建时间的大部分)
Native 编译(如果包含 C/C++ 代码):
BuildNativeWithCmake:使用 CMake 构建 Native 代码BuildNativeWithNinja:使用 Ninja 编译 Native 代码DoNativeStrip:去除 Native 库的调试符号CacheNativeLibs:缓存 Native 库
其他编译步骤:
ProcessLibs:处理依赖库文件(耗时约 8 ms)GenerateLoaderJson:生成加载器 JSON(耗时约 11 ms)
5.1.3 Package 阶段
Package 阶段将编译产物打包为 HAP 包:
MakePackInfo:生成打包信息(耗时约 5 ms)SyscapTransform:系统能力转换(耗时约 2 ms)GeneratePkgModuleJson:生成模块 JSON(耗时约 6 ms)ProcessCompiledResources:处理已编译的资源(耗时约 2 ms)PackageHap:打包 HAP,将所有编译产物打包为.hap文件(耗时约 704 ms)PackingCheck:打包检查(耗时约 9 ms)
5.1.4 Sign 阶段
Sign 阶段对 HAP 包进行数字签名:
SignHap:使用签名证书对 HAP 包签名(耗时约 3 ms)
工程级打包:
MakeProjectPackInfo:生成工程打包信息(耗时约 5 ms)ProcessProjectPrivacyProfile:处理隐私声明GeneratePackRes:生成打包资源(耗时约 2 ms)PackageApp:打包 APP,将所有 HAP 合并为.app文件(耗时约 594 ms)SignApp:对 APP 包签名(耗时约 1 ms)assembleApp:最终组装 APP 包
5.1.5 IVGuard 构建日志分析
以下是从 IVGuard 实际构建日志中提取的关键时间线(增量构建):
> hvigor Finished ::PreBuildApp... after 1 ms
> hvigor UP-TO-DATE :entry:default@PreBuild...
> hvigor Finished ::DuplicateDependencyCheck... after 1 ms
> hvigor Finished :entry:default@CreateModuleInfo... after 2 ms
> hvigor UP-TO-DATE :entry:default@GenerateMetadata...
> hvigor Finished :entry:default@ConfigureCmake... after 1 ms
> hvigor UP-TO-DATE :entry:default@MergeProfile...
> hvigor UP-TO-DATE :entry:default@CreateBuildProfile...
> hvigor Finished :entry:default@PreCheckSyscap... after 1 ms
> hvigor UP-TO-DATE :entry:default@GeneratePkgContextInfo... after 11 ms
> hvigor Finished :entry:default@GeneratePkgSdkInfo... after 5 ms
> hvigor Finished :entry:default@ProcessIntegratedHsp... after 2 ms
> hvigor Finished :entry:default@BuildNativeWithCmake... after 1 ms
> hvigor UP-TO-DATE :entry:default@MakePackInfo...
> hvigor Finished :entry:default@SyscapTransform... after 17 ms
> hvigor UP-TO-DATE :entry:default@ProcessProfile...
> hvigor UP-TO-DATE :entry:default@ProcessRouterMap...
> hvigor UP-TO-DATE :entry:default@ProcessShareConfig...
> hvigor Finished :entry:default@ProcessStartupConfig... after 3 ms
> hvigor Finished :entry:default@BuildNativeWithNinja... after 1 ms
> hvigor UP-TO-DATE :entry:default@ProcessResource...
> hvigor UP-TO-DATE :entry:default@GenerateLoaderJson...
> hvigor UP-TO-DATE :entry:default@ProcessLibs...
> hvigor UP-TO-DATE :entry:default@CompileResource...
> hvigor UP-TO-DATE :entry:default@DoNativeStrip...
> hvigor Finished :entry:default@BuildJS... after 4 ms
> hvigor UP-TO-DATE :entry:default@CacheNativeLibs...
> hvigor Finished :entry:default@CompileArkTS... after 8 s 726 ms
> hvigor Finished :entry:default@GeneratePkgModuleJson... after 6 ms
> hvigor Finished :entry:default@ProcessCompiledResources... after 2 ms
> hvigor Finished :entry:default@PackageHap... after 704 ms
> hvigor Finished :entry:default@PackingCheck... after 9 ms
> hvigor Finished :entry:default@SignHap... after 3 ms
> hvigor Finished :entry:default@CollectDebugSymbol... after 1 ms
> hvigor Finished :entry:default@assembleHap... after 1 ms
> hvigor Finished ::MakeProjectPackInfo... after 5 ms
> hvigor Finished ::ProcessProjectPrivacyProfile... after 6 ms
> hvigor Finished ::GeneratePackRes... after 2 ms
> hvigor Finished ::PackageApp... after 594 ms
> hvigor Finished ::SignApp... after 1 ms
> hvigor Finished ::assembleApp... after 1 ms
> hvigor BUILD SUCCESSFUL in 16 s 142 ms
关键观察:
- 增量构建效率:大部分 Task 被标记为
UP-TO-DATE,只有CompileArkTS重新执行 - CompileArkTS 是瓶颈:耗时 8.7 秒,占总构建时间的 54%
- PackageHap 次之:耗时 704 ms,占总构建时间的 4.4%
- 全量构建约 19-30 秒,增量构建约 16 秒
5.2 ArkTS 编译器的前端检查
ArkTS 编译器在 CompileArkTS 阶段执行严格的前端检查,这是 ArkTS 与普通 TypeScript 的关键区别。
5.2.1 arkts_check 静态分析
arkts_check 是 ArkTS 编译器内置的静态分析工具,在编译前对代码进行规则检查。它会检测以下违规行为:
arkts-no-standalone-this:禁止在 @Component 装饰的 struct 之外使用 this。
arkts-no-any-unknown:禁止使用 any 和 unknown 类型,强制显式类型声明。
arkts-no-obj-literals-as-types:禁止使用对象字面量作为类型,必须使用 class。
arkts-no-destructuring:限制解构赋值的使用场景。
arkts-limited-stdlib:限制标准库的使用,部分 JavaScript 标准库 API 在 ArkTS 中不可用。
这些检查在 CompileArkTS 阶段自动执行,如果检测到违规,会直接导致编译失败并输出错误信息。
5.2.2 IVGuard 中的编译错误示例
在 IVGuard 的首次构建中,遇到了以下编译错误:
ERROR: 10905209 ArkTS Compiler Error
Error Message: Only UI component syntax can be written here.
At File: F:/projects/IVGuard/entry/src/main/ets/pages/CostPage.ets:164:23
ERROR: 10905209 ArkTS Compiler Error
Error Message: Only UI component syntax can be written here.
At File: F:/projects/IVGuard/entry/src/main/ets/pages/CostPage.ets:249:15
ERROR: 10905209 ArkTS Compiler Error
Error Message: Only UI component syntax can be written here.
At File: F:/projects/IVGuard/entry/src/main/ets/component/MonitorOverlay.ets:31:9
ERROR: 10905209 ArkTS Compiler Error
Error Message: Only UI component syntax can be written here.
At File: F:/projects/IVGuard/entry/src/main/ets/component/MonitorOverlay.ets:32:9
Only UI component syntax can be written here 错误是 ArkTS 严格模式中最常见的编译错误之一,表示在 build() 方法中使用了不允许的语法。在 build() 方法中,只能使用 UI 组件声明语法,不能使用普通的 JavaScript 语句(如 const 声明、if/else 块等普通控制流需要改为条件表达式)。
5.3 HAP 打包与签名
5.3.1 HAP 文件结构
HAP(HarmonyOS Ability Package)是 HarmonyOS 应用的基本安装单元,类似 Android 的 APK。一个 HAP 文件实际上是一个 ZIP 压缩包,内部结构如下:
entry-default.hap (ZIP 格式)
├── entry/ # 模块根目录
│ ├── ets/ # 编译后的 ArkTS 字节码
│ │ ├── entryability/ # Ability 字节码
│ │ ├── pages/ # 页面字节码
│ │ ├── service/ # 服务字节码
│ │ ├── model/ # 数据模型字节码
│ │ └── component/ # 组件字节码
│ ├── resources/ # 编译后的资源文件
│ │ ├── base/
│ │ └── dark/
│ └── module.json # 模块配置(编译后)
├── libs/ # Native 库(.so 文件)
├── resources.index # 资源索引文件
├── module.json # 模块清单
└── pack.info # 包信息
IVGuard 构建产物的实际路径:
# HAP 包(模块级)
entry/build/default/outputs/default/entry-default-unsigned.hap # 未签名
entry/build/default/outputs/default/app/entry-default.hap # 已签名
# APP 包(工程级)
build/outputs/default/IVGuard-default-unsigned.app # 未签名
5.3.2 APP 与 HAP 的关系
APP(Application Package)是包含一个或多个 HAP 的发布包:
- APP 包:用于应用市场分发和真机安装,包含所有模块的 HAP
- HAP 包:单个模块的安装包,可用于模拟器安装和调试
当项目只有一个 entry 模块时,APP 包和 HAP 包的内容基本一致,但文件格式不同(APP 包会额外包含 pack.info 等元数据)。
5.3.3 签名流程
签名是将数字证书附加到 HAP/APP 包的过程,确保应用的完整性和来源可信。
调试签名:
- 通过 DevEco Studio 自动生成(Automatically generate signature)
- 仅用于开发调试阶段
- 签名信息存储在
build-profile.json5的signingConfigs中
发布签名:
- 需要向华为申请发布证书和 Profile
- 通过 AppGallery Connect 管理签名材料
- 用于正式上架到华为应用市场
IVGuard 当前的签名状态:
由于未配置 signingConfigs,构建时产生以下警告:
WARN: Will skip sign 'hos_hap'. No signingConfigs profile is configured in current project.
WARN: Will skip sign 'app'. No signingConfigs profile is configured in current project.
这意味着生成的 HAP/APP 包是未签名的(-unsigned 后缀),只能在模拟器上安装,无法在真机上安装。真机调试或上架前必须配置签名。
5.4 增量构建 vs 全量构建
5.4.1 增量构建
增量构建是 Hvigor 的核心优化能力。当源码只有部分变更时,增量构建只重新编译受影响的部分,跳过未变化的 Task。
增量构建的判定逻辑:
- Hvigor 检查每个 Task 的输入文件和输出文件
- 计算输入文件的哈希值,与缓存中的哈希值比较
- 如果哈希值相同,标记该 Task 为
UP-TO-DATE,跳过执行 - 如果哈希值不同,执行该 Task 并更新缓存
IVGuard 增量构建示例(仅修改了 ArkTS 源码):
> hvigor UP-TO-DATE :entry:default@PreBuild...
> hvigor UP-TO-DATE :entry:default@GenerateMetadata...
> hvigor UP-TO-DATE :entry:default@MergeProfile...
> hvigor UP-TO-DATE :entry:default@ProcessResource...
> hvigor UP-TO-DATE :entry:default@CompileResource...
> hvigor Finished :entry:default@CompileArkTS... after 8 s 726 ms
> hvigor Finished :entry:default@PackageHap... after 704 ms
> hvigor BUILD SUCCESSFUL in 16 s 142 ms
大部分 Task 被跳过,只有 CompileArkTS 和后续的打包步骤重新执行。
5.4.2 全量构建
全量构建清除所有缓存,从零开始重新编译所有内容。
触发全量构建的场景:
- 手动执行
hvigorw clean后再构建 - 修改了
build-profile.json5等配置文件 - 修改了
module.json5等模块配置 - 增减了模块或依赖
- 缓存损坏导致增量构建失败
IVGuard 全量构建示例:
> hvigor Finished ::PreBuildApp... after 1 ms
> hvigor Finished :entry:default@PreBuild... after 189 ms
> hvigor Finished :entry:default@CreateModuleInfo... after 1 ms
> ... (所有 Task 都重新执行)
> hvigor Finished :entry:default@CompileArkTS... after 8 s 726 ms
> hvigor Finished :entry:default@PackageHap... after 704 ms
> hvigor BUILD FAILED in 19 s 103 ms
全量构建通常耗时 19-30 秒,比增量构建慢约 20-80%。
5.4.3 何时使用 clean 构建
- 怀疑缓存污染:多次增量构建仍然失败时,尝试 clean 构建
- 配置变更后:修改了
build-profile.json5、module.json5等配置文件 - 依赖变更后:添加或删除了 ohpm 依赖
- 切换分支后:从 Git 切换到另一个分支,缓存可能失效
# 执行 clean 构建
hvigorw clean assembleHap --no-daemon
6. IVGuard 项目构建实践
6.1 项目概览
IVGuard 项目的关键信息:
| 属性 | 值 |
|---|---|
| 项目路径 | F:\projects\IVGuard |
| bundleName | com.example.ivguard |
| targetSdkVersion | 6.1.1(24) |
| compatibleSdkVersion | 6.1.1(24) |
| runtimeOS | HarmonyOS |
| 主模块 | entry(HAP) |
| 页面数量 | 17 个 |
| 权限声明 | 8 项 |
| 组件数量 | 8 个自定义组件 |
| 服务数量 | 11 个服务类 |
| 数据模型 | 6 个模型文件 |
6.2 首次构建遇到的 3 个问题及解决
6.2.1 问题一:无效权限名 ohos.permission.SCAN_WIFI
现象:
首次构建时,module.json5 中声明了 ohos.permission.SCAN_WIFI 权限,但该权限在 HarmonyOS API 24 中不存在。
错误信息:
构建时,Hvigor 在 ProcessProfile 阶段检测到无效的权限名,导致编译失败。
根因分析:
ohos.permission.SCAN_WIFI 是一个不存在的权限名。HarmonyOS 中与 WiFi 相关的权限包括:
ohos.permission.GET_WIFI_INFO:获取 WiFi 连接信息ohos.permission.SET_WIFI_INFO:设置 WiFi 信息ohos.permission.GET_WIFI_LOCAL_MAC:获取设备 MAC 地址ohos.permission.WIFI:WiFi 管理权限
IVGuard 只需要获取 WiFi 信息用于辅助定位,不需要扫描 WiFi,因此应该使用 GET_WIFI_INFO。
解决方案:
将 module.json5 中的权限名从 ohos.permission.SCAN_WIFI 修改为 ohos.permission.GET_WIFI_INFO:
// 修改前
{
"name": "ohos.permission.SCAN_WIFI",
"reason": "$string:wifi_reason",
"usedScene": {
"abilities": ["EntryAbility"],
"when": "inuse"
}
}
// 修改后
{
"name": "ohos.permission.GET_WIFI_INFO"
}
同时,由于 GET_WIFI_INFO 是 system_grant 权限,安装时自动授予,所以移除了 reason 和 usedScene 字段。
经验总结:
- HarmonyOS 的权限名是严格定义的,不存在"类似"的权限名
- 声明权限前,务必查阅官方权限列表:
https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/permissions-overview system_grant权限不需要reason和usedScene字段user_grant权限必须有reason和usedScene字段
6.2.2 问题二:const 声明在 build() 方法中报错
现象:
在 @Component 的 build() 方法中使用 const 声明变量,触发 ArkTS 编译器错误:
ERROR: 10905209 ArkTS Compiler Error
Error Message: Only UI component syntax can be written here.
根因分析:
ArkTS 的 build() 方法有严格的语法限制,只能包含 UI 组件声明语法。这是 ArkTS 与普通 TypeScript 的关键区别之一。
在 build() 方法中,以下语法是不允许的:
// 错误 - 在 build() 中使用 const/let/var
build() {
const title = 'IVGuard'
Text(title)
}
// 错误 - 在 build() 中使用普通函数调用
build() {
const data = this.processData()
Text(data)
}
// 错误 - 在 build() 中使用解构
build() {
const { width, height } = this.dimensions
Text(`${width} x ${height}`)
}
解决方案:
根据不同的使用场景,有以下替代方案:
方案 A:使用 @State 或 @Prop
如果变量需要响应式更新,使用 @State:
@Component
struct MyComponent {
@State title: string = 'IVGuard'
build() {
Text(this.title)
}
}
方案 B:使用内联表达式
如果变量只是简单的计算结果,直接内联:
build() {
Text('IVGuard') // 直接使用字面量
}
方案 C:使用 @Builder 函数
如果需要复用 UI 片段,使用 @Builder:
@Builder
titleBuilder(title: string) {
Text(title)
}
build() {
this.titleBuilder('IVGuard')
}
方案 D:将逻辑移到 aboutToAppear
如果变量需要在初始化时计算,将逻辑移到生命周期回调中:
@Component
struct MyComponent {
@State displayTitle: string = ''
aboutToAppear(): void {
this.displayTitle = this.processTitle()
}
build() {
Text(this.displayTitle)
}
}
经验总结:
build()方法中只能使用 UI 组件声明语法- 任何需要在
build()中使用的动态数据,都应通过@State/@Prop/@Link管理 - 复杂的计算逻辑应在
aboutToAppear或其他方法中完成 @Builder函数是复用 UI 逻辑的推荐方式
6.2.3 问题三:flexWrap 在 Row 组件上不存在
现象:
尝试在 Row 组件上使用 .flexWrap() 属性,编译报错提示该属性不存在。
根因分析:
在 ArkUI 中,flexWrap 是 Flex 容器组件的属性,而不是 Row 或 Column 的属性。Row 和 Column 是简化版的线性布局组件,不支持 flexWrap 属性。
// 错误 - Row 不支持 flexWrap
Row() {
Text('Item 1')
Text('Item 2')
Text('Item 3')
}.flexWrap(FlexWrap.Wrap) // 编译错误:Row 没有 flexWrap 属性
解决方案:
使用 Flex 组件替代 Row,Flex 是更灵活的布局容器,支持 flexWrap、alignItems、justifyContent 等完整的 Flexbox 布局属性:
// 正确 - 使用 Flex 组件
Flex({ wrap: FlexWrap.Wrap, direction: FlexDirection.Row }) {
Text('Item 1')
Text('Item 2')
Text('Item 3')
}
Row/Column 与 Flex 的区别:
| 特性 | Row / Column | Flex |
|---|---|---|
| 布局方向 | Row: 水平 / Column: 垂直 | 自由指定 direction |
| 换行 | 不支持 | 支持 wrap: FlexWrap.Wrap |
| 对齐方式 | .alignItems() / .justifyContent() |
构造参数中指定 |
| 性能 | 更优(简化的布局计算) | 略慢(完整的 Flexbox 计算) |
| 使用场景 | 简单的线性布局 | 需要换行或更复杂的布局 |
经验总结:
- 需要换行布局时,使用
Flex而不是Row Row/Column适合简单的线性布局,性能更好Flex适合需要换行或复杂对齐的场景- 在使用 ArkUI 组件属性前,应查阅 API 文档确认组件是否支持该属性
6.3 构建成功后的 WARN 处理

IVGuard 构建成功后,日志中仍有 47 条 WARN。这些 WARN 不会导致构建失败,但值得关注和逐步修复。
6.3.1 getContext(this) 已弃用警告
警告信息:
WARN: ArkTS:WARN File: .../pages/Index.ets:11:21
'getContext' has been deprecated.
影响范围:在 15 个页面文件中都使用了 getContext(this)。
根因分析:
getContext(this) 在 API 24 中已被标记为 deprecated(弃用),推荐使用 this.getUIContext().getHostContext() 或 this.commonContext 等新 API。
当前处理:
由于 getContext(this) 虽然已弃用但仍可正常工作,当前不做修改,后续版本迁移到新 API 即可。这种"可用但弃用"的状态在 HarmonyOS API 演进中很常见,通常会在 2-3 个大版本后才真正移除。
未来迁移方案:
// 旧写法(已弃用)
const context = getContext(this) as common.UIAbilityContext
// 新写法(推荐)
const context = this.getUIContext().getHostContext() as common.UIAbilityContext
6.3.2 requestEnableNotification 已弃用警告
警告信息:
WARN: ArkTS:WARN File: .../service/NotificationService.ets:42:35
'requestEnableNotification' has been deprecated.
根因分析:
requestEnableNotification() 在 API 24 中已被弃用,推荐使用 notificationManager.requestEnableNotification() 或新的通知授权 API。
当前处理:
与 getContext 类似,已弃用但仍可用。后续版本迁移即可。
6.3.3 Function may throw exceptions 警告
警告信息:
WARN: ArkTS:WARN File: .../service/DataStore.ets:12:23
Function may throw exceptions. Special handling is required.
影响范围:DataStore.ets 中有 26 条此类警告。
根因分析:
ArkTS 编译器检测到某些函数调用可能抛出异常,但代码中没有使用 try-catch 进行异常处理。涉及的函数主要是 preferences 模块的同步 API,如 getPreferencesSync、putSync、getSync、flush 等。
当前处理:
这些同步 API 在正常情况下不会抛出异常(除非参数严重错误),当前不处理。如果需要严格消除警告,可以添加 try-catch:
// 当前写法
static loadMedicines(): Medicine[] {
const s = DataStore.getStore()
const raw = s.getSync('medicines', '[]') as string
return JSON.parse(raw) as Medicine[]
}
// 严格处理异常的写法
static loadMedicines(): Medicine[] {
try {
const s = DataStore.getStore()
const raw = s.getSync('medicines', '[]') as string
return JSON.parse(raw) as Medicine[]
} catch (e) {
hilog.error(0x0000, 'DataStore', 'Failed to load medicines: %{public}s', JSON.stringify(e))
return []
}
}
6.3.4 私有属性初始化警告
警告信息:
WARN: ArkTS:WARN File: .../pages/MedicinePage.ets:81:13
Property 'onCardClick' is private and can not be initialized through the component constructor.
WARN: ArkTS:WARN File: .../pages/NurseHomePage.ets:146:15
Property 'onHandle' is private and can not be initialized through the component constructor.
根因分析:
在 ArkUI 自定义组件中,private 修饰的属性不能通过组件构造器(即父组件调用子组件时的属性赋值)进行初始化。应该将 private 改为不限制访问修饰符(默认为 public)或使用 @Prop 等装饰器。
当前处理:
警告不影响功能,但建议后续修复。将 private 改为默认访问级别或 @Prop 即可。
6.3.5 WARN 处理优先级建议
| 优先级 | 警告类型 | 数量 | 建议 |
|---|---|---|---|
| P2 | getContext 已弃用 |
15 | 下一版本迁移到新 API |
| P2 | requestEnableNotification 已弃用 |
1 | 下一版本迁移到新 API |
| P3 | 函数可能抛出异常 | 26 | 逐步添加 try-catch |
| P3 | 私有属性初始化 | 2 | 修改访问修饰符 |
7. 常见构建问题与解决方案
7.1 权限配置错误
7.1.1 无效权限名
症状:构建失败,错误提示权限名不存在。
常见错误:
// 错误:不存在的权限名
{ "name": "ohos.permission.SCAN_WIFI" } // 不存在
{ "name": "ohos.permission.CAMERA_ACCESS" } // 不存在
{ "name": "ohos.permission.READ_CALENDAR" } // 不存在
// 正确:
{ "name": "ohos.permission.GET_WIFI_INFO" }
{ "name": "ohos.permission.CAMERA" }
{ "name": "ohos.permission.READ_CALENDAR" } // 这个确实存在
解决方案:
- 查阅官方权限列表确认权限名是否正确
- 注意权限名大小写敏感(
caseSensitiveCheck: true) - 参考权限文档:
https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/permissions-overview
7.1.2 缺少 reason 字段
症状:构建警告或应用上架被驳回。
规则:
user_grant权限必须配置reason字段system_grant权限不需要reason字段
// 错误 - user_grant 权限缺少 reason
{
"name": "ohos.permission.CAMERA"
// 缺少 reason 和 usedScene
}
// 正确
{
"name": "ohos.permission.CAMERA",
"reason": "$string:camera_reason",
"usedScene": {
"abilities": ["EntryAbility"],
"when": "inuse"
}
}
7.1.3 usedScene 缺失
症状:构建警告或应用上架审核不通过。
规则:
user_grant权限应配置usedScene,声明权限使用的场景when字段可选值为inuse(仅前台)或always(前后台)- 优先使用
inuse,除非功能确实需要后台访问
// 错误 - usedScene 缺失
{
"name": "ohos.permission.LOCATION",
"reason": "$string:location_reason"
}
// 正确
{
"name": "ohos.permission.LOCATION",
"reason": "$string:location_reason",
"usedScene": {
"abilities": ["EntryAbility"],
"when": "inuse"
}
}
7.2 页面注册不一致
7.2.1 症状
- 启动应用后白屏
- 路由跳转时报错
- 页面无法加载
7.2.2 根因
main_pages.json 中注册的页面与 entry/src/main/ets/pages/ 目录下的实际页面文件不匹配。
常见不一致场景:
- 新增了页面文件但未在 main_pages.json 注册:新增了
SettingsPage.ets,但忘记在main_pages.json中添加"pages/SettingsPage" - main_pages.json 注册了不存在的页面:注册了
"pages/ProfilePage",但实际没有ProfilePage.ets文件 - 页面路径拼写错误:
main_pages.json中写的是"pages/Monitor",但文件名是MonitorPage.ets
7.2.3 解决方案
- 每次新增页面时,同步更新
main_pages.json - 构建前检查页面文件与注册表的对应关系
- 使用脚本自动检测不一致:
# 检查 pages 目录下的 .ets 文件
$pages = Get-ChildItem -Path "entry\src\main\ets\pages" -Filter "*.ets" |
ForEach-Object { "pages/" + $_.BaseName }
# 读取 main_pages.json 中的注册页面
$registered = (Get-Content "entry\src\main\resources\base\profile\main_pages.json" |
ConvertFrom-Json).src
# 对比差异
$missing = $pages | Where-Object { $_ -notin $registered }
$extra = $registered | Where-Object { $_ -notin $pages }
if ($missing) { Write-Host "未注册的页面: $missing" }
if ($extra) { Write-Host "不存在的页面: $extra" }
7.3 ArkTS 严格模式编译错误
7.3.1 使用了 any/unknown 类型
错误:arkts-no-any-unknown
解决方案:
// 错误
let data: any = response
function parse(input: unknown): string
// 正确 - 使用具体类型
let data: Record<string, Object> = response
function parse(input: string): string
7.3.2 在 build() 中使用了 const/let
错误:Only UI component syntax can be written here
解决方案:
// 错误
build() {
const items = this.getList()
ForEach(items, (item: string) => { Text(item) })
}
// 正确 - 使用 @State
@Component
struct MyComponent {
@State items: string[] = []
aboutToAppear() {
this.items = this.getList()
}
build() {
ForEach(this.items, (item: string) => { Text(item) })
}
}
7.3.3 使用了对象字面量类型
错误:arkts-no-obj-literals-as-types
解决方案:
// 错误
type Config = { theme: string; fontSize: number }
// 正确 - 使用 class
class Config {
theme: string = ''
fontSize: number = 14
}
7.3.4 使用了结构类型而非类
错误:arkts-no-structural-type
解决方案:
// 错误 - 接口作为参数类型
function greet(person: { name: string }): string
// 正确 - 使用 class
class Person {
name: string = ''
}
function greet(person: Person): string
7.4 资源引用错误
7.4.1 $r 路径错误
错误现象:运行时资源找不到,显示空白或默认值。
常见错误:
// 错误 - 路径格式不正确
$r('string.camera_reason') // 缺少模块前缀
$r('entry.string.camera_reason') // 正确但不带 app 前缀
// 正确
$r('app.string.camera_reason') // 应用级资源
$r('entry.string.camera_reason') // 模块级资源
$r('app.media.layered_image') // 图片资源
$r('app.color.start_window_background') // 颜色资源
资源引用格式:
$r('app.{type}.{name}'):引用 AppScope 下的应用级资源$r('entry.{type}.{name}'):引用 entry 模块下的资源{type}可以是string、color、float、media、profile
7.4.2 $rawfile 路径错误
$rawfile 用于引用 resources/rawfile/ 目录下的原始文件:
// 正确 - 引用 rawfile 下的文件
$rawfile('config/data.json')
// 错误 - 路径不存在
$rawfile('data.json') // 如果文件在 rawfile/config/ 子目录下
注意事项:
$rawfile的路径相对于resources/rawfile/目录- 不需要写
resources/rawfile/前缀 - 支持 子目录路径
7.5 签名配置问题
7.5.1 真机调试签名缺失
症状:hdc install 安装 HAP 到真机时报签名错误。
解决方案:
- 在 DevEco Studio 中配置自动签名
- 或手动配置
signingConfigs
7.5.2 签名证书过期
症状:签名失败,提示证书已过期。
解决方案:
- 在 AppGallery Connect 中重新申请调试证书
- 更新
build-profile.json5中的证书路径
7.5.3 签名类型不匹配
症状:签名失败,提示签名类型与设备系统不匹配。
解决方案:
确保 signingConfigs 中的 type 与目标设备系统一致:
- 目标为 HarmonyOS 设备:
type: "HarmonyOS" - 目标为 OpenHarmony 设备:
type: "OpenHarmony"
8. CI/CD 集成建议
8.1 命令行构建
8.1.1 hvigorw 命令行构建
Hvigor 的命令行接口是 CI/CD 集成的基础。所有在 DevEco Studio 中执行的构建操作,都可以通过命令行完成。
基本构建命令:
# 构建整个 APP(包含所有模块)
hvigorw assembleApp --no-daemon
# 仅构建 entry 模块的 HAP
hvigorw assembleHap --no-daemon
# 指定 product 和 buildMode
hvigorw assembleApp -p product=default -p buildMode=debug --no-daemon
# 构建 release 包
hvigorw assembleApp -p product=default -p buildMode=release --no-daemon
# 清理构建产物后重新构建
hvigorw clean assembleApp --no-daemon
--no-daemon 参数的重要性:
在 CI/CD 环境中,必须使用 --no-daemon 参数,原因如下:
- Hvigor 默认启动守护进程(daemon)来加速后续构建
- 守护进程在构建完成后不会自动退出,会占用内存
- 在 CI/CD 流水线中,守护进程会导致构建任务"挂住",无法正常结束
--no-daemon确保构建完成后进程立即退出
IVGuard 的 CI 构建命令:
# 完整的 CI 构建脚本
$projectDir = "F:\projects\IVGuard"
# 1. 拉取最新代码
git pull origin main
# 2. 安装依赖
ohpm install
# 3. 清理旧构建产物
hvigorw clean --no-daemon
# 4. 构建 debug HAP
hvigorw assembleHap -p product=default -p buildMode=debug --no-daemon
# 5. 检查构建结果
$hapPath = "$projectDir\entry\build\default\outputs\default\entry-default-unsigned.hap"
if (Test-Path $hapPath) {
Write-Host "BUILD SUCCESS: $hapPath"
} else {
Write-Host "BUILD FAILED"
exit 1
}
8.1.2 环境变量配置
在 CI/CD 环境中,需要确保以下工具可用:
# 设置 DevEco Studio 工具链路径
$devecoHome = "F:\DevEco Studio"
$env:PATH += ";$devecoHome\tools\node"
$env:PATH += ";$devecoHome\tools\hvigor\bin"
$env:PATH += ";$devecoHome\tools\ohpm\bin"
$env:PATH += ";$devecoHome\tools\hdc"
# 设置 SDK 路径
$env:HARMONYOS_SDK_HOME = "F:\HarmonyOS\Sdk"
# 设置 Node.js 选项(大项目可能需要更多内存)
$env:NODE_OPTIONS = "--max-old-space-size=8192"
8.1.3 构建日志保存
在 CI/CD 中,构建日志是排查问题的重要依据:
# 将构建日志保存到文件
hvigorw assembleApp --no-daemon 2>&1 | Tee-Object -FilePath "build-$(Get-Date -Format 'yyyyMMdd-HHmmss').log"
或使用 --log-path 参数(如果 hvigor 支持):
hvigorw assembleApp --no-daemon --log-path build.log
8.2 自动化签名配置
8.2.1 签名材料的准备
在 CI/CD 环境中,签名材料需要提前准备并安全存储:
需要的签名材料:
| 文件 | 说明 | 获取方式 |
|---|---|---|
.p12 文件 |
密钥库文件 | 通过 DevEco Studio 或 keytool 生成 |
.cer 文件 |
证书文件 | 从 AppGallery Connect 下载 |
.p7b 文件 |
Profile 文件 | 从 AppGallery Connect 下载 |
签名材料的安全管理:
# 签名材料应存放在安全的 CI/CD 密钥管理系统中
# 不要将签名材料提交到 Git 仓库!
# Jenkins 示例:使用 Credentials 存储签名密码
$certPath = Get-Credential -Message "Certificate Path"
$storePassword = $env:SIGNING_STORE_PASSWORD # 从 CI 环境变量读取
$keyPassword = $env:SIGNING_KEY_PASSWORD # 从 CI 环境变量读取
8.2.2 动态配置 signingConfigs
在 CI/CD 中,可以通过脚本动态生成 build-profile.json5 的签名配置:
// generate-signing-config.js
const fs = require('fs');
const path = require('path');
const buildProfilePath = path.join(__dirname, 'build-profile.json5');
let content = fs.readFileSync(buildProfilePath, 'utf-8');
const signingConfig = {
name: 'default',
type: 'HarmonyOS',
material: {
certpath: process.env.SIGNING_CERT_PATH,
storePassword: process.env.SIGNING_STORE_PASSWORD,
keyAlias: process.env.SIGNING_KEY_ALIAS || 'debugKey',
keyPassword: process.env.SIGNING_KEY_PASSWORD,
profile: process.env.SIGNING_PROFILE_PATH,
signAlg: 'SHA256withECDSA',
storeFile: process.env.SIGNING_STORE_FILE
}
};
// 替换 signingConfigs
content = content.replace(
/"signingConfigs":\s*\[\]/,
`"signingConfigs": [${JSON.stringify(signingConfig, null, 2)}]`
);
fs.writeFileSync(buildProfilePath, content, 'utf-8');
console.log('Signing config generated successfully');
# CI 流水线中使用
node generate-signing-config.js
hvigorw assembleApp -p buildMode=release --no-daemon
8.2.3 使用自动签名(AGC)
如果使用华为 AppGallery Connect(AGC)自动签名:
- 在 AGC 中注册应用,获取
clientId和clientSecret - 在 CI/CD 环境中配置这些凭证
- 构建时使用 AGC CLI 自动获取签名材料
8.3 构建产物归档
8.3.1 产物路径
IVGuard 构建后的产物路径:
# HAP 包
entry/build/default/outputs/default/entry-default-unsigned.hap # 未签名 HAP
entry/build/default/outputs/default/app/entry-default.hap # 已签名 HAP
# APP 包
build/outputs/default/IVGuard-default-unsigned.app # 未签名 APP
build/outputs/default/IVGuard-default-signed.app # 已签名 APP
# Source Map(用于线上崩溃还原)
entry/build/default/outputs/default/mapping/sourceMaps.map
# 构建日志
entry/build/default/outputs/default/entry-default-build.log
8.3.2 归档脚本
# 归档构建产物
$buildId = Get-Date -Format 'yyyyMMdd-HHmmss'
$archiveDir = "F:\archives\IVGuard\$buildId"
New-Item -ItemType Directory -Path $archiveDir -Force
# 复制 HAP 包
Copy-Item "entry\build\default\outputs\default\entry-default-unsigned.hap" $archiveDir
# 复制 APP 包(如果存在)
if (Test-Path "build\outputs\default\IVGuard-default-unsigned.app") {
Copy-Item "build\outputs\default\IVGuard-default-unsigned.app" $archiveDir
}
# 复制 Source Map
Copy-Item "entry\build\default\outputs\default\mapping\sourceMaps.map" $archiveDir
# 复制构建日志
Copy-Item "build.log" $archiveDir -ErrorAction SilentlyContinue
# 生成构建信息文件
$buildInfo = @{
buildId = $buildId
versionName = "1.0.0"
versionCode = 1000000
bundleName = "com.example.ivguard"
buildTime = Get-Date -Format 'yyyy-MM-dd HH:mm:ss'
gitCommit = git rev-parse HEAD
buildMode = "debug"
} | ConvertTo-Json
Set-Content -Path "$archiveDir\build-info.json" -Value $buildInfo
Write-Host "Archived to: $archiveDir"
8.3.3 产物命名规范
建议使用以下命名规范区分不同构建产物:
IVGuard-{versionName}-{buildMode}-{buildId}.hap
IVGuard-{versionName}-{buildMode}-{buildId}.app
# 示例
IVGuard-1.0.0-debug-20260803120000.hap
IVGuard-1.0.0-release-20260803120000.app
8.4 多渠道打包
8.4.1 多 Product 配置
通过 build-profile.json5 的 products 数组,可以配置多个构建产物:
{
"app": {
"products": [
{
"name": "default",
"signingConfig": "default",
"targetSdkVersion": "6.1.1(24)",
"compatibleSdkVersion": "6.1.1(24)",
"runtimeOS": "HarmonyOS"
},
{
"name": "nurse",
"signingConfig": "nurse",
"targetSdkVersion": "6.1.1(24)",
"compatibleSdkVersion": "6.1.1(24)",
"runtimeOS": "HarmonyOS",
"buildOption": {
"arkOptions": {
"compilerOptions": {
"arkuiBuild": "partial"
}
}
}
}
]
}
}
8.4.2 构建不同渠道包
# 构建默认渠道包
hvigorw assembleHap -p product=default -p buildMode=release --no-daemon
# 构建护士专用渠道包
hvigorw assembleHap -p product=nurse -p buildMode=release --no-daemon
8.4.3 环境隔离配置
在多人协作开发时,每个开发者可以配置自己的签名和 product:
// build-profile.json5
{
"app": {
"signingConfigs": [
{
"name": "dev_zhang",
"type": "HarmonyOS",
"material": {
"certpath": "D:/Signing/zhang/cert.cer",
"storeFile": "D:/Signing/zhang/key.p12",
// ...
}
},
{
"name": "dev_li",
"type": "HarmonyOS",
"material": {
"certpath": "D:/Signing/li/cert.cer",
"storeFile": "D:/Signing/li/key.p12",
// ...
}
}
],
"products": [
{
"name": "zhang",
"signingConfig": "dev_zhang",
"targetSdkVersion": "6.1.1(24)",
"compatibleSdkVersion": "6.1.1(24)",
"runtimeOS": "HarmonyOS"
},
{
"name": "li",
"signingConfig": "dev_li",
"targetSdkVersion": "6.1.1(24)",
"compatibleSdkVersion": "6.1.1(24)",
"runtimeOS": "HarmonyOS"
}
]
}
}
8.4.4 GitHub Actions 集成示例
以下是一个完整的 GitHub Actions 工作流示例,用于自动化构建 IVGuard:
# .github/workflows/build.yml
name: IVGuard Build
on:
push:
branches: [ main, develop ]
pull_request:
branches: [ main ]
jobs:
build:
runs-on: windows-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '18'
- name: Setup DevEco CLI
run: npm install -g @deveco/deveco-cli@latest
- name: Install Dependencies
run: ohpm install
working-directory: F:\projects\IVGuard
- name: Build Debug HAP
run: |
hvigorw assembleHap -p product=default -p buildMode=debug --no-daemon
working-directory: F:\projects\IVGuard
env:
NODE_OPTIONS: --max-old-space-size=8192
- name: Archive Build Artifacts
uses: actions/upload-artifact@v4
with:
name: IVGuard-debug-hap
path: F:\projects\IVGuard\entry\build\default\outputs\default\entry-default-unsigned.hap
- name: Build Release APP
if: github.ref == 'refs/heads/main'
run: |
hvigorw assembleApp -p product=default -p buildMode=release --no-daemon
working-directory: F:\projects\IVGuard
env:
NODE_OPTIONS: --max-old-space-size=8192
SIGNING_CERT_PATH: ${{ secrets.SIGNING_CERT_PATH }}
SIGNING_STORE_PASSWORD: ${{ secrets.SIGNING_STORE_PASSWORD }}
SIGNING_KEY_ALIAS: ${{ secrets.SIGNING_KEY_ALIAS }}
SIGNING_KEY_PASSWORD: ${{ secrets.SIGNING_KEY_PASSWORD }}
SIGNING_PROFILE_PATH: ${{ secrets.SIGNING_PROFILE_PATH }}
SIGNING_STORE_FILE: ${{ secrets.SIGNING_STORE_FILE }}
8.4.5 Jenkins 集成示例
// Jenkinsfile
pipeline {
agent { label 'windows' }
environment {
PROJECT_DIR = 'F:\\projects\\IVGuard'
NODE_OPTIONS = '--max-old-space-size=8192'
}
stages {
stage('Checkout') {
steps {
checkout scm
}
}
stage('Install Dependencies') {
steps {
bat "ohpm install"
}
}
stage('Build Debug') {
steps {
bat "hvigorw assembleHap -p product=default -p buildMode=debug --no-daemon"
}
}
stage('Archive') {
steps {
archiveArtifacts artifacts: "entry/build/default/outputs/default/*.hap", allowEmptyArchive: true
}
}
stage('Deploy to Test Device') {
when {
branch 'develop'
}
steps {
bat "hdc install -r entry/build/default/outputs/default/entry-default-unsigned.hap"
}
}
}
post {
failure {
mail to: 'team@example.com',
subject: "IVGuard Build Failed: ${env.JOB_NAME} #${env.BUILD_NUMBER}",
body: "Build failed. Check console output at ${env.BUILD_URL}"
}
}
}
附录
A. IVGuard 项目文件速查表
| 文件路径 | 类型 | 说明 |
|---|---|---|
AppScope/app.json5 |
配置 | 应用标识(bundleName、version) |
AppScope/resources/base/element/string.json |
资源 | 应用级字符串资源 |
build-profile.json5 |
配置 | 工程级构建配置 |
entry/build-profile.json5 |
配置 | 模块级构建配置 |
entry/src/main/module.json5 |
配置 | 模块声明(Ability、权限) |
entry/src/main/resources/base/profile/main_pages.json |
配置 | 页面路由注册 |
entry/src/main/resources/base/profile/backup_config.json |
配置 | 备份恢复配置 |
entry/src/main/resources/base/element/string.json |
资源 | 模块级字符串资源 |
entry/src/main/resources/base/element/color.json |
资源 | 颜色资源 |
entry/src/main/resources/base/element/float.json |
资源 | 尺寸资源 |
entry/src/main/ets/entryability/EntryAbility.ets |
源码 | 入口 Ability |
entry/src/main/ets/entrybackupability/EntryBackupAbility.ets |
源码 | 备份扩展 |
entry/src/main/ets/pages/*.ets |
源码 | 17 个页面 |
entry/src/main/ets/component/*.ets |
源码 | 8 个自定义组件 |
entry/src/main/ets/service/*.ets |
源码 | 11 个服务类 |
entry/src/main/ets/model/*.ets |
源码 | 6 个数据模型 |
entry/oh-package.json5 |
配置 | 模块级依赖声明 |
entry/obfuscation-rules.txt |
配置 | 代码混淆规则 |
entry/hvigorfile.ts |
脚本 | 模块级构建脚本 |
oh-package.json5 |
配置 | 工程级依赖声明 |
oh-package-lock.json5 |
锁文件 | 依赖锁文件 |
hvigorfile.ts |
脚本 | 工程级构建脚本 |
hvigor/hvigor-config.json5 |
配置 | 构建工具配置 |
code-linter.json5 |
配置 | 代码检查配置 |
B. 常用构建命令速查
| 命令 | 说明 |
|---|---|
hvigorw assembleHap |
构建 HAP 包 |
hvigorw assembleApp |
构建 APP 包 |
hvigorw assembleHar |
构建 HAR 包 |
hvigorw assembleHsp |
构建 HSP 包 |
hvigorw clean |
清理构建产物 |
hvigorw clean assembleApp --no-daemon |
清理后全量构建 |
hvigorw -p buildMode=debug assembleHap |
构建 debug HAP |
hvigorw -p buildMode=release assembleHap |
构建 release HAP |
ohpm install |
安装依赖 |
ohpm install <package> |
安装指定依赖 |
hdc install <hap> |
安装 HAP 到设备 |
hdc hilog |
查看设备日志 |
hdc list targets |
列出已连接设备 |
C. 权限速查表
| 权限 | 授权类型 | 说明 |
|---|---|---|
ohos.permission.CAMERA |
user_grant | 相机 |
ohos.permission.NFC_TAG |
user_grant | NFC 标签 |
ohos.permission.NOTIFICATION_CONTROLLER |
user_grant | 通知控制 |
ohos.permission.KEEP_BACKGROUND_RUNNING |
user_grant | 后台保活 |
ohos.permission.VIBRATE |
system_grant | 振动 |
ohos.permission.LOCATION |
user_grant | 精确定位 |
ohos.permission.APPROXIMATELY_LOCATION |
user_grant | 粗略定位 |
ohos.permission.GET_WIFI_INFO |
system_grant | WiFi 信息 |
ohos.permission.INTERNET |
system_grant | 网络访问 |
ohos.permission.READ_MEDIA |
user_grant | 读取媒体文件 |
ohos.permission.WRITE_MEDIA |
user_grant | 写入媒体文件 |
ohos.permission.MICROPHONE |
user_grant | 麦克风 |
ohos.permission.BLUETOOTH |
system_grant | 蓝牙 |
更多推荐


所有评论(0)