如果你只把 HarmonyOS 的工具链当成“把 Gradle 换成另一套命令”,很快就会踩到两个坑:
1) 依赖说不清:同一个三方库,在 Android 里你知道它来自 Maven Central / Google Maven;在 HarmonyOS 里你会突然面对 ohpm/DevEco 生态入口、包形态(HAP/HAR/HSP)、以及“有没有对应库”这种现实问题。 2) 构建不稳定:本地能跑、CI 跑不起来;或者能打包但无法解释“这份产物到底对应哪份依赖版本”,后续排查像黑盒。
先不急着背工具名,从最常见的依赖声明看起。能看懂依赖写在哪里、从哪里拉、版本怎么固定,后面再看 Gradle task、AGP、hvigor task 和产物形态,就不会被一堆新名词带偏。
先看依赖写法:Android 和 HarmonyOS 长什么样
Android 里常说的“Gradle 依赖”和“Maven 依赖”不是同一层东西:
- Gradle 是构建系统,负责读取脚本、解析依赖、组织任务、调用 Android Gradle Plugin 打包。
- Maven 仓库 是依赖来源和坐标体系,常见坐标长这样:
group:name:version。 - AGP 是 Android Gradle Plugin,把 Android 编译、资源处理、打包、签名等能力接到 Gradle 里。
先看一个 Android 工程里最常见的几个构建文件位置:
android-demo/
├── settings.gradle.kts # 仓库源、插件源、模块 include
├── build.gradle.kts # 根工程公共配置
├── gradle/
│ └── libs.versions.toml # 可选:集中管理依赖版本
├── gradlew # Gradle Wrapper,固定团队使用的 Gradle 入口
└── app/
├── build.gradle.kts # app 模块自己的插件、android 配置、dependencies
└── src/main/AndroidManifest.xml
平时新增一个三方库,最常改的是 app/build.gradle.kts 里的 dependencies。如果要改依赖从哪里下载,看 settings.gradle.kts。如果团队把版本集中管理,再看 gradle/libs.versions.toml。
一个最普通的 Android app module 依赖通常写在 app/build.gradle.kts:
plugins {
id("com.android.application")
id("org.jetbrains.kotlin.android")
}
android {
namespace = "fun.codehubble.demo"
compileSdk = 36
defaultConfig {
applicationId = "fun.codehubble.demo"
minSdk = 23
targetSdk = 36
versionCode = 1
versionName = "1.0"
}
}
dependencies {
implementation("androidx.core:core-ktx:1.17.0")
implementation("com.squareup.okhttp3:okhttp:4.12.0")
testImplementation("junit:junit:4.13.2")
}
如果项目还在用 Groovy DSL,同一段依赖声明会长这样:
dependencies {
implementation 'androidx.core:core-ktx:1.17.0'
implementation 'com.squareup.okhttp3:okhttp:4.12.0'
testImplementation 'junit:junit:4.13.2'
}
这里的 androidx.core:core-ktx:1.17.0 和 com.squareup.okhttp3:okhttp:4.12.0 就是 Maven 坐标。可以先把它看成三段式地址:
androidx.core : core-ktx : 1.17.0
group : artifact : version
group:库所属的组织或命名空间,比如androidx.core。artifact:具体库名,比如core-ktx。version:要使用的版本,比如1.17.0。
implementation("androidx.core:core-ktx:1.17.0") 的意思就是:这个模块编译和运行时需要 androidx.core 组织下的 core-ktx 这个库,版本固定为 1.17.0。Gradle 看到这个坐标之后,会去 settings.gradle.kts 里配置的 Maven 仓库找包:
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
google()
mavenCentral()
}
}
多模块项目里,不建议把版本散落在每个 module。常见做法是把版本集中到 gradle/libs.versions.toml:
[versions]
coreKtx = "1.17.0"
okhttp = "4.12.0"
[libraries]
androidx-core-ktx = { module = "androidx.core:core-ktx", version.ref = "coreKtx" }
okhttp = { module = "com.squareup.okhttp3:okhttp", version.ref = "okhttp" }
然后在 module 里引用别名:
dependencies {
implementation(libs.androidx.core.ktx)
implementation(libs.okhttp)
}
HarmonyOS 这边要先把两个角色分开:
- ohpm 更接近包管理器,负责读取
oh-package.json5、安装依赖、处理本地包/远程包。 - hvigor 是构建编排工具,项目构建入口通常在
hvigorfile.ts,实际打包能力由 HarmonyOS/DevEco 工程插件接入。
再看 HarmonyOS Samples 这种多模块工程的目录形态:
harmonyos-demo/
├── hvigorfile.ts # 工程级构建任务入口
├── build-profile.json5 # 工程构建配置、产品/模块配置
├── oh-package.json5 # 工程级 ohpm 配置、开发期依赖、版本参数文件
├── VersionFile.json5 # 示例工程中用于集中放版本参数
├── products/
│ └── phone/
│ ├── oh-package.json5 # phone 产品模块依赖:本地 feature/common 模块
│ └── build-profile.json5
├── features/
│ └── commonbusiness/
│ └── oh-package.json5 # feature 模块依赖:例如 file:../../common
└── common/
└── oh-package.json5 # 公共模块依赖:例如 @ohos/imageknife
所以 HarmonyOS 里找依赖,不能只盯着根目录。根目录 oh-package.json5 可能放开发期依赖和版本参数;产品模块、feature 模块、公共模块也可以各自有 oh-package.json5,声明自己需要的远程包或本地模块。
在 HarmonyOS Samples 里,工程根目录的 oh-package.json5 可以集中声明开发期依赖,并通过 parameterFile 把版本放到单独文件:
{
"modelVersion": "5.0.0",
"dependencies": {},
"devDependencies": {
"@ohos/hypium": "@param:dependencies.hypium-version",
"@ohos/hamock": "@param:dependencies.hamock-version",
},
"parameterFile": "VersionFile.json5",
"dynamicDependencies": {}
}
业务模块自己的 oh-package.json5 会声明模块名、入口和依赖。例如公共模块依赖图片库:
{
"name": "@ohos/common",
"version": "1.0.0",
"main": "Index.ets",
"dependencies": {
"@ohos/imageknife": "@param:dependencies.imageknife-version",
}
}
同一个工程里的模块依赖,则经常用 file: 指向本地模块:
{
"name": "@ohos/commonbusiness",
"version": "1.0.0",
"main": "Index.ets",
"dependencies": {
"@ohos/common": "file:../../common"
}
}
再看构建入口,HarmonyOS Samples 根目录的 hvigorfile.ts 很薄:
import { appTasks } from '@ohos/hvigor-ohos-plugin';
export default {
system: appTasks,
plugins: []
}
这说明迁移时不要把 oh-package.json5 和 hvigorfile.ts 混成一个东西。依赖版本、包来源、本地模块关系主要看各级 oh-package.json5 / ohpm;构建任务、插件接入、打包流程再看 hvigorfile.ts 和相关 build profile。
再把目标说清楚:什么叫“可复现构建”
我在这里用一个工程化、但足够入门的定义:
> 给定同一份源码、同一组依赖版本声明、同一套构建配置,在不同机器(本地/CI)上构建出来的产物在功能与依赖组成上应尽可能一致,并且能追溯。
这会直接落到你每天真的会遇到的几件事:
- 依赖来自哪里?(registry / 仓库源)
- 依赖版本如何被锁定?(lockfile / BOM / version catalog)
- 构建任务如何被组织与复用?(task graph / script / plugin)
- 产物是什么形态?(APK/AAB/AAR vs HAP/HAR/HSP)
- 发布/合规如何更早暴露?(IDE 提示、Policy/SDK 风险、签名与提交链路)
迁移时最常见的 5 个问题
很多迁移问题看起来像“工具链差异”,本质是“治理目标没对齐”。下面这 5 个问题我自己最常遇到,也最建议团队先把问法升级一下。
1) “这个库在 HarmonyOS 有没有?” 更稳的问法:这类能力(网络/图片/存储/加密/日志)在 HarmonyOS 侧是优先找系统能力、官方生态库,还是自己封装一层再替换实现?
2) “依赖版本怎么锁?” 更稳的问法:我们需要可追溯到什么程度:只锁主依赖,还是要锁 transitive 依赖?发生线上问题时,能不能快速还原那次构建的依赖集合?
3) “CI 上怎么保证一致?” 更稳的问法:哪些输入必须固定(工具版本、依赖源、缓存策略、构建脚本)?哪些输出必须可追溯(产物、依赖清单、签名信息)?
4) “Gradle 里那套插件体系怎么办?” 更稳的问法:你真正依赖的不是插件本身,而是插件提供的能力(代码生成、静态检查、打包、资源处理、发布流程);把能力列清单,迁移路径会更清晰。
5) “发布与合规怎么做?” 更稳的问法:我们的发布流程里有哪些安全/合规风险点?能不能把它们提前到开发期可见(IDE 提示/依赖风险/签名与密钥管理/提交历史可追溯)?
一张对照表:Gradle/AGP 与 hvigor/ohpm 的“最小心智模型”
前面看过代码后,再回到这张表会更清楚:迁移不是给每个 Android 文件找一个 HarmonyOS 同名文件,而是把职责层级重新对齐。
| 关注点 | Android(Gradle/AGP)通常怎么做 | HarmonyOS(hvigor/ohpm)通常怎么做 | 迁移时的关键提醒 |
|---|---|---|---|
| 工具链入口 | Android Studio + Gradle Wrapper + AGP | DevEco Studio + hvigor 构建脚本 | 不要只找“等价命令”,先确认入口文件与构建配置放在哪里 |
| 依赖声明 | dependencies { ... },通常写在 module 的 build.gradle(.kts) |
oh-package.json5,可以出现在工程根目录或模块目录 |
先把远程依赖、本地模块依赖、开发期依赖分清 |
| 依赖坐标 | Maven 坐标:group:name:version |
ohpm 包名与版本,或 file: 本地路径 |
Android 里的“Gradle 写法”和“Maven 坐标”要分层理解 |
| 依赖来源 | google() / mavenCentral() / 私有 Maven 仓库 |
DevEco Service / OHPM Center / ohpm registry / 本地 HAR | 先对齐 registry/生态入口,再谈 lock 与离线缓存 |
| 版本集中管理 | version catalog / BOM / constraints | parameterFile、包版本声明、团队约定的 ohpm 版本策略 |
迁移时先问“团队想锁到什么粒度”:主依赖、传递依赖,还是整份依赖清单 |
| 构建任务 | Gradle task graph(assemble / test / lint 等) |
hvigor task(由工程插件和脚本组织) | 对照的是“任务编排方式”,不是某个 task 的名字 |
| 产物形态 | APK / AAB / AAR | HAP / HAR / HSP | 产物差异会反过来影响模块拆分策略(复用/发布/签名) |
| 风险与合规前置 | Studio/Play 生态把风险前置到 IDE、构建、发布链路 | 更多依赖 DevEco 生态入口、ohpm 依赖治理与项目配置约束 | 团队要明确哪些风险在开发期失败,哪些风险到发布期检查 |
一个“可复现构建”检查清单:迁移时可以直接落地
如果想让迁移变成一次真正的工程治理,可以把下面的 checklist 当作最小落地单元(每条都能拆成一个小任务):
- 依赖来源:列出所有依赖源(官方/三方/私有),明确谁负责维护可信来源与镜像策略。
- 版本策略:确定锁版本策略(锁到模块/锁到分库/锁到全部传递依赖),并约定升级窗口与回滚方式。
- 构建输入固定:固定工具版本(wrapper/构建脚本版本)与关键配置,避免“同代码不同机器不同结果”。
- 构建输出可追溯:产出依赖清单与构建元信息(版本号、构建号、提交 hash),确保问题可还原。
- 风险前置:把依赖/合规风险在开发期暴露(IDE 或流水线早期阶段失败),减少发布期返工。
这份清单的价值在于:你可以先在 Android 侧把它跑通(因为生态更成熟),再把同一份清单迁到 HarmonyOS 工程上。对比不是为了证明谁更好,而是为了让迁移更可控。
参考素材(精选)
- Android Developers Blog:Making it easier and faster to build and publish safer apps(2026-05-06):https://android-developers.googleblog.com/2026/05/making-it-easier-to-build-publish-safer-apps.html
- Android Developers:Gradle dependency resolution:https://developer.android.com/build/gradle-dependency-resolution
- Android Developers:Manage remote repositories:https://developer.android.com/build/remote-repositories
- Android Developers:Add build dependencies:https://developer.android.com/build/dependencies
- DevEco Service(OHPM Center / 生态入口):https://developer.huawei.com/consumer/cn/deveco-service/
- HarmonyOS Guides:oh-package.json5:https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/ide-oh-package-json5
- HarmonyOS Guides:添加依赖项:https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/ide-hvigor-dependencies
- HarmonyOS Guides:三方依赖管理工具(ohpm):https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/ide-ohpm-cli
- ohpm(OpenHarmony 包管理器仓库):https://gitee.com/openharmony-tpc/ohpm
- HarmonyOS Samples:sample_in_harmonyos:https://gitcode.com/HarmonyOS_Samples/sample_in_harmonyos
// Kai@CodeHubble // 观测坐标:Android-HarmonyOS/2026-05-09