从零搭建记账应用 — MoneyTrack 工程全景解析在这里插入图片描述

概述

当开发者第一次接触一个新的鸿蒙应用工程时,面对纷繁的目录结构和配置文件,往往不知从何入手。理解工程的骨架和各个配置文件的用途,是高效开发和定位问题的第一步。MoneyTrack 基于 HarmonyOS Stage 模型构建,采用标准的多模块 HAR 工程布局,其工程结构代表了当前鸿蒙商业级应用的典型范式。本文从工程目录结构出发,逐一解析 AppScope 全局配置、products 入口模块、commons 通用库、components 业务组件和 features 特性页面的完整划分与设计思路,并深入分析关键配置文件的细节,帮助读者建立起鸿蒙应用工程的全局认知。

核心知识点

1. Stage 模型工程结构

HarmonyOS Stage 模型的工程包含三个主要区域:

  • AppScope:存放全局应用配置,包括 app.json5(bundleName、版本号、图标等)和 resources 目录(全局资源),是应用级元数据的集中管理区域。
  • 模块(modules):每个 HAR 或 entry 模块独立存放,包含 src/main/module.json5(模块配置)、src/main/ets/(ArkTS 代码目录)、src/main/resources/(模块级资源目录)。
  • 编译配置:根目录 build-profile.json5 定义所有模块和构建目标,hvigor/hvigor-config.json5 配置构建工具链参数。

MoneyTrack 的完整工程目录结构如下:

MoneyTrack 根目录

/

AppScope/

products/

commons/

components/

features/

hvigor/

build-profile.json5

hvigorfile.ts

app.json5

resources/

entry/

module.json5

src/main/ets/

src/main/resources/

pages/MainEntry.ets

entryability/EntryAbility.ets

entryformability/EntryFormAbility.ets

commonlib/

lib_network/

bill_base/

bill_card/

bill_chart/

bill_manage/

bill_data_processing/

asset_base/

asset_card/

asset_manage/

aggregated_login/

app_setting/

collect_personal_info/

feedback/

membership/

module_ui_base/

home/

statistics/

assets/

mine/

2. AppScope 配置详解

AppScope/app.json5 定义应用的全局元数据:

{
  "app": {
    "bundleName": "com.hyh.moneyTrack",
    "vendor": "example",
    "versionCode": 1000000,
    "versionName": "1.0.0",
    "icon": "$media:layered_image",
    "label": "$string:app_name"
  }
}
  • bundleName:应用唯一标识,格式通常为反域名形式,在华为应用市场发布后不可更改。
  • versionCode:整型版本号,用于应用市场的版本比较和灰度发布,此处 1000000 对应 1.0.0
  • versionName:面向用户的版本名称,显示在应用详情页。
  • icon/label:引用 resources/base/element/string.jsonresources/base/media/ 目录下的资源。

资源文件位于 AppScope/resources/base/ 目录,包含 element/string.json(字符串国际化)、media/(应用图标和分层图)。

3. products/entry 入口模块

products/entry 作为应用入口(type 为 “entry”),是唯一一个可独立安装的模块。其 module.json5 配置了完整的 Ability 体系:

{
  "module": {
    "name": "entry",
    "type": "entry",
    "description": "$string:module_desc",
    "mainElement": "EntryAbility",
    "deviceTypes": ["phone", "tablet"],
    "deliveryWithInstall": true,
    "installationFree": false,
    "pages": "$profile:main_pages",
    "metadata": [
      // todo: 修改client_id
      { "name": "client_id", "value": "******" }
    ],
    "querySchemes": [
      "weixin", "wxopensdk", "qqopenapi", "https"
    ],
    "abilities": [
      {
        "name": "EntryAbility",
        "supportWindowMode": ["fullscreen", "floating"],
        "srcEntry": "./ets/entryability/EntryAbility.ets",
        "description": "$string:EntryAbility_desc",
        "icon": "$media:layered_image",
        "label": "$string:EntryAbility_label",
        "startWindowIcon": "$media:app_icon",
        "startWindowBackground": "$color:start_window_background",
        "exported": true,
        "skills": [
          {
            "entities": ["entity.system.home"],
            "actions": ["action.system.home"]
          }
        ]
      }
    ],
    "requestPermissions": [
      { "name": "ohos.permission.PUBLISH_AGENT_REMINDER" }
    ],
    "extensionAbilities": [
      {
        "name": "EntryFormAbility",
        "srcEntry": "./ets/entryformability/EntryFormAbility.ets",
        "label": "$string:EntryFormAbility_label",
        "description": "$string:EntryFormAbility_desc",
        "type": "form",
        "metadata": [
          {
            "name": "ohos.extension.form",
            "resource": "$profile:form_config"
          }
        ]
      }
    ]
  }
}

