3、项目结构对比:安卓Gradle项目 vs 鸿蒙HAP项目,模块化与多工程管理,资源文件组织方式

说实话,我刚从安卓转到鸿蒙时,第一反应是:这项目结构怎么这么眼熟?但仔细一挖,发现坑还挺多。今天我就把这两套体系掰开揉碎了讲,顺便聊聊我踩过的那些坑。

3.1 整体骨架:Gradle项目 vs HAP项目

安卓用 Gradle 构建,这大家都知道。一个典型项目长这样:

MyAndroidApp/
├── app/
│   ├── build.gradle
│   └── src/
├── library/
│   ├── build.gradle
│   └── src/
├── settings.gradle
└── build.gradle

鸿蒙这边呢?用的是自家的 HAP 包结构。说白了,HAP 就是鸿蒙的应用包,类似安卓的 APK。但组织方式不太一样:

MyHarmonyApp/
├── entry/
│   ├── build-profile.json5
│   └── src/
├── library/
│   ├── build-profile.json5
│   └── src/
├── build-profile.json5
└── oh-package.json5

嗯,这里要注意:鸿蒙没有 Gradle,用的是自家的构建系统。配置文件从 .gradle 变成了 .json5。我个人习惯把 build-profile.json5 看作鸿蒙版的 build.gradle,这样理解起来轻松很多。

核心差异一句话:安卓用 Groovy/Kotlin DSL 写构建脚本,鸿蒙用 JSON5 写配置。前者灵活但复杂,后者简洁但约束多。

3.2 模块化:多 Module vs 多 HAP

安卓里我们经常搞多 Module 工程,比如:

  • app - 主模块
  • common - 公共库
  • feature_home - 首页模块
  • feature_login - 登录模块

鸿蒙这边呢?叫多 HAP 工程。每个 HAP 就是一个独立的功能单元。我记得第一次迁移时,直接把安卓的 Module 结构照搬过来,结果编译报错——鸿蒙对 HAP 之间的依赖关系有严格限制。

为什么会这样?因为鸿蒙的 HAP 分为两种:

类型 说明 安卓类比
Entry HAP 应用入口,必须有一个 app Module
Feature HAP 功能模块,按需加载 feature Module
Shared HAP 共享库,被其他 HAP 引用 library Module

你想想看,安卓里 Module 之间可以随便互相依赖,但鸿蒙里 Entry HAP 不能依赖 Feature HAP,只能反过来。这个限制我当初折腾了一下午才搞明白。

我的建议:迁移时先把安卓的 Module 依赖图画出来,然后按鸿蒙的规则重新组织。别硬搬,否则后面改起来很痛苦。

3.3 多工程管理:Gradle Composite Build vs 鸿蒙多工程

大项目里,安卓会用 Composite Build 来管理多个独立工程。鸿蒙也有类似机制,叫多工程管理。

安卓的做法:

// settings.gradle
includeBuild('../shared-library')
includeBuild('../network-library')

鸿蒙的做法:

// build-profile.json5
{
  "app": {
    "products": ["phone", "tablet"]
  },
  "modules": [
    {
      "name": "entry",
      "srcPath": "./entry"
    },
    {
      "name": "shared",
      "srcPath": "../shared-library"
    }
  ]
}

我个人觉得鸿蒙的多工程管理更直观一些。你直接在 build-profile.json5 里列出所有模块的路径就行,不用像 Gradle 那样搞一堆 settings.gradleincludeBuild

不过要注意:鸿蒙的多工程要求所有模块在同一个 oh-package.json5 的命名空间下。我曾经把两个不同团队的模块硬凑到一起,结果包名冲突,编译直接挂了。

避坑指南:我曾经因为没统一包名,导致 Feature HAP 引用 Shared HAP 时一直报找不到类。检查了半天才发现是 oh-package.json5 里的 name 字段写错了。记住:所有模块的 name 必须唯一,且遵循反向域名规则。

3.4 资源文件组织:res vs resources

这是迁移中最容易出问题的地方。安卓的资源在 res/ 目录下,鸿蒙的在 resources/ 目录下。名字像,但结构完全不同。

安卓的资源结构:

res/
├── drawable/
├── layout/
├── values/
│   ├── strings.xml
│   └── colors.xml
├── mipmap/
└── raw/

鸿蒙的资源结构:

resources/
├── base/
│   ├── element/
│   │   ├── string.json
│   │   └── color.json
│   ├── media/
│   └── profile/
├── en_US/
│   └── element/
│       └── string.json
└── zh_CN/
    └── element/
        └── string.json

嗯,这里有个关键区别:鸿蒙把资源按「用途」和「语言」双重维度组织。base/ 是默认资源,en_US/zh_CN/ 是国际化资源。安卓是把国际化资源放在 values-en/values-zh/ 这样的目录里。

说白了,鸿蒙的资源组织更「工程化」一些。你想想看,安卓的 drawable-hdpidrawable-xhdpi 这种目录,是不是很烦?鸿蒙直接按 media/ 统一管理,系统自动适配。

迁移要点:

  • 布局文件:安卓的 .xml 布局 → 鸿蒙的 .hml.ets 布局
  • 图片资源:安卓的 drawable/ → 鸿蒙的 resources/base/media/
  • 字符串:安卓的 strings.xml → 鸿蒙的 string.json
  • 颜色:安卓的 colors.xml → 鸿蒙的 color.json

我记得有一次迁移一个老项目,里面用了大量 selectorshape 资源。鸿蒙没有这些概念,得用代码实现。那两天我几乎都在写状态管理逻辑,头都大了。

3.5 知识体系总览

下面这张图是我自己总结的,帮你快速建立整体认知:

安卓 vs 鸿蒙:项目结构对比全景图 安卓 Gradle 项目 构建系统:Gradle (Groovy/Kotlin DSL) 模块化:多 Module (app, library, feature) 多工程:Composite Build 资源:res/ (drawable, layout, values) 鸿蒙 HAP 项目 构建系统:自家构建 (JSON5配置) 模块化:多 HAP (Entry, Feature, Shared) 多工程:多工程管理 (统一命名空间) 资源:resources/ (base, 语言目录) 核心差异:构建脚本语言、模块依赖规则、资源组织维度

这张图把四个核心维度都列出来了。你对照着看,迁移时心里就有底了。

3.6 迁移实战建议

最后,我总结几条实战经验:

  1. 先理清模块依赖:把安卓的 Module 依赖图画出来,再按鸿蒙的规则重新设计。别偷懒,这一步省不了。
  2. 资源文件分批迁移:先迁移字符串和颜色,再迁移布局和图片。每迁移一批就编译一次,别攒到最后一起搞。
  3. 注意包名一致性:所有 HAP 的 oh-package.json5 里的 name 必须统一命名空间,否则编译报错。
  4. 善用工具:鸿蒙 DevEco Studio 有资源迁移向导,能帮你把安卓的 res/ 转成鸿蒙的 resources/。虽然不能 100% 自动完成,但能省不少事。

小技巧:如果你项目里有大量 selector 资源,建议写个脚本批量转换。我当初手动改了一百多个文件,手都酸了。后来写了个 Python 脚本,十分钟搞定。

好了,项目结构这块就聊到这儿。记住一句话:结构是骨架,搞清楚了骨架,后面的血肉(代码逻辑)才能长对地方。

专注资料整理