Appearance
10_Engineering/02 - 项目结构
1. 项目目录结构
1.1 标准项目结构
MyApplication/ # 项目根目录
├── entry/ # 主模块(Entry 模块,必须存在)
│ ├── src/
│ │ ├── main/
│ │ │ ├── ets/ # ArkTS 源代码
│ │ │ │ ├── entryability/ # EntryAbility 入口
│ │ │ │ │ └── EntryAbility.ets
│ │ │ │ ├── pages/ # 页面目录
│ │ │ │ │ ├── Index.ets # 首页(启动页)
│ │ │ │ │ └── detail/
│ │ │ │ │ └── DetailPage.ets
│ │ │ │ ├── components/ # 自定义组件
│ │ │ │ │ └── Header.ets
│ │ │ │ ├── model/ # 数据模型
│ │ │ │ │ └── User.ets
│ │ │ │ └── utils/ # 工具类
│ │ │ │ └── Format.ets
│ │ │ ├── resources/ # 资源目录
│ │ │ │ ├── base/ # 默认资源
│ │ │ │ │ ├── element/ # 字符串、颜色
│ │ │ │ │ │ └── string.json
│ │ │ │ │ ├── media/ # 图片
│ │ │ │ │ │ └── icon.png
│ │ │ │ │ └── profile/ # 配置文件
│ │ │ │ │ └── main_pages.json
│ │ │ │ ├── rawfile/ # 原始文件
│ │ │ │ │ └── data.json
│ │ │ │ └── zh_CN/ # 中文资源
│ │ │ │ └── element/
│ │ │ │ └── string.json
│ │ │ └── module.json5 # 模块配置
│ │ ├── ohosTest/ # 测试代码
│ │ │ └── ets/
│ │ │ └── test/
│ │ │ └── List.test.ets
│ │ └── test/ # 本地单元测试
│ ├── hvigorfile.ts # 模块构建脚本
│ └── build-profile.json5 # 模块构建配置
├── hvigor/ # 构建配置目录
│ └── hvigorfile.ts # 项目级构建脚本
├── build-profile.json5 # 项目构建配置
├ hvigorw # Hvigor 包装器
├── hvigorw.bat
├── hvigorconfig.json # Hvigor 全局配置
└── oh-package.json5 # 项目依赖1.2 模块类型目录对比
| 模块类型 | 根目录名 | 用途 | module.json5 type |
|---|---|---|---|
| Entry | entry/ | 主应用模块,可独立安装运行 | entry |
| HAR | library/ | 静态共享包,编译时链接 | har |
| HSP | hspmodule/ | 动态共享包,运行时加载 | shared |
2. entry/pages 目录详解
2.1 pages 目录结构
entry/src/main/ets/pages/
├── Index.ets # 应用入口页(由 main_pages.json5 指定)
├── login/
│ ├── LoginPage.ets # 登录页
│ └── LoginViewModel.ets # 登录页的 ViewModel
├── home/
│ ├── HomePage.ets # 首页
│ └── components/
│ ├── TabBar.ets
│ └── Banner.ets
├── detail/
│ ├── DetailPage.ets # 详情页
│ └── DetailViewModel.ets
└── mine/
├── MinePage.ets # 个人页
└── MineViewModel.ets2.2 页面配置 main_pages.json5
json5
// entry/src/main/resources/base/profile/main_pages.json5
{
"src": [
"pages/Index",
"pages/login/LoginPage",
"pages/home/HomePage",
"pages/detail/DetailPage",
"pages/mine/MinePage"
]
}⚠️ 关键:所有路由到的页面必须在此声明,否则
router.pushUrl会失败。
3. resources 资源目录详解
3.1 资源分类
| 资源类型 | 目录 | 格式 | 访问方式 |
|---|---|---|---|
| 字符串 | element/string.json | JSON | @string/string_name |
| 颜色 | element/color.json | JSON | @color/color_name |
| 字符串值 | string.json | JSON | @string/string_name |
| 布局 | layout/ | XML | @layout/layout_name |
| 媒体 | media/ | PNG/JPG/GIF | @media/image_name |
| 菜单 | menu/ | JSON | @menu/menu_name |
| 原始文件 | rawfile/ | 任意 | resource.getRawFd() |
3.2 多语言资源
resources/
├── base/ # 默认语言(中文)
│ └── element/
│ └── string.json
├── en_US/ # 英文
│ └── element/
│ └── string.json
└── ja_JP/ # 日文
└── element/
└── string.jsonjson5
// base/element/string.json
{
"string": [
{ "name": "app_name", "value": "我的应用" },
{ "name": "hello", "value": "你好,世界" }
]
}
// en_US/element/string.json
{
"string": [
{ "name": "app_name", "value": "My App" },
{ "name": "hello", "value": "Hello, World" }
]
}3.3 资源访问方式
typescript
// ArkTS 中访问资源
import { resource } from '@kit.ArkUI';
// 方式1:在 UI 模板中通过装饰器
@Entry
@Component
struct Index {
build() {
Column() {
Text($r('app.string.hello')) // 通过 $r 访问
.fontSize(20)
Text($r('app.string.app_name'))
}
}
}
// 方式2:通过 resourceManager API
import { resourceManager } from '@kit.AbilityKit';
const manager = getContext(this).resourceManager;
const str = await manager.getStringByName('hello');4. module.json5 模块配置
4.1 module.json5 完整结构
json5
// entry/src/main/module.json5
{
"module": {
"name": "entry",
"type": "entry",
"description": "主模块描述",
"mainElement": "EntryAbility",
"deviceTypes": ["phone", "tablet"],
"deliveryWithInstall": true,
"installationFree": false,
// 权限声明
"permissions": [
{
"name": "ohos.permission.INTERNET",
"reason": "需要网络访问",
"usedScene": {
"abilities": ["EntryAbility"],
"when": "always"
}
}
],
// 入口能力
"abilities": [
{
"name": "EntryAbility",
"srcEntry": "./ets/entryability/EntryAbility.ets",
"description": "应用主入口",
"icon": "$media:icon",
"label": "$string:app_name",
"startWindowIcon": "$media:icon",
"startWindowBackground": "$color:start_window_bg",
"exported": true,
"skills": [
{
"entities": ["entity.system.home"],
"actions": ["action.system.home"]
}
],
"launchType": "standard"
}
],
// 应用级配置
"configuration": {
"bundleName": "com.example.myapp",
"apiReleaseType": "release",
"compileSdkVersion": "12",
"compatibleSdkVersion": "11",
"bundleType": "app"
}
}
}4.2 module.json5 vs AndroidManifest.xml
| 配置项 | Android (XML) | HarmonyOS (JSON5) |
|---|---|---|
| 模块类型 | <manifest> type 属性 | "type": "entry" |
| 权限 | <uses-permission> | permissions 数组 |
| 入口 | <activity> with intent-filter | abilities 数组 |
| 设备类型 | <compatible-screens> | deviceTypes 数组 |
| 网络权限 | 声明即可 | 需说明 reason |
| 配置格式 | XML | JSON5(支持注释) |
5. build-profile.json5 构建配置
5.1 项目级 build-profile.json5
json5
// build-profile.json5
{
"app": {
"signingConfigs": [
{
"name": "default",
"type": "HarmonyOS",
"material": {
"certpath": "xxx.cer",
"storeFile": "xxx.p12",
"signAlg": "SHA256withECDSA",
"storePwd": "******",
"keyPwd": "******",
"keyAlias": "debugKey"
}
}
],
"products": [
{
"name": "default",
"signingConfig": "default",
"compatibleSdkVersion": "11",
"runtimeOS": "HarmonyOS",
"bundleName": "com.example.myapp"
}
],
"buildModeSet": [
{ "name": "debug" },
{ "name": "release" }
]
},
"modules": [
{
"name": "entry",
"srcPath": "./entry",
"targets": [
{
"name": "default",
"applyToProducts": ["default"]
}
]
},
{
"name": "common",
"srcPath": "./common",
"targets": [
{
"name": "default",
"applyToProducts": ["default"]
}
]
}
]
}5.2 module-level build-profile.json5
json5
// entry/build-profile.json5
{
"apiType": "stageMode",
"compileSdkVersion": "12",
"compatibleSdkVersion": "11",
"bundleFormat": "charcoal",
"buildOption": {
"arkOptions": {
"arkFlags": ["--enable-source-map"],
"compileMode": "esmodule"
}
},
"buildOptionSet": [
{
"name": "debug",
"arkOptions": {
"sourceMap": true
}
},
{
"name": "release",
"arkOptions": {
"sourceMap": false,
"obfuscation": {
"ruleOptions": {
"enable": true,
"includes": ["**/*.ets"]
}
}
}
}
]
}6. oh-package.json5 依赖配置
json5
// oh-package.json5
{
"name": "myapp",
"version": "1.0.0",
"description": "我的 HarmonyOS 应用",
"main": "",
"author": "",
"license": "Apache-2.0",
"dependencies": {
"@ohos/axios": "^2.2.0"
},
"devDependencies": {
"@ohos/hypium": "1.0.16",
"@ohos/hvigor": "4.0.0"
},
"overrides": {
"@ohos/hvigor-ohos-plugin": "4.0.0"
}
}7. 面试高频考点
Q1: entry 和 library 模块有什么区别?
回答要点:
entry是主模块,有module.json5,可独立运行library是静态共享库,无 module.json5,不可独立运行- entry 的
type为"entry",library 的type为"har"- entry 有入口能力(Ability),library 没有
Q2: main_pages.json5 的作用是什么?
回答要点:
- 声明所有页面路由路径
- 指定应用的启动页
- 页面必须在此注册,否则 router.pushUrl 会失败
- 与 Android 的 Intent 配置类似
Q3: build-profile.json5 的 app 和 modules 分别控制什么?
回答要点:
app:应用级配置(签名、产品、构建模式)modules:模块级配置(每个模块的路径、目标平台)signingConfigs用于配置签名证书products定义不同产品变体buildModeSet定义 debug/release 构建模式
Q4: resources/base 和 resources/zh_CN 的区别?
回答要点:
base是默认资源,设备语言不匹配时回退到此zh_CN等是特定语言的资源,优先于 base- 资源查找顺序:设备语言 → 对应语言目录 → base 目录
- 如果某个字符串在 zh_CN 中缺失,会从 base 自动回退
8. Android 对比
| 概念 | Android | HarmonyOS |
|---|---|---|
| 主模块 | app/ module | entry/ module |
| 资源目录 | res/ | resources/ |
| 布局文件 | layout/ XML | resources/base/layout/ XML |
| 字符串资源 | res/values/strings.xml | resources/base/element/string.json |
| 配置文件 | AndroidManifest.xml | module.json5 |
| 构建配置 | build.gradle.kts | build-profile.json5 |
| 启动页配置 | 无特定文件 | main_pages.json5 |
| 资源引用 | @string/name | $r('app.string.name') |