关键配置说明:

  • mainElement:指定应用启动时加载的 Ability(EntryAbility),声明了 skillsentity.system.homeaction.system.home 表示这是桌面入口。
  • deviceTypes:支持 phone 和 tablet 两种设备,系统会根据运行设备自动适配形态。
  • querySchemes:声明应用需要查询的 URL Scheme,包括 weixin(微信支付/登录)、qqopenapi(QQ 互联)、https(通用 Web 跳转),是实现第三方登录和支付的必要配置。
  • requestPermissions:声明 PUBLISH_AGENT_REMINDER 权限,用于账单提醒和通知。
  • extensionAbilities:注册 EntryFormAbility(类型为 form),用于提供服务卡片能力。

EntryAbility 的实际代码如下——它在 onCreate 中设置应用主题色,在 onWindowStageCreate 中加载主页面:

export default class EntryAbility extends UIAbility {
  public onCreate(want: Want): void {
    this.context.getApplicationContext()
      .setColorMode(ConfigurationConstant.ColorMode.COLOR_MODE_LIGHT);
    this.handleWantInfo(want);
  }

  public onNewWant(want: Want): void {
    this.handleWantInfo(want);
  }

  public onWindowStageCreate(windowStage: window.WindowStage): void {
    windowStage.loadContent('pages/MainEntry', (err) => {
      if (err.code) {
        Logger.error(TAG, 'Failed to load the content.' + JSON.stringify(err));
        return;
      }
      contextUtil.setUiContext(windowStage.getMainWindowSync().getUIContext());
    });
  }
}

主入口页面 MainEntry.ets 使用 Tabs 组件组织四个 Tab 页面,每个 Tab 对应一个特性模块的视图:

@Entry
@ComponentV2
struct MainEntry {
  vm: MainEntryVM = MainEntryVM.instance;

  build() {
    Navigation(this.vm.navStack) {
      Tabs({ barPosition: BreakpointSystem.isTablet ? BarPosition.Start : BarPosition.End,
             index: this.vm.curIndex, controller: this.vm.tabController }) {
        TabContent() { HomeView() }
          .tabBar(this.tabBarBuilder(TabIndexMap.HOME))
        TabContent() { StatisticsView() }
          .tabBar(this.tabBarBuilder(TabIndexMap.STATISTICS))
        TabContent() { AssetsView() }
          .tabBar(this.tabBarBuilder(TabIndexMap.ASSETS))
        TabContent() { MineView() }
          .tabBar(this.tabBarBuilder(TabIndexMap.MINE))
      }
    }
  }
}

4. 构建配置:hvigor-config.json5

hvigor/hvigor-config.json5 控制鸿蒙构建工具链的行为:

{
  "modelVersion": "5.0.2",
  "dependencies": {},
  "execution": {
    // "analyze": "normal",       /* 构建分析模式:normal | advanced | false */
    // "daemon": true,            /* 守护进程编译,加速重复构建 */
    // "incremental": true,       /* 增量编译,只重新编译变更文件 */
    // "parallel": true,          /* 并行编译,多模块同时构建 */
    // "typeCheck": false,        /* 是否启用类型检查 */
  },
  "logging": {
    // "level": "info"           /* 日志级别:debug | info | warn | error */
  },
  "debugging": {
    // "stacktrace": false       /* 编译错误时是否输出完整堆栈 */
  },
  "nodeOptions": {
    // "maxOldSpaceSize": 8192   /* Node.js 最大堆内存,单位 MB */
  }
}

这些配置项对构建性能有直接影响:

  • 并行编译(parallel):21 个模块的工程开启并行编译后,构建时间可从数分钟缩短至数十秒。
  • 增量编译(incremental):开发阶段只编译发生变化的文件,大幅提升热重载效率。
  • 类型检查(typeCheck):Release 构建建议开启,Debug 构建可关闭以加快编译速度。

