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 资源限定词匹配规则

系统匹配资源时,会按照以下优先级:

  1. 精确匹配: 比如语言、地区、屏幕密度都完全匹配。
  2. 模糊匹配: 比如只匹配语言,不匹配地区。
  3. 默认匹配: 使用 base/ 目录下的资源。

举个例子:如果设备是中文(简体)、深色模式、高密度屏幕,系统会优先找 zh_CN-dark-hdpi/ 目录。如果没有,就找 zh_CN-dark/,再没有就找 zh_CN/,最后才用 base/

核心原则: 把通用资源放 base/,把特定场景的资源放限定词目录。这样既保证了兼容性,又实现了个性化。

3.4 知识体系结构图

下面这张图,帮你理清本章的知识脉络:

项目结构解析知识体系 工程目录结构 配置文件解读 资源管理 entry 主模块 feature 功能模块 library 公共库模块 build-profile.json5 module.json5 详解 abilities 配置 pages 路由配置 deviceTypes 设备类型 base 基础资源 限定词资源(语言/主题) 资源引用方式 匹配优先级规则 核心要点 目录结构是骨架,配置文件是灵魂,资源管理是血肉 三者结合,才能构建出健壮的 HarmonyOS 应用

3.5 避坑总结

最后,分享几个我踩过的坑:

  • 资源路径错误: 图片一定要放在 resources/base/media/ 下,别放 ets 目录。
  • 配置文件遗漏: 新增页面后,记得在 main_pages.json 里注册,否则路由找不到。
  • 权限声明: 如果需要网络、定位等权限,必须在 module.json5requestPermissions 里声明。
  • 模块类型混淆: entry 模块只能有一个,feature 模块可以有多个。别搞反了。

我的建议: 刚开始学的时候,别急着改目录结构。先用默认的 entry 模块跑通一个页面,再慢慢拆。一口吃不成胖子,对吧?

好了,项目结构这块就聊到这儿。记住:目录结构是骨架,配置文件是灵魂,资源管理是血肉。把这三样搞明白了,后面的开发就会顺畅很多。


公众号:蓝海资料掘金营,微信deep3321