ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

鸿蒙应用开发:模块化项目结构与核心配置解析

鸿蒙应用开发:模块化项目结构与核心配置解析

1. 鸿蒙应用项目结构概述

作为一名从Android开发转向鸿蒙生态的开发者,初次接触鸿蒙项目结构时最直观的感受就是其模块化设计的彻底性。与Android项目相比,鸿蒙从项目创建伊始就采用了严格的多模块架构,这种设计理念贯穿于整个开发流程中。

在Android开发中,我们通常从一个单模块项目开始,随着业务复杂度的增加再逐步拆分模块。而鸿蒙则反其道而行之,强制开发者从一开始就考虑模块化。这种设计带来的直接好处是:

  • 代码边界清晰,避免后期重构的痛苦
  • 资源隔离明确,减少命名冲突
  • 构建效率提升,支持模块独立编译

典型的鸿蒙应用项目包含三个核心层级:

  1. 工程级配置(Project Level):定义全局构建规则、依赖管理和代码规范
  2. 应用级配置(App Level):配置应用全局属性和共享资源
  3. 模块级实现(Module Level):包含具体业务逻辑和功能实现

这种层级分明的结构设计,使得鸿蒙应用在跨设备适配、功能扩展和团队协作方面具有天然优势。下面我们就深入解析每个关键目录和文件的具体作用。

2. 工程级核心文件解析

2.1 构建系统配置文件

build-profile.json5是工程级的构建中枢,其作用相当于Android项目中的根build.gradle。这个JSON5格式的文件(支持注释和更灵活的语法)主要配置:

