NearPlay 构建配置与签名部署
1. HarmonyOS 应用构建体系
1.1 hvigor 构建工具概述
HarmonyOS 采用了全新的构建工具链 hvigor(HarmonyOS Vigor),而非传统前端生态中的 webpack 或 Android 生态中的 Gradle。理解 hvigor 的设计理念和运行机制,是掌握 HarmonyOS 应用构建流程的关键。
┌────────────────────────────────────────────────────────────┐
│ 构建工具对比 │
├──────────┬──────────────┬──────────────┬─────────────────────┤
│ 维度 │ hvigor │ webpack │ Gradle │
├──────────┼──────────────┼──────────────┼─────────────────────┤
│ 适用平台 │ HarmonyOS │ Web/跨平台 │ Android/JVM │
│ 配置语言 │ TypeScript │ JavaScript │ Groovy/Kotlin DSL │
│ 配置文件 │ hvigorfile.ts│ webpack.config│ build.gradle(.kts) │
│ 增量构建 │ 原生支持 │ 插件支持 │ 原生支持 │
│ 任务模型 │ Task Pipeline │ Loader/Plugin│ Task DAG │
│ 包产物 │ HAP/HSP/HAR │ JS Bundle │ AAR/APK │
│ 守护进程 │ hvigor daemon │ 无 │ Gradle daemon │
│ 缓存机制 │ 全局+项目级 │ loader缓存 │ build-cache │
│ 依赖管理 │ ohpm │ npm/yarn │ Maven │
│ IDE集成 │ DevEco Studio│ 各类IDE插件 │ Android Studio │
└──────────┴──────────────┴──────────────┴─────────────────────┘
hvigor 的核心设计目标包括:
-
TypeScript 原生配置:与 ArkTS 应用代码语言一致,开发者无需学习额外的 DSL。hvigorfile.ts 中的任务定义使用标准 TypeScript 语法,可以充分利用类型检查和 IDE 智能提示。
-
任务管道模型:hvigor 采用线性任务管道(Task Pipeline)模型,每个构建任务接收输入、执行变换、产出输出。这与 webpack 的 Loader 链和 Gradle 的有向无环图(DAG)不同,管道模型更简单直观,适合 HarmonyOS 应用的构建场景。
-
内置增量编译:hvigor 在任务级别实现了增量检测,只有当任务的输入文件或配置发生变化时才重新执行,否则直接复用上次的输出。对于 ArkTS 编译任务,hvigor 还支持文件级增量,仅重新编译修改过的 .ets/.ts 文件。
-
守护进程加速:hvigor daemon 是一个常驻后台进程,避免每次构建都重新启动 Node.js 运行时和加载插件。daemon 会监听项目文件变化,在收到构建请求时快速响应。首次启动 daemon 需要几秒钟,后续构建可节省 2-5 秒的冷启动时间。
-
ohpm 生态集成:hvigor 与 HarmonyOS 的包管理器 ohpm 深度集成,oh_modules 目录中的依赖会被自动解析和参与构建。依赖的 HAR/HSP 模块会被正确链接到主模块的构建流程中。
1.2 构建生命周期
hvigor 的构建生命周期可分为以下几个阶段:
┌─────────────────────────────────────────────────────────────┐
│ hvigor 构建生命周期 │
│ │
│ ┌─────────┐ ┌──────────┐ ┌───────────┐ ┌──────────┐ │
│ │ 初始化 │───▶│ 配置解析 │───▶│ 任务执行 │───▶│ 产出输出 │ │
│ │ Init │ │ Configure│ │ Execute │ │ Output │ │
│ └─────────┘ └──────────┘ └───────────┘ └──────────┘ │
│ │ │ │ │ │
│ ▼ ▼ ▼ ▼ │
│ 加载 hvigor- 读取 build- 按依赖顺序 生成 HAP/ │
│ config.json5, profile.json5, 执行各任务 HSP/HAR │
│ 初始化 hvigor 解析 products, CompileArkTS, 写入 build │
│ daemon 连接 signingConfigs ProcessRes, 输出目录 │
│ 合并模块配置 SignHap... │
└─────────────────────────────────────────────────────────────┘
初始化阶段(Init):
- 加载项目根目录的
hvigor-config.json5,获取 hvigor 版本和全局设置 - 建立与 hvigor daemon 的连接(如果 daemon 已运行),或启动新的 daemon 进程
- 扫描项目结构,发现所有模块(entry、feature、shared 等)
配置解析阶段(Configure):
- 读取根级
build-profile.json5,解析 products、signingConfigs、modules - 读取每个模块的
build-profile.json5,解析 apiType、buildOption、targets - 根据
--product和--target参数,确定本次构建的 product 和 target 组合 - 合并 app 级和 module 级配置,生成最终的构建配置对象
- 读取
module.json5和资源文件,建立模块元数据
任务执行阶段(Execute):
- 根据构建目标(assembleHap、assembleApp 等),确定需要执行的任务列表
- 按任务的依赖关系排列执行顺序
- 依次执行每个任务,支持增量检测跳过未变化的任务
- 实时输出构建日志,包括警告和错误信息
产出输出阶段(Output):
- 将签名后的 HAP 包写入
build/default/outputs/目录 - 生成构建摘要报告,包含各模块的包大小、任务耗时等信息
- 对于 assembleApp,还会生成完整的 APP 包(.app 文件)
1.3 命令行参数
hvigor 支持丰富的命令行参数,可在 DevEco Studio 的终端或命令行环境中使用:
bash
# 基本构建命令
hvigorw assembleHap # 构建单个 HAP 包
hvigorw assembleApp # 构建完整 APP 包
hvigorw clean # 清理构建产物
# 指定产品和目标
hvigorw assembleHap --product default # 指定 product
hvigorw assembleHap --target default # 指定 target
hvigorw assembleHap -p product=default # 简写形式
# 构建模式
hvigorw assembleHap --mode release # release 模式
hvigorw assembleHap --mode debug # debug 模式(默认)
# 增量控制
hvigorw assembleHap --no-incremental # 禁用增量编译,全量构建
hvigorw clean && hvigorw assembleHap # 先清理再构建
# 守护进程控制
hvigorw --stop-daemon # 停止 daemon
hvigorw --no-daemon # 不使用 daemon,前台运行
hvigorw --daemon-status # 查看 daemon 状态
# 分析与调试
hvigorw assembleHap --analyze=normal # 构建分析(普通级别)
hvigorw assembleHap --analyze=advanced # 构建分析(高级别)
hvigorw assembleHap --verbose # 详细日志输出
# 模块指定
hvigorw --module entry assembleHap # 仅构建 entry 模块
在 NearPlay 项目中,典型的构建命令执行流程如下:
$ hvigorw --module entry@default assembleHap
> hvigor Finished :entry:default@CompileArkTS... after 15 s 230 ms
> hvigor Finished :entry:default@GeneratePkgModuleJson... after 120 ms
> hvigor Finished :entry:default@ProcessCompiledResources... after 890 ms
> hvigor Finished :entry:default@PackageHap... after 2 s 150 ms
> hvigor Finished :entry:default@SignHap... after 890 ms
> hvigor Finished :entry:default@assembleHap... after 30 s 120 ms
hvigor BUILD SUCCESSFUL in 30 s 234 ms
整个构建过程大约耗时 30 秒,其中 CompileArkTS 占据了大部分时间。这是因为在增量编译场景下,资源处理和打包阶段相对较快,而 ArkTS 编译器需要将 .ets 文件编译为方舟字节码(abc 文件),这个过程较为耗时。
2. build-profile.json5 详解
build-profile.json5 是 HarmonyOS 项目中最重要的构建配置文件,分为 app 级(项目根目录)和 module 级(模块目录)两个层级。两个层级的配置相互配合,共同决定项目的构建行为。
2.1 App 级 build-profile.json5
NearPlay 项目的 app 级配置位于项目根目录 F:\projects\NearPlay\build-profile.json5:
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 :签名配置数组。当前为空数组 [],表示没有配置任何签名方案。在实际真机部署时,需要在此数组中添加签名配置项。每个签名配置项包含 name(配置名称)、type(签名类型,通常为 HarmonyOS)、material(签名材料,包含证书和配置文件路径)。当此数组为空时,构建系统会使用默认的调试签名,生成的 HAP 包可以在模拟器上运行,但无法在真机上安装。
app.products :产品变体数组。每个 product 定义了一种构建变体,包含目标 SDK 版本、签名关联、运行时操作系统等信息。当前只有一个 default 产品:
name:产品名称,为"default"。在多产品场景下(如免费版/付费版),可以定义多个 product,每个使用不同的名称。signingConfig:关联的签名配置名称,为"default"。但当前signingConfigs数组为空,所以这个关联实际上没有生效。配置签名后,此值应对应signingConfigs数组中某个配置项的name。targetSdkVersion:目标 SDK 版本,为"6.1.1(24)",对应 HarmonyOS NEXT SDK 6.1.1、API 版本 24。这是应用编译时使用的 SDK 版本,决定了可用的 API 范围。compatibleSdkVersion:兼容 SDK 版本,同样为"6.1.1(24)",表示应用最低兼容的 SDK 版本。在应用市场分发时,系统会检查此值以确定应用是否可以在用户设备上运行。当 target 和 compatible 相同时,应用仅支持该版本及以上的设备。runtimeOS:运行时操作系统,为"HarmonyOS",表示应用运行在 HarmonyOS 上。另一个可选值是"OpenHarmony"。buildOption.strictMode:严格模式配置。caseSensitiveCheck: true启用大小写敏感检查,确保资源引用和文件路径的大小写完全匹配,避免在大小写不敏感的文件系统(如 Windows)上开发但在大小写敏感的系统(如 Linux)上部署时出现找不到资源的问题。useNormalizedOHMUrl: true启用规范化的 OHM URL,确保 OpenHarmony Module 的引用路径使用统一的规范格式。
app.buildModeSet :构建模式集合。定义了 debug 和 release 两种构建模式。debug 模式下,编译器不进行代码优化和混淆,便于调试;release 模式下,编译器会进行代码优化、混淆和压缩,减小包体积并提升运行性能。
app.modules (注意:此字段位于 app 同级):模块声明数组,声明项目中包含的所有模块。当前只有一个 entry 模块:
name:模块名称,为"entry",必须与模块目录名一致。srcPath:模块源码路径,为"./entry",相对于项目根目录。targets:模块的目标数组。每个目标定义了模块的一个构建变体。当前只有一个default目标,applyToProducts: ["default"]表示此目标应用于default产品。在多产品场景下,不同产品可以应用不同的模块目标。
2.2 Module 级 build-profile.json5
NearPlay 项目的 module 级配置位于 F:\projects\NearPlay\entry\build-profile.json5:
json5
{
"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 模型。Stage 模型是 HarmonyOS 推荐的应用开发模型,提供了更清晰的 Ability 生命周期和更高效的多设备适配能力。另一个可选值是 "faMode"(FA 模型,即 Feature Ability 模型),这是早期的 API 模型,已不推荐新项目使用。
buildOption:模块级构建选项,对 debug 和 release 模式均生效:
resOptions.copyCodeResource.enable:设为false,表示不将代码资源(如 rawfile 中的脚本文件)复制到编译输出中。这可以减小包体积,但意味着运行时不能通过 rawfile 访问这些代码资源。对于 NearPlay 应用,所有逻辑代码都在 ArkTS 中实现,无需额外的代码资源文件。
buildOptionSet :特定构建模式下的选项集合。当前定义了 release 模式的选项:
arkOptions.obfuscation.ruleOptions.enable:设为false,表示即使在 release 模式下也不启用代码混淆。这对于调试阶段很方便,但正式发布时应设为true并配置相应的混淆规则,以保护代码不被逆向分析。arkOptions.obfuscation.ruleOptions.files:混淆规则文件路径,为"./obfuscation-rules.txt",相对于模块目录。当启用混淆时,此文件中定义的保留规则和混淆策略会被应用。
targets:模块目标数组,定义了模块的不同构建目标:
"default":默认目标,用于生成正式的 HAP 包。"ohosTest":测试目标,用于生成测试 HAP 包,包含在设备上运行的 UI 测试和集成测试代码。
2.3 配置关联关系
app 级和 module 级的配置通过 product → target → module 的链路关联:
┌───────────────────────────────────────────────────────────────┐
│ 配置关联关系图 │
│ │
│ app.signingConfigs ──────┐ │
│ (签名配置) │ 引用 │
│ │ │ │
│ ▼ ▼ │
│ app.products ────────── signingConfig │
│ ┌──────────────────┐ │
│ │ name: "default" │───┐ │
│ │ signingConfig: │ │ applyToProducts │
│ │ "default" │ │ │
│ │ targetSdkVersion:│ │ │
│ │ "6.1.1(24)" │ │ │
│ └──────────────────┘ │ │
│ │ │ │
│ │ 指定product │ │
│ ▼ ▼ │
│ modules[0].targets ── applyToProducts: ["default"] │
│ ┌──────────────────┐ │
│ │ name: "default" │───┐ 匹配 │
│ └─────────────────┘ │ │
│ ▼ │
│ entry/build-profile.json5 │
│ ┌──────────────────┐ │
│ │ targets: │ │
│ │ - "default" │ ◀── 匹配 module target name │
│ │ - "ohosTest" │ │
│ └──────────────────┘ │
└───────────────────────────────────────────────────────────────┘
当执行构建命令 hvigorw --module entry@default assembleHap 时,构建系统会:
- 从 app 级配置中找到
defaultproduct - 从 modules 中找到
entry模块的defaulttarget,其applyToProducts包含default - 从 module 级配置中匹配
defaulttarget - 合并 app 级和 module 级的 buildOption,生成最终构建参数
- 如果 signingConfigs 中有名为
default的配置,则关联到构建过程
2.4 签名配置方法
要为真机部署配置签名,需要在 app.signingConfigs 数组中添加签名配置:
json5
{
"app": {
"signingConfigs": [
{
"name": "default",
"type": "HarmonyOS",
"material": {
"certpath": "C:/path/to/cert.cer",
"storePassword": "xxxxxx",
"keyAlias": "debug",
"keyPassword": "xxxxxx",
"profile": "C:/path/to/debug.p7b",
"signAlg": "SHA256withECDSA",
"storeFile": "C:/path/to/debug.p12"
}
}
],
"products": [
{
"name": "default",
"signingConfig": "default",
// ... 其他配置
}
]
}
}
签名材料说明:
- certpath:应用证书文件路径(.cer),由华为开发者平台签发
- storeFile:密钥库文件路径(.p12),包含应用的私钥
- storePassword:密钥库密码
- keyAlias:密钥别名,标识密钥库中的特定密钥
- keyPassword:密钥密码
- profile:调试配置文件路径(.p7b),即 Provision Profile,包含设备 UDID 等信息
- signAlg :签名算法,通常使用
SHA256withECDSA
在 DevEco Studio 中,可以通过 File → Project Structure → Project → Signing Configs 界面图形化配置签名,也可以勾选 "Automatically generate signature" 让 IDE 自动生成调试签名。
3. module.json5 详解
module.json5 是 HarmonyOS 模块的核心配置清单文件,定义了模块的身份信息、设备适配、页面路由、权限声明、Ability 注册等关键元数据。它相当于 Android 的 AndroidManifest.xml 和 iOS 的 Info.plist 的综合体。
NearPlay 项目的 module.json5 位于 F:\projects\NearPlay\entry\src\main\module.json5:
json5
{
"module": {
"name": "entry",
"type": "entry",
"description": "$string:module_desc",
"mainElement": "EntryAbility",
"deviceTypes": ["phone"],
"deliveryWithInstall": true,
"installationFree": false,
"pages": "$profile:main_pages",
"requestPermissions": [...],
"abilities": [...],
"extensionAbilities": [...]
}
}
3.1 module.name
json5
"name": "entry"
模块名称,在应用包内唯一标识此模块。此名称必须与 build-profile.json5 中 modules 数组对应项的 name 字段一致,也必须与模块目录名一致。对于 entry 类型的模块,名称通常为 "entry"。
模块名称在运行时用于模块间引用和 HSP/HAR 的依赖解析。在 ohpm 包中,包名(bundleName)和模块名共同构成模块的全局唯一标识。
3.2 module.type
json5
"type": "entry"
模块类型,决定了模块在应用中的角色和构建行为。HarmonyOS 支持以下模块类型:
entry:入口模块,每个应用有且仅有一个 entry 模块。它是应用的安装入口,包含应用的主 Ability。entry 模块会被首先安装和启动。feature:特性模块,实现应用的特定功能。feature 模块可以动态安装和卸载,实现按需加载。一个应用可以有零个或多个 feature 模块。shared:共享模块(即 HSP,Harmony Shared Package),提供代码和资源的共享能力。shared 模块不能独立安装,只能被 entry 或 feature 模块引用。har:静态共享模块(Harmony Archive),编译时以静态链接方式合并到引用模块中。har 模块不产生独立的 HAP 包。
NearPlay 当前只有一个 entry 模块,所有功能都集中在此模块中。随着功能扩展,可以考虑将语音通信、附近发现等功能拆分为独立的 feature 模块。
3.3 module.description
json5
"description": "$string:module_desc"
模块描述,使用资源引用格式 $string:module_desc。构建时,系统会从资源文件 string.json 中查找名为 module_desc 的字符串值进行替换。在 NearPlay 中,该值为 "module description"。
使用资源引用而非硬编码字符串的好处:
- 国际化支持:不同语言环境下可以显示不同的描述文本
- 配置集中管理:所有用户可见的文本集中在资源文件中,便于统一修改
- 长度限制合规:应用市场上架时对描述文本有长度要求,资源引用方式便于调整
3.4 module.mainElement
json5
"mainElement": "EntryAbility"
模块的主元素,指定模块安装后首先启动的 Ability 名称。此值必须与 abilities 数组中某个 Ability 的 name 字段一致。
对于 entry 类型的模块,mainElement 指向应用的入口 Ability。当用户点击应用图标启动应用时,系统会启动此 Ability。在 NearPlay 中,mainElement 为 "EntryAbility",对应 abilities 数组中的第一个 Ability。
3.5 module.deviceTypes
json5
"deviceTypes": ["phone"]
设备类型数组,声明模块支持的设备类型。构建时,系统会根据此字段决定模块的设备适配策略。当前支持的设备类型包括:
phone:手机设备tablet:平板设备2in1:二合一设备(PC 平板二合一)tv:智慧屏/电视设备wearable:可穿戴设备(手表等)car:车机设备
NearPlay 当前仅支持 phone 类型。由于应用的核心功能是发现附近用户和语音交互,这些交互模式最适合手机场景。如果未来需要适配平板,可以添加 "tablet" 到数组中。
需要注意的是,deviceTypes 同时影响应用市场的分发策略。只有设备类型匹配的应用才会出现在对应设备的应用市场中。
3.6 module.deliveryWithInstall
json5
"deliveryWithInstall": true
是否随应用安装一起交付。设为 true 时,模块在应用安装时自动安装到设备上;设为 false 时,模块不随应用安装,而是在运行时按需下载安装。
对于 entry 模块,此值必须为 true,因为入口模块是应用运行的必要条件。对于 feature 模块,可以根据功能的使用频率决定是否随安装交付。高频使用的核心功能设为 true,低频使用的附加功能设为 false 以减小初始安装体积。
3.7 module.installationFree
json5
"installationFree": false
是否支持免安装。免安装是一种特殊的分发方式,用户无需完整安装应用即可快速体验应用的部分功能。设为 true 时,模块可以通过免安装方式分发和运行。
NearPlay 当前设为 false,不支持免安装。免安装模式对应用大小有严格限制(通常不超过 10MB),且功能受限,不适合需要完整系统权限(如位置和麦克风)的应用。
3.8 module.pages
json5
"pages": "$profile:main_pages"
页面路由配置,使用资源引用格式 $profile:main_pages。构建时,系统会在 resources/base/profile/ 目录下查找 main_pages.json 文件,该文件定义了模块中所有注册的页面路径:
json
{
"src": [
"pages/Index",
"pages/NearbyPage",
"pages/VoicePage"
]
}
页面路由文件中声明的页面才可以被导航访问。ArkUI 的 router.pushUrl() 和 Navigation 组件只能导航到已在 pages 中注册的路径。未注册的页面路径会导致运行时崩溃。
$profile: 前缀表示引用的是 profile 目录下的 JSON 配置文件,而非普通的字符串或媒体资源。
3.9 module.requestPermissions
json5
"requestPermissions": [
{
"name": "ohos.permission.INTERNET"
},
{
"name": "ohos.permission.APPROXIMATELY_LOCATION",
"reason": "$string:location_reason",
"usedScene": {
"abilities": ["EntryAbility"],
"when": "inuse"
}
},
{
"name": "ohos.permission.MICROPHONE",
"reason": "$string:microphone_reason",
"usedScene": {
"abilities": ["EntryAbility"],
"when": "inuse"
}
}
]
权限请求数组,声明模块运行时需要的系统权限。这是 HarmonyOS 权限管控体系的核心配置入口。每个权限项包含以下字段:
name :权限名称,使用 ohos.permission.XXX 格式。HarmonyOS 的权限分为三个等级:
- normal 级 :普通权限,风险较低,安装时自动授予。如
INTERNET。 - system_basic 级 :系统基础权限,风险较高,需要用户在运行时授权。如
APPROXIMATELY_LOCATION、MICROPHONE。 - system_core 级:系统核心权限,仅系统应用可申请。普通应用无法获取。
reason:权限申请理由,使用资源引用格式。对于 system_basic 级权限,此字段为必填。当系统弹出权限授权弹窗时,reason 文本会显示给用户,帮助用户理解为什么应用需要此权限。reason 文本必须清晰、具体,不能使用模糊的通用描述。
usedScene:权限使用场景,声明权限在哪些 Ability 中使用以及使用时机:
abilities:使用此权限的 Ability 名称数组。只有声明在此数组中的 Ability 才能申请和使用该权限。when:权限使用时机,"inuse"表示仅在前台使用时需要权限,"always"表示后台也需要权限。NearPlay 的位置和麦克风权限都设为"inuse",因为应用只在前台使用这些权限。
3.10 module.abilities
json5
"abilities": [
{
"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"]
}
]
}
]
Ability 数组,声明模块中包含的所有 UI Ability。每个 Ability 是一个独立的用户交互入口。NearPlay 的 EntryAbility 逐字段解读:
name :Ability 类名,为 "EntryAbility"。此名称必须与源码中 export 的 Ability 类名一致,也是 requestPermissions 和 usedScene.abilities 中引用的标识符。
srcEntry :Ability 源码入口路径,为 "./ets/entryability/EntryAbility.ets",相对于模块的 src/main/ 目录。构建时,系统根据此路径找到 Ability 的源码文件并编译。
description:Ability 描述,使用资源引用。在应用信息界面、权限管理界面等位置展示。
icon :Ability 图标,使用 $media:layered_image 引用媒体资源。layered_image 通常是一个自适应图标(Adaptive Icon),包含前景层和背景层。在设备桌面和应用列表中显示。
label :Ability 标签,使用 $string:EntryAbility_label 引用字符串资源,值为 "NearPlay"。这是在设备桌面上显示的应用名称。
startWindowIcon :启动窗口图标,为 $media:startIcon。应用冷启动时,系统会先显示一个启动窗口(Splash Screen),此图标在启动窗口中央显示。
startWindowBackground :启动窗口背景色,为 $color:start_window_background。启动窗口的背景颜色,通常使用品牌主色或纯白色。
exported :是否可被其他应用调用,为 true。设为 true 时,其他应用可以通过 Want 启动此 Ability;设为 false 时,只有同一应用内的组件可以启动。对于入口 Ability,通常设为 true,以便系统桌面可以启动应用。
skills:技能声明数组,定义 Ability 可以响应的隐式 Want。每个 skill 包含:
entities:实体过滤器,"entity.system.home"表示这是桌面应用入口actions:动作过滤器,"ohos.want.action.home"表示响应桌面启动动作
skills 的作用类似于 Android 的 Intent Filter。当用户点击桌面图标时,系统会发送一个包含 ohos.want.action.home 动作和 entity.system.home 实体的隐式 Want,所有声明了匹配 skill 的 Ability 都可以响应。
3.11 module.extensionAbilities
json5
"extensionAbilities": [
{
"name": "EntryBackupAbility",
"srcEntry": "./ets/entrybackupability/EntryBackupAbility.ets",
"type": "backup",
"exported": false,
"metadata": [
{
"name": "ohos.extension.backup",
"resource": "$profile:backup_config"
}
]
}
]
Extension Ability 数组,声明模块中的扩展能力。Extension Ability 是没有 UI 界面的后台组件,提供特定的系统能力。NearPlay 声明了一个备份扩展能力:
name :Extension Ability 类名,为 "EntryBackupAbility"
srcEntry :源码入口路径,为 "./ets/entrybackupability/EntryBackupAbility.ets"
type :扩展类型,为 "backup",表示这是一个备份/恢复扩展。HarmonyOS 的备份框架会调用此扩展来执行应用数据的备份和恢复操作。其他常见类型包括:
"service":Service Extension,后台长驻服务"form":卡片(Widget)扩展"workScheduler":延迟任务调度扩展"inputMethod":输入法扩展"accessibility":无障碍扩展
exported :为 false,表示此扩展不对外暴露,只有系统备份框架可以调用。
metadata:元数据数组,为扩展提供附加配置:
name:元数据名称,"ohos.extension.backup"是备份扩展的标准元数据名称resource:配置文件引用,$profile:backup_config指向resources/base/profile/backup_config.json,该文件定义了备份规则,如哪些文件需要备份、哪些需要排除等
4. 三个权限的 module.json5 配置
4.1 ohos.permission.INTERNET
json5
{
"name": "ohos.permission.INTERNET"
}
权限等级:normal(普通权限)
授权方式:安装时自动授予,无需用户确认
用途说明:INTERNET 权限允许应用访问网络,包括发起 HTTP 请求、WebSocket 连接、Socket 通信等。对于 NearPlay 应用,网络权限是核心基础------发现附近用户需要通过服务器进行坐标匹配和用户信息交换,语音通信需要通过网络传输音频数据。
配置要点:
- INTERNET 是 normal 级权限,无需
reason和usedScene字段。系统会在安装时自动授予此权限,用户不会看到授权弹窗。 - 即使不声明 INTERNET 权限,调试版本的应用在模拟器上也能访问网络(调试特权),但在真机和正式发布时必须显式声明,否则所有网络请求都会失败并抛出权限拒绝异常。
- 对于 NearPlay,网络请求可能使用
@ohos.net.http模块发起 HTTP 请求,或使用 WebSocket 进行实时通信。所有这些网络操作都依赖于 INTERNET 权限。
常见问题 :如果应用无法访问网络且没有声明 INTERNET 权限,运行时错误通常是 PermissionDeny 或网络请求返回错误码。排查时首先检查 module.json5 中是否声明了此权限。
4.2 ohos.permission.APPROXIMATELY_LOCATION
json5
{
"name": "ohos.permission.APPROXIMATELY_LOCATION",
"reason": "$string:location_reason",
"usedScene": {
"abilities": ["EntryAbility"],
"when": "inuse"
}
}
权限等级:system_basic(系统基础权限)
授权方式:运行时弹窗请求用户授权
用途说明:APPROXIMATELY_LOCATION 权限允许应用获取粗略位置信息,精度通常在城市街区级别(约 3 平方公里范围)。NearPlay 使用粗略位置来发现附近的在线用户------不需要精确到米级的定位,只需要大致区域信息即可匹配附近用户。
reason 配置:
json5
"reason": "$string:location_reason"
对应 string.json 中的值为 "用于发现附近的用户和活动。"。这个理由说明了位置权限的具体用途,符合 HarmonyOS 权限审核要求:
- 明确说明了"为什么"需要位置权限(发现附近用户和活动)
- 解释了位置信息的用途场景(附近用户匹配)
- 文本简洁具体,不是泛泛的"用于提供更好的服务"
usedScene 配置:
json5
"usedScene": {
"abilities": ["EntryAbility"],
"when": "inuse"
}
abilities: ["EntryAbility"]:位置权限仅在 EntryAbility 中使用。如果 NearPlay 未来添加了新的 Ability(如专门的地图查看 Ability),也需要将其添加到此数组中。when: "inuse":仅在前台使用时获取位置。应用退到后台后,位置访问会自动停止。这对于社交发现类应用是合理的------用户只有在打开应用时才需要发现附近的人。
APPROXIMATELY_LOCATION vs EXACT_LOCATION:
HarmonyOS 区分粗略位置和精确位置两个权限。NearPlay 选择 APPROXIMATELY_LOCATION(粗略位置)而非 ACCESS_LOCATION(精确位置),原因如下:
- 功能需求不需要精确位置------附近用户发现只需要大致区域
- 粗略位置的授权通过率更高------用户更愿意授予粗略位置权限
- 隐私合规要求最小权限原则------只申请功能所需的最小权限
- 应用市场审核更易通过------精确位置权限需要更充分的理由
4.3 ohos.permission.MICROPHONE
json5
{
"name": "ohos.permission.MICROPHONE",
"reason": "$string:microphone_reason",
"usedScene": {
"abilities": ["EntryAbility"],
"when": "inuse"
}
}
权限等级:system_basic(系统基础权限)
授权方式:运行时弹窗请求用户授权
用途说明:MICROPHONE 权限允许应用录制音频,使用设备麦克风捕获声音。NearPlay 使用麦克风实现两个核心功能:
- 游戏语音发言:在多人游戏中,玩家可以通过语音与其他玩家交流
- 语音输入:支持语音转文字的输入方式,方便快速发送消息
reason 配置:
json5
"reason": "$string:microphone_reason"
对应值为 "用于游戏语音发言和语音输入。"。这个理由明确说明了麦克风权限的两个使用场景,符合审核要求。
usedScene 配置:
json5
"usedScene": {
"abilities": ["EntryAbility"],
"when": "inuse"
}
麦克风权限设为 "inuse" 仅前台使用。这既是隐私合规的要求(后台录音需要 "always" 权限且审核极严),也是功能需求所决定------语音发言和语音输入都是用户主动操作,只在前台进行。
运行时权限请求流程:
对于 APPROXIMATELY_LOCATION 和 MICROPHONE 这两个 system_basic 级权限,仅声明配置还不够,还需要在代码中运行时请求:
typescript
import abilityAccessCtrl from '@ohos.abilityAccessCtrl';
const atManager = abilityAccessCtrl.createAtManager();
const grantStatus = await atManager.checkAccessToken(
bundleName, 'ohos.permission.APPROXIMATELY_LOCATION'
);
if (grantStatus === abilityAccessCtrl.GrantStatus.PERMISSION_DENIED) {
const result = await atManager.requestPermissionsFromUser(
context,
['ohos.permission.APPROXIMATELY_LOCATION', 'ohos.permission.MICROPHONE']
);
}
系统会弹出授权弹窗,弹窗中显示 reason 字段定义的理由文本。用户选择"允许"后,应用获得权限;选择"禁止"后,应用相关功能不可用,但不影响其他功能的正常使用。
4.4 三个权限的声明顺序
在 requestPermissions 数组中,权限的声明顺序有讲究:
- INTERNET 在最前:这是 normal 级权限,安装时自动授予,不会弹窗。放在最前是惯例,让配置的读者首先看到基础权限。
- APPROXIMATELY_LOCATION 在中间:功能上先需要位置发现用户,然后才需要语音交流。按照功能流程的先后顺序排列。
- MICROPHONE 在最后:这是用户最敏感的权限(录音),放在最后可以让用户先授权位置权限(相对不敏感),再授权麦克风权限,降低用户拒绝率。
5. string.json 权限文案
string.json 位于 F:\projects\NearPlay\entry\src\main\resources\base\element\string.json,其中与权限相关的文案如下:
json
{
"string": [
{
"name": "location_reason",
"value": "用于发现附近的用户和活动。"
},
{
"name": "microphone_reason",
"value": "用于游戏语音发言和语音输入。"
}
]
}
5.1 location_reason 文案
名称 :location_reason
值 :"用于发现附近的用户和活动。"
用途 :此文案在用户授权 APPROXIMATELY_LOCATION 权限时,显示在系统权限弹窗中,向用户解释应用为什么需要获取位置信息。
文案要求:
- 字数限制:建议 10-50 个汉字,过长会被截断,过短可能无法清晰解释用途
- 内容要求:必须说明权限的具体用途,不能使用"用于提供更好的服务"等模糊表述
- 语气要求:客观陈述用途,不使用祈使句或命令语气
- 合规要求:与应用实际功能一致,审核时会检查 reason 与功能是否匹配
5.2 microphone_reason 文案
名称 :microphone_reason
值 :"用于游戏语音发言和语音输入。"
用途 :此文案在用户授权 MICROPHONE 权限时显示,解释应用需要录音权限的原因。
文案分析:
- 明确列出了两个使用场景:游戏语音发言和语音输入
- 使用"用于"开头,直截了当说明用途
- 两个场景都围绕应用的核心交互功能,与 NearPlay 的定位一致
5.3 注意事项
-
国际化 :当前文案只有中文版本(base 目录)。如果应用需要支持其他语言,应在
resources/en_US/element/string.json中提供对应的英文翻译。例如:"Used for voice chat and voice input in games." -
文案更新 :修改权限文案后,只需修改
string.json中的value字段,无需修改module.json5中的$string:引用。构建系统会自动关联。 -
审核风险:权限文案是应用市场审核的重点检查项。如果文案过于模糊或与功能不符,可能被驳回。NearPlay 的两个文案都直接关联到核心功能,审核风险低。
6. HAP 打包流程
HAP(HarmonyOS Ability Package)是 HarmonyOS 应用的基本安装单元,类似于 Android 的 APK。理解 HAP 的打包流程有助于排查构建问题和优化构建性能。
6.1 打包流程概览
┌──────────────────────────────────────────────────────────────────┐
│ HAP 打包流程 │
│ │
│ .ets/.ts module.json5 resources/ assets/ │
│ 源码文件 模块配置 资源文件 原始资产 │
│ │ │ │ │ │
│ ▼ │ │ │ │
│ ┌──────────┐ │ │ │ │
│ │CompileAr │ │ │ │ │
│ │kTS │ │ │ │ │
│ │.ets→.abc │ │ │ │ │
│ └────┬─────┘ │ │ │ │
│ │ │ │ │ │
│ ▼ ▼ ▼ ▼ │
│ ┌────────────────────────────────────────────────────┐ │
│ │ GeneratePkgModuleJson │ │
│ │ 合并 module.json5 + build 配置 → module.json │ │
│ └────────────────────────┬─────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ ProcessCompiledResources │ │
│ │ 编译 resources → resources.index + 编译后资源 │ │
│ └────────────────────────┬─────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ PackageHap │ │
│ │ abc + module.json + resources + assets → HAP包 │ │
│ └───────────────────────┬────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌────────────────────────────────────────────────────┐ │
│ │ SignHap │ │
│ │ HAP包 + 签名材料 → 签名后的HAP包 │ │
│ └────────────────────────┬─────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌──────────────────┐ │
│ │ assembleHap │ │
│ │ 构建完成 │ │
│ └──────────────────┘ │
└──────────────────────────────────────────────────────────────────┘
6.2 CompileArkTS 阶段
CompileArkTS 是最耗时的构建任务,负责将 ArkTS 源码编译为方舟字节码:
- 输入:
src/main/ets/目录下的所有.ets和.ts文件 - 输出:
.abc文件(Ark Byte Code)
编译过程包括:
- 语法解析:ArkTS 编译器解析源码,构建抽象语法树(AST)
- 类型检查 :执行 ArkTS 严格模式的类型检查,包括
arkts-no-*系列规则 - 语法降级:将 ArkTS 高级语法降级为标准 JavaScript 语法(如结构体转为类、@Component 转为渲染函数等)
- 字节码生成:将降级后的代码编译为方舟字节码(abc),这是方舟运行时(Ark Runtime)可以直接执行的字节码格式
在增量编译场景下,CompileArkTS 只重新编译修改过的文件。hvigor 通过比较源文件的哈希值和修改时间来判断是否需要重新编译。在 NearPlay 项目中,增量编译通常在 5-15 秒内完成,而全量编译需要 15-25 秒。
6.3 GeneratePkgModuleJson 阶段
GeneratePkgModuleJson 负责生成最终的模块配置文件:
- 输入:
module.json5、build-profile.json5(app 级和 module 级) - 输出:
module.json(去掉 json5 注释和尾逗号,合并构建配置后的标准 JSON 文件)
处理逻辑:
- 解析
module.json5,移除 JSON5 特有的注释和尾逗号 - 解析资源引用(如
$string:xxx),在构建时保留引用格式(运行时由系统解析) - 合并
build-profile.json5中的相关配置(如 debug/release 模式的特定设置) - 验证配置的完整性和合法性(如 abilities 中引用的权限是否已声明)
- 生成标准 JSON 格式的
module.json
此任务通常在 100-200 毫秒内完成,是所有任务中最快的。
6.4 ProcessCompiledResources 阶段
ProcessCompiledResources 负责编译和打包资源文件:
- 输入:
resources/目录下的所有资源文件(字符串、颜色、媒体等) - 输出:
resources.index(资源索引文件)+ 编译后的资源文件
处理逻辑:
- 资源编译:将 XML/JSON 格式的资源文件编译为二进制格式,减小体积和加快运行时加载速度
- 索引生成 :创建
resources.index文件,建立资源 ID 到资源文件路径的映射关系 - 资源限定符处理:根据设备类型、语言、屏幕密度等限定符,组织资源的优先级链
- 资源验证 :检查资源引用的合法性,如
$string:xxx引用的字符串是否存在、$media:xxx引用的图片是否存在等
此任务在 NearPlay 项目中通常耗时 500-900 毫秒。资源文件越多,耗时越长。
6.5 PackageHap 阶段
PackageHap 将所有编译产物打包为一个 HAP 文件:
HAP 包内部结构:
├── entry/
│ ├── module.json ← 模块配置(由 GeneratePkgModuleJson 生成)
│ ├── resources.index ← 资源索引(由 ProcessCompiledResources 生成)
│ ├── ets/
│ │ └── entryability/
│ │ └── EntryAbility.abc ← 编译后的字节码
│ ├── resources/
│ │ ├── base/
│ │ │ ├── element/
│ │ │ │ └── string.json
│ │ │ ├── media/
│ │ │ │ ├── layered_image.png
│ │ │ │ └── startIcon.png
│ │ │ └── profile/
│ │ │ ├── main_pages.json
│ │ │ └── backup_config.json
│ │ └── zh_CN/ (如果有中文限定资源)
│ └── rawfile/ (如果有原始文件资产)
└── pack.info ← 包信息
6.6 SignHap 阶段
SignHap 为 HAP 包添加数字签名:
- 输入:未签名的 HAP 包 + 签名材料(证书、密钥、Profile)
- 输出:签名后的 HAP 包
签名过程:
- 计算HAP包内容的摘要(使用 SHA-256 哈希算法)
- 使用私钥对摘要进行数字签名(ECDSA 算法)
- 将签名信息、证书链和 Provision Profile 附加到 HAP 包中
- 验证签名的正确性,确保 HAP 包未被篡改
如果 signingConfigs 为空,构建系统使用默认调试签名。调试签名的 HAP 包只能在模拟器上运行,无法在真机上安装。
6.7 assembleHap 终点任务
assembleHap 是整个构建流程的终点任务,它本身不执行任何操作,只是声明了对上述所有任务的依赖关系。当 assembleHap 完成时,意味着所有前置任务都已成功执行,最终的 HAP 包已经生成在 build/default/outputs/entry/ 目录下。
NearPlay 项目中完整的构建耗时约 30 秒,各阶段占比:
┌──────────────────────────────────────────────┐
│ 构建耗时分布(约30秒) │
│ │
│ CompileArkTS ████████████████ 50% │
│ ProcessCompiledRes ████ 15% │
│ PackageHap ███ 10% │
│ SignHap ███ 10% │
│ GeneratePkgModuleJson █ 3% │
│ 其他(初始化、依赖解析) ███ 12% │
└──────────────────────────────────────────────┘
7. 签名配置
7.1 真机与模拟器的签名差异
HarmonyOS 对真机和模拟器的签名要求有本质区别:
┌────────────────────────────────────────────────────────────────┐
│ 签名要求对比 │
├───────────────────┬─────────────────────┬────────────────────────┤
│ 维度 │ 模拟器 │ 真机 │
├───────────────────┼─────────────────────┼────────────────────────┤
│ 签名要求 │ 可选(调试签名即可) │ 必须有效签名 │
│ 签名类型 │ 调试签名(自动生成) │ 开发者签名 │
│ 证书来源 │ SDK 内置 │ 华为开发者平台签发 │
│ Profile │ SDK 内置通用Profile │ 包含设备UDID的Profile │
│ 配置方式 │ 无需配置 │ build-profile.json5 │
│ 缺失签名 │ 正常运行 │ 安装失败 │
│ 安装方式 │ hdc install / IDE │ hdc install / IDE │
│ 应用市场 │ 不可上架 │ 签名后可上架 │
└──────────────────┴────────────────────┴───────────────────────┘
模拟器签名 :模拟器内置了宽松的签名验证策略,允许安装和运行未签名或使用调试签名的 HAP 包。这是因为模拟器本身就是开发环境的一部分,安全性要求较低。NearPlay 项目当前 signingConfigs 为空,构建出的 HAP 包使用调试签名,可以在模拟器上正常运行。
真机签名:真机对签名验证极其严格。HAP 包必须有有效的数字签名才能安装。签名过程涉及:
- 应用证书(.cer):由华为开发者平台签发的应用身份证书
- 调试 Profile(.p7b):开发阶段使用,包含允许调试的设备 UDID 列表
- 发布 Profile(.p7b):发布阶段使用,不包含设备限制
- 密钥库(.p12):包含应用私钥的 PKCS#12 格式文件
7.2 自动签名
DevEco Studio 提供了自动签名功能,是最便捷的签名配置方式:
- 打开 File → Project Structure → Project → Signing Configs
- 勾选 "Automatically generate signature"(自动生成签名)
- 登录华为开发者账号
- 选择或创建调试证书和 Profile
- IDE 自动将签名材料路径写入
build-profile.json5
自动签名的工作原理:
┌───────────────────────────────────────────────────────────┐
│ 自动签名流程 │
│ │
│ DevEco Studio │
│ │ │
│ ▼ │
│ 登录华为开发者账号 ────▶ 请求调试证书 │
│ │ │ │
│ │ ▼ │
│ │ 开发者平台签发证书 │
│ │ 生成 .cer + .p7b + .p12 │
│ │ │ │
│ ▼ ▼ │
│ 下载签名材料到本地目录 │
│ (通常在 ~/.hus/ 或项目 .cxx/ 目录下) │
│ │ │
│ ▼ │
│ 自动写入 build-profile.json5 │
│ signingConfigs 数组 │
│ │ │
│ ▼ │
│ 下次构建时自动使用签名 │
└───────────────────────────────────────────────────────────┘
自动签名的优势是配置简单、一键完成。缺点是签名材料存储在 IDE 管理的目录中,团队成员无法共享签名配置(因为密钥密码以明文存储在 build-profile.json5 中,不应提交到版本库)。
7.3 签名缺失警告
当 signingConfigs 为空时,构建过程会输出签名缺失警告:
> hvigor WARNING: The signingConfigs is not configured.
The HAP will be signed with the default debug signature,
which can only be installed on emulators. To deploy to
real devices, please configure signing in build-profile.json5.
此警告的含义:
- HAP 包已成功构建,使用默认调试签名
- HAP 包可以在模拟器上安装和运行
- 如需在真机上运行,必须配置正式签名
NearPlay 项目当前处于开发初期阶段,仅在模拟器上测试,因此签名缺失警告可以暂时忽略。当需要真机测试时,必须配置签名。
在 DevEco Studio 中,签名缺失还会以更醒目的方式提示:构建输出窗口中,签名相关的警告行会以黄色高亮显示,IDE 顶部的运行配置区域也可能显示签名未配置的提示。
8. 模拟器部署
8.1 模拟器选择
NearPlay 项目在开发过程中使用 HarmonyOS 模拟器进行测试。根据实测结果,不同模拟器型号的兼容性存在差异:
┌────────────────────────────────────────────────────────────┐
│ 模拟器兼容性测试结果 │
├──────────────┬───────────────────┬───────────────────────────┤
│ 模拟器型号 │ 测试结果 │ 备注 │
├──────────────┼──────────────────┼───────────────────────────┤
│ Pura 90 │ ✅ 正常运行 │ 推荐使用,启动和运行稳定 │
│ Mate X7 │ ❌ 启动超时 │ 模拟器启动超时,不可用 │
└──────────────┴───────────────────┴───────────────────────────┘
Pura 90 模拟器:华为 Pura 90 是 HarmonyOS NEXT 的官方推荐模拟器型号。它模拟了华为 Pura 系列手机的硬件配置和系统行为,包括正确的屏幕尺寸(6.8 英寸)、分辨率(2844×1260)和像素密度。NearPlay 应用在 Pura 90 上运行流畅,界面布局正确,权限授权弹窗正常弹出。
Mate X7 模拟器:Mate X7 是折叠屏型号的模拟器,模拟了折叠屏设备的双屏切换行为。但在实际测试中,该模拟器启动过程经常超时,无法正常使用。超时原因可能包括:折叠屏模拟器需要模拟两块屏幕,资源消耗更大;模拟器镜像文件较大,冷启动时间更长;当前 SDK 版本对折叠屏模拟器的优化不够完善。
8.2 hdc 命令部署
hdc(HarmonyOS Device Connector)是 HarmonyOS 的设备调试工具,类似于 Android 的 adb。通过 hdc 命令可以手动部署 HAP 包到模拟器或真机。
常用 hdc 命令:
bash
# 列出连接的设备
hdc list targets
# 查看设备信息
hdc shell param get const.product.model
# 安装 HAP 包
hdc install <hap-file-path>
# 卸载应用
hdc uninstall com.example.nearplay
# 清除应用数据
hdc shell bm clean -n com.example.nearplay
# 启动应用
hdc shell aa start -a EntryAbility -b com.example.nearplay
# 停止应用
hdc shell aa force-stop com.example.nearplay
# 查看应用日志
hdc hilog | findstr NearPlay
# 文件推送到设备
hdc file send <local-path> <remote-path>
# 从设备拉取文件
hdc file recv <remote-path> <local-path>
NearPlay 的完整部署流程:
bash
# 1. 确认模拟器已启动
hdc list targets
# 输出:127.0.0.1:5555
# 2. 构建 HAP 包(在项目目录下)
hvigorw --module entry@default assembleHap
# 3. 安装 HAP 包到模拟器
hdc install build\default\outputs\entry\entry-default-signed.hap
# 4. 启动应用
hdc shell aa start -a EntryAbility -b com.example.nearplay
8.3 模拟器网络地址
模拟器在本地网络中的地址为 127.0.0.1:5555,这是 hdc 连接模拟器的默认地址和端口:
┌────────────────────────────────────────────────────────┐
│ 模拟器连接架构 │
│ │
│ 开发机 (Windows) │
│ ┌──────────────────────────────────────────┐ │
│ │ │ │
│ │ hdc 客户端 │ │
│ │ │ │ │
│ │ │ 127.0.0.1:5555 │ │
│ │ ▼ │ │
│ │ ┌─────────────────────┐ │ │
│ │ │ QEMU 模拟器进程 │ │ │
│ │ │ (HarmonyOS NEXT) │ │ │
│ │ │ │ │ │
│ │ │ NearPlay 应用 │ │ │
│ │ │ 运行在虚拟设备中 │ │ │
│ │ └──────────────────────┘ │ │
│ │ │ │
│ └──────────────────────────────────────────┘ │
└────────────────────────────────────────────────────────┘
127.0.0.1:本地回环地址,模拟器与开发机在同一主机上5555:hdc 监听的默认端口号。如果同时运行多个模拟器实例,端口号会递增(5555、5556、5557...)
当 hdc list targets 输出 127.0.0.1:5555 时,表示模拟器已正常启动并建立了连接。如果输出为空或连接失败,需要检查模拟器是否已启动、hdc 服务是否正常运行。
多设备场景下的指定安装:
bash
# 当有多个设备连接时,使用 -t 参数指定目标
hdc -t 127.0.0.1:5555 install entry-default-signed.hap
9. 常见构建错误
9.1 签名缺失错误
错误现象:在真机上安装 HAP 包时失败
hdc install entry-default-signed.hap
# 错误:AppInstallFinishWithError: install error code: 9568348
# 原因:签名验证失败
原因分析:HAP 包使用调试签名或未签名,真机拒绝安装。
解决方案:
- 在 DevEco Studio 中配置自动签名
- 手动在
build-profile.json5中添加signingConfigs - 确保证书和 Profile 有效且未过期
- 确保调试 Profile 中包含目标设备的 UDID
9.2 Deprecated API 警告
错误现象:构建输出中显示 deprecated API 警告
> ArkTS:WARN Unexpected usage of deprecated API.
'PhotoViewPicker' is deprecated.
Recommended alternative: 'photoAccessHelper.PhotoViewPicker'
File: entry/src/main/ets/pages/Index.ets:42:5
> ArkTS:WARN Unexpected usage of deprecated API.
'getContext' is deprecated.
Recommended alternative: 'this.context'
File: entry/src/main/ets/entryability/EntryAbility.ets:15:10
原因分析:代码使用了已被标记为 deprecated 的 API。HarmonyOS SDK 版本迭代过程中,部分 API 会被标记为废弃并推荐使用新的替代 API。
NearPlay 中的具体问题:
-
PhotoViewPicker 废弃 :旧版的
PhotoViewPickerAPI 已废弃,应使用@kit.PhotoAccessHelper模块中的新 API。新 API 提供了更好的权限管控和更清晰的接口设计。 -
getContext 废弃 :全局的
getContext()函数已废弃,应使用 Ability 实例的this.context属性获取上下文。这是因为全局 getContext 在多 Ability 场景下可能返回错误的上下文。
解决方案:
typescript
// 旧写法(deprecated)
const context = getContext(this);
// 新写法
const context = this.context;
typescript
// 旧写法(deprecated)
const picker = new PhotoViewPicker();
// 新写法
import { photoAccessHelper } from '@kit.PhotoAccessHelper';
const picker = new photoAccessHelper.PhotoViewPicker();
9.3 ArkTS Linter 错误
错误现象:编译失败,输出 arkts-linter 规则错误
> ArkTS:ERROR arkts-no-standalone-this
'this' is not allowed in standalone function.
File: entry/src/main/ets/utils/Helper.ets:25:10
> ArkTS:ERROR arkts-no-obj-literals-as-types
Object literal cannot be used as type annotation.
File: entry/src/main/ets/model/Data.ets:8:15
> ArkTS:ERROR arkts-no-any-unknown
The 'any' or 'unknown' type is not allowed.
File: entry/src/main/ets/services/Api.ets:30:5
原因分析:ArkTS 是 TypeScript 的严格子集,禁用了许多 TypeScript 中允许的动态特性。这些限制是为了确保编译时的类型安全,避免运行时类型错误。
常见 arkts-linter 规则和修复:
| 规则 | 描述 | 修复方法 |
|---|---|---|
arkts-no-standalone-this |
独立函数中禁止使用 this | 改用类方法或箭头函数 |
arkts-no-obj-literals-as-types |
禁止用对象字面量作为类型 | 使用 interface 或 class |
arkts-no-any-unknown |
禁止 any/unknown 类型 | 使用具体类型 |
arkts-no-as-const |
禁止 as const 断言 | 使用显式类型声明 |
arkts-no-enum-trailing-comma |
枚举末尾禁止逗号 | 移除尾逗号 |
arkts-no-spread-operator |
限制展开运算符 | 使用显式赋值 |
9.4 oh_modules 缺失错误
错误现象:编译失败,找不到依赖模块
> Error: Cannot find module '@ohos/xxx' or its corresponding type declarations.
File: entry/src/main/ets/services/Service.ets:3:1
原因分析:oh_modules 目录中没有安装所需的依赖包。这可能是因为:
- 从版本库拉取代码后未执行
ohpm install - 依赖声明(oh-package.json5)与实际安装的版本不一致
- ohpm 源配置错误或网络问题导致下载失败
- oh_modules 目录被意外删除
解决方案:
bash
# 清理并重新安装依赖
ohpm install
# 如果 ohpm 源有问题,检查配置
ohpm config get registry
# 清理缓存后重试
ohpm cache clean
ohpm install
预防措施:
- 将
oh_modules加入.gitignore,避免提交到版本库 - 在项目根目录的 README 或 AGENTS.md 中记录依赖安装步骤
- 锁定依赖版本,避免使用
^或~前缀导致版本漂移 - CI/CD 流程中在构建前自动执行
ohpm install
9.5 其他常见构建错误
SDK 版本不匹配:
> Error: CompileSdkVersion 60101024 is not found.
原因:本机安装的 SDK 版本低于项目要求的版本。需要通过 DevEco Studio 的 SDK Manager 下载对应版本的 SDK。
资源引用错误:
> Error: Resource $string:xxx not found.
原因:string.json 中缺少对应名称的字符串资源。检查资源文件中是否定义了 module.json5 引用的所有资源。
构建超时:
> hvigor BUILD FAILED in 300 s
> Timeout waiting for daemon response.
原因:daemon 进程卡死或系统资源不足。尝试停止 daemon 后重新构建:hvigorw --stop-daemon && hvigorw assembleHap。
10. hvigor 缓存与清理
10.1 缓存机制
hvigor 的缓存分为三个层级:
┌────────────────────────────────────────────────────────────┐
│ hvigor 缓存层级 │
│ │
│ ┌────────────────────────────────────────────────────┐ │
│ │ Level 1:任务级增量缓存 │ │
│ │ 位置:build/ 目录下各模块的 .hvigor/ 子目录 │ │
│ │ 内容:任务输入输出的哈希映射 │ │
│ │ 作用:跳过未变化的任务 │ │
│ └───────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌───────────────────────────────────────────────────┐ │
│ │ Level 2:项目级构建缓存 │ │
│ │ 位置:.hvigor/ 目录(项目根目录下) │ │
│ │ 内容:oh_modules 解析结果、模块依赖图 │ │
│ │ 作用:加速配置解析阶段 │ │
│ └───────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌───────────────────────────────────────────────────┐ │
│ │ Level 3:全局缓存 │ │
│ │ 位置:用户目录 .hvigor/ │ │
│ │ 内容:daemon 状态、全局配置 │ │
│ │ 作用:跨项目共享编译缓存 │ │
│ └────────────────────────────────────────────────────┘ │
└────────────────────────────────────────────────────────────┘
10.2 clean 命令
hvigorw clean 命令清理构建产物,等同于删除 build/ 目录:
bash
# 清理所有模块的构建产物
hvigorw clean
# 清理指定模块
hvigorw --module entry clean
clean 命令删除的内容包括:
build/default/目录下的所有编译输出(abc 文件、resources.index、HAP 包等)- 任务级增量缓存的哈希映射
- 但不会删除 oh_modules(依赖包)和 .hvigor/(项目级缓存)
何时需要 clean:
- 增量构建结果不正确(缓存污染)
- 构建报错但代码无问题(构建状态不一致)
- 切换 SDK 版本后需要全量重建
- 修改了构建配置(build-profile.json5、module.json5)后,增量构建未反映变更
10.3 --no-daemon 选项
--no-daemon 选项禁用 hvigor 守护进程,所有构建操作在前台进程中执行:
bash
hvigorw --no-daemon assembleHap
适用场景:
- CI/CD 环境 :自动化构建中不需要常驻的 daemon 进程,使用
--no-daemon避免进程残留 - daemon 故障排查 :当 daemon 行为异常(如卡死、响应超时)时,使用
--no-daemon绕过 daemon - 资源受限环境:daemon 占用一定内存,在内存紧张的环境中可以关闭以释放资源
性能影响:不使用 daemon 时,每次构建都需要重新启动 Node.js 运行时和加载 hvigor 插件,增加约 2-5 秒的冷启动时间。对于频繁构建的开发场景,建议使用 daemon。
daemon 管理命令:
bash
# 查看 daemon 状态
hvigorw --daemon-status
# 停止 daemon
hvigorw --stop-daemon
# 强制重启 daemon(先停止再自动启动)
hvigorw --stop-daemon && hvigorw assembleHap
本文档基于 NearPlay 项目实际配置编写,适用于 HarmonyOS NEXT SDK 6.1.1(API 24)版本。随着 SDK 版本迭代,部分配置和流程可能有变化,请参考最新的官方文档。
11. 构建配置与持续集成展望
11.1 CI/CD流水线设计
NearPlay当前的构建流程完全依赖开发者手动在DevEco Studio中点击构建按钮。未来接入持续集成后,每次代码提交自动触发构建和测试流程:代码拉取→依赖安装(ohpm install)→静态检查(arkts_check)→编译构建(hvigorw assembleHap)→单元测试→HAP包归档。构建失败时自动通知提交者,构建成功时自动部署到测试设备。这套流水线将构建质量检查从人工操作转变为自动化保障,减少"本地能跑但别人拉下来跑不了"的问题。
11.2 多构建变体管理
NearPlay当前只有debug构建模式。未来可能需要release模式(代码混淆、资源压缩、性能优化)和test模式(内置测试数据、调试日志全开)。不同模式的构建产物用途不同:debug用于开发调试,release用于应用市场上架,test用于自动化测试。build-profile.json5的buildModeSet字段已经预留了多模式配置的能力,只需要添加新的模式定义并配置对应的编译选项。
11.3 构建缓存与团队协作
hvigor的增量缓存在团队协作中可能带来问题------开发者A修改了代码但缓存未失效,构建出错误的HAP包推送给测试人员。建议在团队规范中约定:每天早上首次构建使用clean全量重建,日常修改使用增量构建;构建失败时先尝试clean再重试;发布测试版本前必须clean全量重建。这些规范确保了构建产物的可靠性,避免缓存污染导致的难以排查的问题。