5. 各层目录结构详析

commons 通用层

commons/commonlib 是项目的"工具箱",其内部结构展示了通用模块的最佳组织方式:

commons/commonlib/src/main/ets/
├── components/           # 通用 UI 组件
│   ├── CommonButton.ets
│   ├── CommonDayPicker.ets
│   ├── CommonDivider.ets
│   ├── CommonHeader.ets
│   ├── CommonMonthPicker.ets
│   ├── ContainerColumn.ets
│   └── ContainerRow.ets
├── constants/            # 常量与枚举
│   ├── CommonConstants.ets
│   └── CommonEnums.ets
├── dialogs/              # 通用弹窗
│   └── CommonConfirmDialog.ets
└── utils/                # 工具类
    ├── eventbus/         # 事件总线
    ├── framework/        # 框架工具(Tab 切换等)
    ├── logger/           # 日志封装
    ├── router/           # 路由管理(RouterModule)
    ├── userinfo/         # 用户信息管理
    ├── window/           # 窗口工具
    ├── BreakpointSystem.ets  # 断点适配系统
    ├── ContextUtil.ets       # Context 工具
    └── ReminderUtil.ets      # 提醒工具

commons/lib_network 封装了网络层:

commons/lib_network/src/main/ets/
├── constants/Enums.ets           # 网络相关枚举
├── https/
│   ├── apis/                     # 业务 API
│   │   ├── Asset.ets
│   │   ├── Bill.ets
│   │   └── User.ets
│   └── Request.ets               # Axios 请求封装
├── httpsmock/                    # Mock 数据
│   ├── mockapis/                 # Mock API 实现
│   └── MockAdapter.ets
└── types/responses/              # 响应类型定义
    ├── BaseResponse.ets
    └── UserResponse.ets
components 组件层(共 14 个模块)

每个组件模块遵循一致的内部结构。以 bill_base 为例:

components/bill_base/src/main/ets/
├── commons/
│   ├── BillConstants.ets   # 常量
│   ├── Enums.ets           # 枚举(BalanceChangeType 等)
│   ├── FamilyModels.ets    # 家庭账本数据模型
│   ├── Models.ets          # 核心数据模型
│   └── Types.ets           # TypeScript 类型定义
└── utils/
    ├── BreakpointSystem.ets # 断点适配
    ├── Logger.ets           # 日志
    └── ResourceUtil.ets     # 资源工具

collect_personal_info 为例的复杂组件模块:

components/collect_personal_info/src/main/ets/
├── common/
│   ├── ConfigModel.ets
│   ├── Constant.ets
│   ├── CustomModifier.ets
│   ├── ErrorMsgMap.ets
│   ├── FormModel.ets
│   ├── GridRowColSetting.ets
│   └── Types.ets
├── components/              # 表单子组件
│   ├── ChooseAvatar.ets
│   ├── ChooseDate.ets
│   ├── EnterPhoneNumber.ets
│   ├── EnterTextArea.ets
│   ├── EnterTextInput.ets
│   └── SelectDialog.ets
├── viewmodels/
│   └── PersonalInfoViewVM.ets
└── views/
    ├── ListCard.ets
    └── PersonalInfoView.ets
features 特性层(共 4 个模块)

home 为例——它是最核心的特性模块:

features/home/src/main/ets/
├── commons/
│   ├── Constants.ets        # 首页常量
│   ├── Enums.ets            # 首页枚举(弹窗类型等)
│   ├── Models.ets           # 首页数据模型
│   └── Types.ets            # 类型定义
├── components/              # 首页子组件
│   ├── AccountBookSelector.ets
│   ├── MonthlyBudgetCard.ets
│   └── TypeFilterSheet.ets
├── viewmodels/              # ViewModel 层
│   ├── AccountBookVM.ets
│   ├── BillDetailVM.ets
│   └── HomeVM.ets
└── views/                   # 页面视图
    ├── AccountBookDetailPage.ets
    ├── AccountBookManagePage.ets
    ├── AccountBookPage.ets
    ├── BillDetailPage.ets
    ├── HomeView.ets
    └── ResourceManagePage.ets

assets 为例:

