第三章 元服务项目结构:工程目录解析

好,咱们今天聊聊元服务的项目结构。说实话,我刚从传统App开发转到鸿蒙时,第一眼看到这个目录结构,心里是有点懵的。怎么多了这么多文件夹?但用顺手之后,你会发现——这结构设计得真挺讲究。

3.1 工程目录概览:entry、feature、library

一个标准的元服务工程,通常包含三个核心模块:entryfeaturelibrary。我习惯把它们比作「入口、功能、底座」三层。

模块 作用 我常用的场景
entry 应用的主入口,负责启动和基础配置 放首页、路由配置、全局初始化
feature 业务功能模块,按功能拆分 登录、支付、扫码等独立业务
library 公共基础库,被其他模块依赖 网络请求、工具类、自定义组件

为什么要拆这么细?说白了,就是为了「解耦」。我在项目中遇到过好几次,所有代码都堆在entry里,后期改一个支付逻辑,结果首页也跟着报错。那叫一个头疼。

我的建议:哪怕你的元服务只有三个页面,也请至少拆出entry和library两层。这是为未来扩展留的「后路」。

3.2 entry模块详解

entry是元服务的「门面」。你想想看,用户点开你的服务,第一个加载的就是entry里的代码。

它的典型结构是这样的:

entry/
├── src/
│   ├── main/
│   │   ├── ets/          # 页面逻辑
│   │   ├── resources/    # 资源文件
│   │   └── module.json5  # 模块配置
│   └── ohosTest/         # 测试代码
├── build-profile.json5   # 构建配置
└── package.json          # 依赖管理

嗯,这里要注意:entry模块只能有一个。每个元服务工程有且仅有一个entry,它负责声明Ability、配置路由、初始化全局变量。

小技巧:我习惯在entry的ets目录下建一个pages/文件夹,专门放首页和启动页。其他业务页面,全部放到feature模块里。这样entry永远保持「轻量」。

3.3 feature模块:业务功能的「收纳盒」

feature模块,说白了就是放具体业务的地方。你可以按功能拆成多个feature,比如:

  • feature_login — 登录注册
  • feature_payment — 支付流程
  • feature_scan — 扫码功能

每个feature都是一个独立的HAP包。为什么要独立?因为元服务支持「按需加载」。用户可能只用到了扫码功能,那登录模块的代码就不需要提前下载。这能显著减少首包体积。

我曾经做过一个实验:把三个业务拆成独立feature后,首包体积从2.3MB降到了800KB。用户打开速度提升了近一倍。

避坑指南:feature之间不要互相依赖!如果feature_a引用了feature_b的代码,那它们就「耦合」了。正确的做法是:把公共代码下沉到library,feature只依赖library。

3.4 library模块:代码的「公共仓库」

library是纯代码库,不包含任何Ability。它专门存放:

  • 网络请求封装(比如axios或http)
  • 工具类(日期格式化、字符串处理)
  • 自定义UI组件(按钮、弹窗、卡片)
  • 数据模型(DTO、VO)

它的目录结构通常长这样:

library/
├── src/
│   └── main/
│       ├── ets/
│       │   ├── components/   # 公共组件
│       │   ├── utils/        # 工具函数
│       │   └── model/        # 数据模型
│       └── resources/        # 公共资源
└── index.ets                 # 导出入口

我个人习惯在library里放一个index.ets文件,统一导出所有公共模块。这样其他模块引用时,只需要写一行:

import { HttpUtil, DateUtil, MyButton } from '@ohos/library';

是不是清爽多了?

3.5 资源文件管理(resources)

资源文件这块,很多新手容易搞乱。鸿蒙的资源管理其实很「讲究」——它支持多语言、多设备、多屏幕密度。

resources目录的标准结构:

resources/
├── base/              # 基础资源(默认)
│   ├── element/       # 字符串、颜色、尺寸
│   ├── media/         # 图片、音频
│   └── profile/       # 配置文件
├── en_US/             # 英文资源
├── zh_CN/             # 中文资源
└── rawfile/           # 原始文件(不压缩)

举个例子,你在base/element/string.json里定义:

{
  "string": [
    { "name": "app_name", "value": "我的元服务" }
  ]
}

然后在zh_CN/element/string.json里覆盖:

{
  "string": [
    { "name": "app_name", "value": "我的元服务(中文版)" }
  ]
}

系统会自动根据用户语言加载对应的资源。嗯,这个机制在出海场景下特别有用。

我的经验:图片资源尽量用SVG格式。同样是图标,PNG可能几十KB,SVG只有几KB。而且SVG支持主题色切换,用户体验更好。

3.6 module.json5配置文件详解

这个文件是每个模块的「身份证」。它告诉系统:这个模块叫什么、有哪些Ability、需要什么权限。

一个典型的module.json5长这样:

{
  "module": {
    "name": "entry",
    "type": "entry",
    "description": "元服务主入口",
    "mainElement": "MainAbility",
    "deviceTypes": ["phone", "tablet"],
    "abilities": [
      {
        "name": "MainAbility",
        "srcEntry": "./ets/MainAbility/MainAbility.ets",
        "description": "主Ability",
        "icon": "$media:icon",
        "label": "$string:app_name",
        "startWindowIcon": "$media:icon",
        "startWindowBackground": "$color:start_window_background",
        "visible": true,
        "skills": [
          {
            "entities": ["entity.system.home"],
            "actions": ["action.system.home"]
          }
        ]
      }
    ],
    "requestPermissions": [
      {
        "name": "ohos.permission.INTERNET"
      }
    ]
  }
}

这里有几个关键字段,我重点说一下:

  • type:可选entryfeatureshared。entry只能有一个,feature可以有多个。
  • deviceTypes:支持的设备类型。我建议至少写上phonetablet,因为元服务在平板上体验也很好。
  • abilities:每个Ability相当于一个「页面入口」。如果你有多个页面需要独立启动,就声明多个Ability。
  • skills:这个决定了用户怎么打开你的服务。比如entity.system.home表示可以从桌面图标打开。

避坑指南:我曾经犯过一个错——忘记在requestPermissions里声明网络权限。结果上线后,用户反馈「怎么加载不出数据?」排查了半天,原来是权限没配。所以,每次写完配置,记得检查一遍权限列表。

3.7 总结:目录结构的最佳实践

说了这么多,我总结一下我个人最推荐的工程结构:

MyService/
├── entry/                  # 主入口(轻量)
│   ├── src/main/ets/pages/ # 只放首页和启动页
│   └── module.json5
├── feature_login/          # 登录模块
├── feature_payment/        # 支付模块
├── feature_scan/           # 扫码模块
├── library/                # 公共库
│   ├── components/         # 公共组件
│   ├── utils/              # 工具类
│   └── model/              # 数据模型
└── build-profile.json5     # 全局构建配置

这种结构的好处是:

  • entry保持「瘦身」,启动速度快
  • feature按业务拆分,方便团队协作
  • library统一管理,避免代码重复

你想想看,如果一开始就按这个结构来,后期加功能、修bug、做国际化,是不是都轻松很多?

好,这一章就到这里。下一章咱们聊聊页面布局与组件开发——那可是元服务UI的「灵魂」所在。