{ "products": [{ "name": "phone", // 产品维度:手机版 "signingConfig": "release", "compileSdkVersion": 9, "targetDevices": ["phone"] // 目标设备类型 }], "signingConfigs": [{ // 签名配置 "name": "release", "material": { "certPath": "sign/release.crt", "keyPath": "sign/release.p12", "keyAlias": "releaseKey", "keyPassword": "******", "storePassword": "******", "profile": "sign/ohosProvision.json", "signAlg": "SHA256withECDSA" } }] }

关键提示:产品维度(products)是鸿蒙特有的概念,允许为不同设备类型(如手机、手表)配置独立的构建参数,这在跨设备开发时特别有用。

hvigorfile.ts作为构建脚本入口,采用TypeScript编写,比Groovy更易维护。典型配置包括:

import { hvigor } from '@ohos/hvigor-base'; export default { tasks: { cleanAll: { action: () => { // 自定义清理任务 hvigor.executeTask('clean'); deleteDir('./build'); } } }, plugins: [ '@ohos/hvigor-plugin-ohos' // 官方插件 ] }

2.2 依赖管理机制

鸿蒙使用自研的OHPM包管理器,其配置文件oh-package.json5的结构与npm类似:

{ "name": "myapp", "version": "1.0.0", "dependencies": { "@ohos/router": "^1.0.0", // 官方路由库 "@ohos/network": "~2.1.0", // 网络模块 "third-party-lib": "file:./libs/local.aar" // 本地依赖 }, "devDependencies": { "@ohos/lint": "^3.0.0" // 开发依赖 } }

依赖安装后存储在oh_modules目录,需要注意:

  1. 该目录应加入.gitignore
  2. 版本锁定文件oh-package-lock.json5建议提交到仓库
  3. 支持本地aar、har包引用

2.3 代码质量管控

code-linter.json5提供了强大的静态检查能力:

{ "rules": { "no-console": "error", // 禁止console.log "max-nested-callbacks": ["warn", 3], // 回调嵌套深度 "arkts-no-private-identifier": "off" // 关闭私有标识符检查 }, "include": ["**/*.ets"], "exclude": ["build/**", "oh_modules/**"] }

实际开发中建议开启以下关键规则:

  • arkts-no-any: 禁止使用any类型
  • arkts-no-magic-numbers: 禁止魔法数字
  • arkts-property-order: 强制统一属性顺序

3. 应用级配置详解

3.1 全局资源配置

AppScope/resources目录采用分层设计:

resources/ ├── base/ │ ├── element/ │ │ ├── string.json # 字符串资源 │ │ ├── color.json # 颜色值定义 │ │ └── boolean.json # 布尔常量 │ └── media/ │ ├── icon.png # 应用图标 │ └── splash.png # 启动页图片 └── en_US/ # 英文资源 └── element/ └── string.json # 英文文案

字符串资源的定义示例:

{ "string": [ { "name": "app_name", "value": "我的应用" }, { "name": "login_btn", "value": "登录" } ] }

在代码中引用方式:

Text($r('app.string.app_name')) // 显示"我的应用"

3.2 应用清单文件

app.json5是应用的身份证,关键配置项包括:

{ "app": { "bundleName": "com.example.myapp", // 包名(需唯一) "vendor": "example", "versionCode": 100, "versionName": "1.0.0", "icon": "$media:app_icon", // 图标资源 "label": "$string:app_name", // 应用名称 "distributedNotificationEnabled": true, // 分布式通知 "targetAPIVersion": 9, // 目标API版本 "apiReleaseType": "Release", // API类型 "debuggable": true // 调试模式 } }

特别需要注意:

  1. bundleName采用反向域名规则,上架应用市场后不可修改
  2. versionCode每次更新必须递增
  3. 生产环境应将debuggable设为false

4. 模块级实现剖析

4.1 模块类型与职责

鸿蒙支持多种模块类型,通过module.json5中的type字段定义:

{ "module": { "name": "entry", "type": "entry", // 入口模块 "srcEntry": "./ets/MainAbility", "description": "$string:module_desc", "mainElement": "MainAbility", "deviceTypes": ["phone", "tablet"], "deliveryWithInstall": true, "installationFree": false, "pages": "$profile:main_pages", "abilities": [...] } }

常见模块类型对比:

类型说明可独立运行典型用途
entry主入口是应用主模块
feature功能模块否支付、分享等功能
har静态共享包否工具类库
shared动态共享包否公共UI组件

4.2 Ability生命周期管理

以EntryAbility.ts为例的典型实现:

import UIAbility from '@ohos.app.ability.UIAbility'; export default class EntryAbility extends UIAbility { // 应用创建时触发 onCreate(want, launchParam) { console.log('Ability onCreate'); this.initGlobalConfig(); } // 切换到前台 onForeground() { console.log('Ability onForeground'); this.resumeTasks(); } // 切换到后台 onBackground() { console.log('Ability onBackground'); this.pauseTasks(); } // 应用销毁 onDestroy() { console.log('Ability onDestroy'); this.cleanup(); } private initGlobalConfig() { // 初始化全局状态 } }

关键生命周期方法:

  1. onCreate: 只会在Ability首次创建时调用
  2. onWindowStageCreate: 窗口创建时调用
  3. onForeground/onBackground: 可能被频繁调用

4.3 页面路由配置

pages目录下的路由配置示例:

// src/main/ets/pages/Index.ets @Entry @Component struct Index { build() { Column() { Text('首页') .fontSize(30) Button('跳转到详情') .onClick(() => { router.pushUrl({ url: 'pages/Detail', params: { id: 123 } }); }) } } } // src/main/ets/pages/Detail.ets @Entry @Component struct Detail { @State id: number = 0; onPageShow(params: Record<string, string>) { this.id = Number(params?.id || 0); } build() { Column() { Text(`详情ID: ${this.id}`) } } }

路由配置文件resources/base/profile/main_pages.json:

{ "src": [ "pages/Index", "pages/Detail", "pages/UserCenter" ] }

5. 构建与调试实践

5.1 多环境构建配置

通过build-profile.json5配置不同环境:

{ "products": [ { "name": "dev", "signingConfig": "debug", "compileSdkVersion": 9, "targetDevices": ["phone"], "buildType": "debug", "env": { "API_BASE": "https://dev.api.example.com" } }, { "name": "prod", "signingConfig": "release", "compileSdkVersion": 9, "targetDevices": ["phone", "tablet"], "buildType": "release", "env": { "API_BASE": "https://api.example.com" } } ] }

在代码中访问环境变量:

const context = getContext(this); const apiBase = context.config.env.API_BASE;

5.2 调试技巧

  1. 实时预览:

    • 修改.preview/PreviewBuildParam.json切换预览设备
    • 支持热重载,保存文件后自动刷新
  2. 日志过滤:

    hdc shell hilog -T "MyTag" # 按标签过滤 hdc shell hilog -L D # 仅显示Debug级别
  3. 性能分析:

    hdc shell hiprofiler -c 5 -o /data/local/tmp/trace.html

6. 常见问题解决方案

6.1 资源引用失败

现象:$r('app.string.xxx')返回undefined

排查步骤:

  1. 确认资源文件路径正确
  2. 检查string.json中name是否匹配
  3. 清理构建缓存(hvigor clean)
  4. 检查模块依赖关系

6.2 多模块通信

推荐使用EventHub进行模块间通信:

// 发送方 import common from '@ohos.app.ability.common'; const context = getContext(this) as common.UIAbilityContext; context.eventHub.emit('event_name', { data: 123 }); // 接收方 context.eventHub.on('event_name', (data) => { console.log('收到数据:', data); });

6.3 屏幕适配方案

推荐使用以下方案:

  1. 使用vp(虚拟像素)单位:
    Text('适配文本') .fontSize(16) // 单位:vp .width('100%') // 百分比
  2. 多资源目录:
    resources/ ├── base/ // 默认 ├── small/ // 小屏 └── large/ // 大屏
  3. 媒体查询:
    @Styles function smallScreenStyle() { .width('90%') } @Builder function AdaptLayout() { if (mediaQueryMatchDevice('small')) { Column() { // 小屏布局 }.smallScreenStyle() } else { // 默认布局 } }

7. 项目结构优化建议

经过多个鸿蒙项目的实践,总结出以下优化方案:

  1. 模块拆分原则:

    • 按功能维度划分(如user、payment模块)
    • 公共组件提取为shared模块
    • 第三方SDK封装为独立模块
  2. 资源管理规范:

    resources/ ├── base/ │ ├── element/ │ │ ├── color/ │ │ │ ├── text.json # 文本颜色 │ │ │ └── theme.json # 主题色 │ │ └── string/ │ │ ├── common.json # 通用文案 │ │ └── home.json # 页面专属文案 │ └── media/ │ ├── icons/ # 图标 │ └── images/ # 图片 └── en_US/ # 英文资源 └── element/ └── string/ ├── common.json └── home.json
  3. 构建速度优化:

    • 开启Hvigor并行构建:
      // hvigorfile.ts export default { parallel: true, cache: { enabled: true, strategy: 'content' } }
    • 使用--watch模式开发:
      hvigor assemble --watch
  4. 代码组织建议:

    src/main/ets/ ├── abilities/ # Ability实现 ├── common/ # 通用工具 │ ├── utils/ # 工具类 │ └── constants/ # 常量定义 ├── components/ # 公共组件 ├── model/ # 数据模型 │ ├── api/ # 接口定义 │ └── entity/ # 实体类 ├── pages/ # 页面组件 │ ├── home/ # 首页 │ │ ├── components/ # 页面私有组件 │ │ └── viewmodel.ets # 业务逻辑 │ └── detail/ └── router/ # 路由配置

鸿蒙的项目结构设计体现了其"一次开发,多端部署"的理念。通过合理的模块划分和资源配置,开发者可以高效构建适配多种设备的应用。在实际项目中,建议初期就规划好模块结构,避免后期调整带来的重构成本。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进