3. 项目结构解析:工程目录结构详解、配置文件解读、资源管理
好,咱们直接进入正题。当你用 DevEco Studio 新建一个 HarmonyOS 项目后,第一眼看到的就是那一堆文件夹和文件。说实话,我刚开始接触那会儿,也被这目录结构搞得有点懵。但别怕,这东西就像你家的抽屉——分门别类放好了,用起来才顺手。
3.1 工程目录结构详解
一个标准的 HarmonyOS 项目,顶层目录大概长这样:
MyApplication/
├── entry/ # 应用的主模块(类似 Android 的 app module)
│ ├── src/
│ │ ├── main/
│ │ │ ├── ets/ # 源码目录(ArkTS 文件)
│ │ │ ├── resources/ # 资源文件
│ │ │ └── module.json5 # 模块配置文件
│ │ └── ohosTest/ # 测试代码
│ ├── build/ # 构建产物(不用管它)
│ └── oh-package.json5 # 模块级依赖配置
├── feature/ # 其他功能模块(可选)
├── library/ # 公共库模块(可选)
├── build-profile.json5 # 项目级构建配置
├── hvigor/ # 构建工具配置
├── local.properties # 本地 SDK 路径
└── oh-package.json5 # 项目级依赖配置
嗯,这里要注意:entry 是默认的主模块,你大部分代码都写在这里。我个人习惯把业务逻辑拆成多个模块,比如 feature/ 放首页、详情页,library/ 放网络请求、工具类。这样项目大了以后,编译速度会快很多——你想想看,改一个模块只需要重新编译它自己。
核心目录说明:
entry/src/main/ets/:你的 ArkTS 源码都在这里。页面、组件、服务,统统往里放。entry/src/main/resources/:图片、字符串、颜色、布局等资源文件。entry/src/main/module.json5:这个模块的身份证,声明了权限、页面路由、元数据等。
我记得有一次,同事把图片直接扔到了 ets 目录下,结果死活引用不到。后来才发现——资源必须放在 resources 目录里,这是硬性规定。
3.2 配置文件解读
配置文件有两个层级:项目级和模块级。咱们重点看模块级的 module.json5,因为它直接决定了你的应用怎么跑。
3.2.1 module.json5 深度解析
打开 entry/src/main/module.json5,你会看到类似这样的内容:
{
"module": {
"name": "entry",
"type": "entry",
"description": "$string:module_desc",
"mainElement": "MainAbility",
"deviceTypes": ["phone", "tablet"],
"deliveryWithInstall": true,
"installationFree": false,
"pages": "$profile:main_pages",
"abilities": [
{
"name": "MainAbility",
"srcEntry": "./ets/MainAbility/MainAbility.ets",
"description": "$string:MainAbility_desc",
"icon": "$media:icon",
"label": "$string:MainAbility_label",
"startWindowIcon": "$media:icon",
"startWindowBackground": "$color:start_window_background",
"visible": true,
"skills": [
{
"actions": ["action.system.home"],
"entities": ["entity.system.home"]
}
]
}
]
}
}
咱们挑几个重点字段说说:
| 字段 | 说明 | 避坑指南 |
|---|---|---|
type |
模块类型:entry(主模块)、feature(功能模块)、har(静态共享包) | 我曾经把 feature 模块设成了 entry,结果应用安装后找不到入口页面…… |
deviceTypes |
支持的设备类型,比如 phone、tablet、tv、wearable | 如果你只写了 phone,那在平板上就装不了。别问我怎么知道的。 |
abilities |
Ability 列表,每个 Ability 相当于一个页面或服务 | 记得给入口 Ability 加上 skills 字段,否则桌面看不到图标。 |
pages |
页面路由配置文件的引用,通常指向 $profile:main_pages |
这个文件在 resources/base/profile/ 下,别放错位置。 |
小技巧: 配置里的 $string:xxx、$media:xxx 这种写法,是引用 resources 目录下的资源。好处是——国际化时只需要改资源文件,不用动代码。我所有项目都这么干。
3.2.2 页面路由配置
在 resources/base/profile/main_pages.json 里,定义了所有页面的路由:
{
"src": [
"pages/Index",
"pages/Detail",
"pages/About"
]
}
说白了,这就是你的页面清单。每个页面对应一个 .ets 文件,路径相对于 ets/ 目录。你想想看,如果没有这个清单,系统怎么知道你的应用有哪些页面?
3.3 资源管理
资源管理这块,HarmonyOS 做得挺讲究。它把资源分成了两大类:基础资源和限定词资源。
3.3.1 资源目录结构
resources/
├── base/ # 基础资源(默认)
│ ├── element/ # 字符串、颜色、数值等
│ │ ├── string.json
│ │ ├── color.json
│ │ └── float.json
│ ├── media/ # 图片、音频等
│ │ ├── icon.png
│ │ └── logo.png
│ ├── profile/ # 配置文件(如 main_pages.json)
│ └── layout/ # 布局文件(如果使用 XML 布局)
├── en_US/ # 英文(美国)限定词
│ ├── element/
│ │ └── string.json
│ └── media/
├── zh_CN/ # 中文(简体)限定词
│ ├── element/
│ │ └── string.json
│ └── media/
└── dark/ # 深色模式限定词
├── element/
│ └── color.json
└── media/
嗯,这里有个关键点:限定词目录的优先级。系统会根据当前设备的语言、屏幕密度、深色模式等,自动选择最匹配的资源。比如你在 zh_CN/ 里放了中文,在 en_US/ 里放了英文,那中国用户看到的就是中文。
注意: 限定词目录的命名有严格规范。比如 zh_CN 表示语言为中文、地区为中国。如果你写成了 zh-cn(小写+短横线),系统会直接忽略。我曾经因为这个 bug 排查了半天……
3.3.2 资源引用方式
在代码里引用资源,有两种方式:
- 在 JSON/JS 中: 使用
$string:app_name、$color:primary、$media:icon这种格式。 - 在 ArkTS 代码中: 使用
this.context.resourceManager.getStringSync($r('app.string.app_name'))。
我个人更推荐用 $r() 语法,因为它更简洁:
// 获取字符串
let appName = this.context.resourceManager.getStringSync($r('app.string.app_name'));
// 获取颜色
let primaryColor = this.context.resourceManager.getColorSync($r('app.color.primary'));
// 获取图片
Image($r('app.media.icon'))
你想想看,如果硬编码字符串,国际化时得改多少地方?用资源引用,改一个文件就够了。
3.3.3 资源限定词匹配规则
系统匹配资源时,会按照以下优先级:
- 精确匹配: 比如语言、地区、屏幕密度都完全匹配。
- 模糊匹配: 比如只匹配语言,不匹配地区。
- 默认匹配: 使用
base/目录下的资源。
举个例子:如果设备是中文(简体)、深色模式、高密度屏幕,系统会优先找 zh_CN-dark-hdpi/ 目录。如果没有,就找 zh_CN-dark/,再没有就找 zh_CN/,最后才用 base/。
核心原则: 把通用资源放 base/,把特定场景的资源放限定词目录。这样既保证了兼容性,又实现了个性化。
3.4 知识体系结构图
下面这张图,帮你理清本章的知识脉络:
3.5 避坑总结
最后,分享几个我踩过的坑:
- 资源路径错误: 图片一定要放在
resources/base/media/下,别放 ets 目录。 - 配置文件遗漏: 新增页面后,记得在
main_pages.json里注册,否则路由找不到。 - 权限声明: 如果需要网络、定位等权限,必须在
module.json5的requestPermissions里声明。 - 模块类型混淆: entry 模块只能有一个,feature 模块可以有多个。别搞反了。
我的建议: 刚开始学的时候,别急着改目录结构。先用默认的 entry 模块跑通一个页面,再慢慢拆。一口吃不成胖子,对吧?
好了,项目结构这块就聊到这儿。记住:目录结构是骨架,配置文件是灵魂,资源管理是血肉。把这三样搞明白了,后面的开发就会顺畅很多。
公众号:蓝海资料掘金营,微信deep3321