features/assets/src/main/ets/
├── commons/Constants.ets
├── components/
│   ├── AssetFilterSheet.ets
│   ├── AssetLineChart.ets
│   └── BalanceTypeSelection.ets
├── viewmodels/
│   ├── AssetAnalysisVM.ets
│   ├── AssetDetailVM.ets
│   └── AssetsVM.ets
└── views/
    ├── AddAssetPage.ets
    ├── AssetAnalysisPage.ets
    ├── AssetDetailPage.ets
    └── AssetsView.ets

6. 关键配置文件速查表

配置文件 路径 核心作用 关键字段
app.json5 AppScope/app.json5 应用级元数据 bundleNameversionCodeversionName
module.json5 products/entry/src/main/module.json5 入口模块配置 abilitiesextensionAbilitiesdeviceTypesquerySchemes
build-profile.json5 ./build-profile.json5 模块注册与构建目标 modules[].srcPathproducts[].targetSdkVersion
hvigor-config.json5 hvigor/hvigor-config.json5 构建工具链参数 execution.parallelexecution.incremental
oh-package.json5 每个模块根目录 模块元数据与依赖声明 namemaindependencies
main_pages.json products/entry/src/main/resources/base/profile/main_pages.json 页面路由注册 src 数组列出所有页面路径
router_map.json 各模块 resources/base/profile/ 模块内路由映射 NavDestination 名字与页面的映射关系
form_config.json products/entry/src/main/resources/base/profile/ 服务卡片配置 卡片类型、更新周期、支持尺寸

最佳实践与注意事项

1. 统一包名与版本管理

bundleName 一旦发布即不可更改,因此要确保签名证书的 bundleName 与 app.json5 中一致。建议在项目启动阶段就确定最终的包名,并在 CI/CD 流水线中统一管理 versionCode 的自动递增逻辑。

2. Ability 配置的最小化原则

module.json5 只应包含应用模块级别的配置。Ability 内部的环境初始化逻辑应放在对应的 Ability 实现类中,而非集中写在配置文件中。例如,EntryAbility 中通过 handleWantInfo 处理外部拉起参数,通过 onWindowStageCreate 加载首页,逻辑清晰且便于测试。

3. querySchemes 的按需声明

querySchemes 数组声明的 Scheme 会影响应用市场审核。只需声明确实需要的 Scheme(如微信登录的 weixin),不需要的 Scheme 不应添加。同时要注意,querySchemes 仅允许查询,实际跳转还需要配合 openLink 等 API。

4. 资源管理的层级策略

全局共享的资源(如应用名称、图标)放在 AppScope/resources 中;模块内部独享的资源(如账单分类图标、字符串)放在各自模块的 resources 目录中。这样可以避免资源名冲突,也便于模块的独立发布和消费。

5. 构建配置的针对性调优

Debug 构建建议关闭类型检查、开启并行和增量编译以提升开发效率;Release 构建应开启所有检查项并关闭不必要的调试日志。在 hvigor-config.json5 中可根据构建模式做差异化配置。

总结

MoneyTrack 的工程全景展现了鸿蒙 Stage 模型下多模块应用的标准布局。从 AppScope 的全局配置到每个模块的自包含结构,从 module.json5 的 Ability 注册到 hvigor-config.json5 的构建优化,每个配置文件都有其明确的职责。理解这一工程结构,不仅能帮助开发者快速上手 MoneyTrack 项目,更能为构建自己的鸿蒙应用提供可复用的蓝图。核心思路是:将关注点分离原则贯彻到工程的每个角落——资源按层级归属、配置按模块自治、依赖按方向控制,这样才能构建出真正可维护、可扩展的鸿蒙应用。

参考文档

  • HarmonyOS 应用工程结构指南
  • Stage 模型开发说明
  • module.json5 配置文件参考
  • 项目源文件:d:\HarmonyOS\WorkSpace\MoneyTrack1.0.3\build-profile.json5
  • 入口配置:d:\HarmonyOS\WorkSpace\MoneyTrack1.0.3\products\entry\src\main\module.json5
  • 构建配置:d:\HarmonyOS\WorkSpace\MoneyTrack1.0.3\hvigor\hvigor-config.json5
  • 入口页面:d:\HarmonyOS\WorkSpace\MoneyTrack1.0.3\products\entry\src\main\ets\pages\MainEntry.ets
  • Ability 实现:d:\HarmonyOS\WorkSpace\MoneyTrack1.0.3\products\entry\src\main\ets\entryability\EntryAbility.ets
Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