从一个 entry 写到十几个模块:鸿蒙模块化开发的真实落地方案(含可运行 Demo)

摘要

随着 HarmonyOS 在多设备、多场景中的应用越来越多,应用规模也在不断变大。从最早的单模块 App,到现在动辄十几个业务功能、多个团队协作,如果还用"一个模块写到底"的方式,维护成本会非常高。

模块化开发在鸿蒙中并不是一个"额外技巧",而是官方从架构层面就鼓励的一种开发方式。本文结合鸿蒙的模块体系,讲清楚模块该怎么拆、模块之间怎么通信,并通过可运行的 Demo 和真实业务场景,把模块化真正落地。

引言

在实际开发中,很多鸿蒙项目一开始都很简单,一个 entry 模块,页面、网络、工具类全堆在一起。但随着功能增加,很快就会遇到这些问题:

  • 改一个功能,其他页面也跟着出问题
  • 公共代码到处 copy,版本不一致
  • 包体越来越大,启动越来越慢
  • 多人协作时频繁冲突

鸿蒙本身提供了 Feature、Shared、Service 等模块形态,如果合理使用,可以很好地解决这些问题。接下来我们就从整体结构开始,一步一步拆解。

鸿蒙模块化开发的整体架构设计

模块角色划分思路

在一个标准的模块化鸿蒙项目中,每一类模块都有明确职责:

  • Entry:应用入口,只负责调度和路由
  • Feature:具体业务功能,一个模块一个业务
  • Shared:公共能力,比如网络、工具类、基础 UI
  • Service:后台服务或跨模块、跨设备能力

核心原则只有一句话:
业务只存在于 Feature,公共能力全部下沉到 Shared。

一个典型的模块化项目结构

text 复制代码
MyHarmonyApp
├── entry
├── feature_login
├── feature_home
├── feature_user
├── shared_common
│   ├── http
│   ├── utils
│   └── ui
└── service_update

这个结构在实际项目中非常常见,后续新增功能,基本就是不断加 Feature 模块。

Entry 模块的职责与实现

Entry 只做调度,不写业务

Entry 模块是应用的入口,但很多新手会把业务页面直接写在 Entry 里,这样后期基本没法拆。

Entry 模块中只推荐做三件事:

  • 应用启动逻辑
  • 路由跳转
  • Feature 模块调度

Entry 页面示例代码

ts 复制代码
// entry/src/main/ets/pages/Index.ets
import router from '@ohos.router'

@Entry
@Component
struct Index {
  build() {
    Column() {
      Button('进入登录页')
        .onClick(() => {
          router.pushUrl({
            url: 'pages/LoginPage'
          })
        })
    }
    .width('100%')
    .height('100%')
  }
}

这里的 LoginPage 实际是定义在 feature_login 模块中的页面,只要 Entry 依赖了这个 Feature,就可以正常跳转。

Feature 模块的设计与实现

Feature 模块的基本原则

一个 Feature 模块只做一件事,比如:

  • 登录功能
  • 用户信息管理
  • 订单管理

模块内部尽量做到自洽,不依赖其他 Feature。

Feature 登录模块示例

目录结构:

text 复制代码
feature_login
└── src
    └── main
        └── ets
            ├── pages
            │   └── LoginPage.ets
            └── viewmodel
                └── LoginViewModel.ts

登录页面代码示例

ts 复制代码
// feature_login/pages/LoginPage.ets
import { LoginViewModel } from '../viewmodel/LoginViewModel'

@Component
struct LoginPage {
  private vm: LoginViewModel = new LoginViewModel()

  build() {
    Column() {
      TextInput({ placeholder: '用户名' })
        .onChange(value => this.vm.username = value)

      TextInput({ placeholder: '密码' })
        .type(InputType.Password)
        .onChange(value => this.vm.password = value)

      Button('登录')
        .onClick(() => {
          this.vm.login()
        })
    }
    .padding(20)
  }
}

ViewModel 示例

ts 复制代码
// feature_login/viewmodel/LoginViewModel.ts
import { HttpClient } from 'shared_common/http/HttpClient'
import { LogUtil } from 'shared_common/utils/LogUtil'

export class LoginViewModel {
  username: string = ''
  password: string = ''

  async login() {
    LogUtil.d('开始登录')

    const result = await HttpClient.post('/login', {
      username: this.username,
      password: this.password
    })

    LogUtil.d(`登录结果:${JSON.stringify(result)}`)
  }
}

这里可以看到,Feature 只关心业务逻辑,网络和日志能力全部来自 Shared。

Shared 模块的公共能力设计

Shared 模块适合放什么

Shared 模块中一般放这些内容:

  • 网络请求封装
  • 日志工具
  • 本地存储
  • 通用 UI 组件

不建议在 Shared 中放页面。

网络工具示例

ts 复制代码
// shared_common/http/HttpClient.ts
export class HttpClient {
  static async post(url: string, data: object) {
    // 模拟网络请求
    return new Promise(resolve => {
      setTimeout(() => {
        resolve({
          code: 0,
          data: {}
        })
      }, 500)
    })
  }
}

日志工具示例

ts 复制代码
// shared_common/utils/LogUtil.ts
export class LogUtil {
  static d(msg: string) {
    console.info(`[AppLog] ${msg}`)
  }
}

这些工具在所有 Feature 中都可以复用。

Service 模块在真实场景中的应用

为什么需要 Service 模块

当出现以下需求时,就很适合使用 Service:

  • 后台任务
  • OTA 升级
  • 数据同步
  • 跨模块能力调用

Service 可以让业务模块完全不关心实现细节。

OTA 升级 Service 示例

ts 复制代码
// service_update/UpdateService.ts
import ServiceExtensionAbility from '@ohos.app.ability.ServiceExtensionAbility'

export default class UpdateService extends ServiceExtensionAbility {
  onStart() {
    console.info('OTA 升级服务启动')
  }
}

Feature 中调用 Service

ts 复制代码
import featureAbility from '@ohos.ability.featureAbility'

featureAbility.startAbility({
  want: {
    bundleName: 'com.example.app',
    abilityName: 'UpdateService'
  }
})

这样 Feature 只需要"使用升级能力",不关心升级是怎么实现的。

实际应用场景分析

场景一:大型业务 App 拆分

在一个包含登录、首页、用户中心、订单的 App 中:

  • 每个业务一个 Feature
  • 网络和存储统一放 Shared
  • 登录态校验放 Service

这样新增业务只需要新增 Feature,不会影响已有功能。

场景二:智能设备远程升级

在你正在做的远程升级场景中:

  • Service:负责下载、校验、重启
  • Feature:提供升级 UI 和操作入口
  • Shared:提供网络和文件工具

模块职责清晰,后期维护成本很低。

场景三:多人协作开发

模块化后,每个开发者负责一个 Feature:

  • 冲突减少
  • 测试更简单
  • 发布更安全

常见问题 Q&A

Q1:Feature 之间可以直接依赖吗?

不推荐。如果确实需要共享能力,应该下沉到 Shared 或 Service。

Q2:所有功能都要拆 Feature 吗?

只要是相对独立的业务,都建议拆成 Feature,哪怕一开始规模不大。

Q3:模块多了会不会影响性能?

不会。鸿蒙支持 Feature 按需加载,合理拆分反而有利于性能优化。

总结

鸿蒙的模块化开发不是形式上的拆文件夹,而是一种清晰的架构思维:

  • Entry 负责调度
  • Feature 负责业务
  • Shared 负责复用
  • Service 负责能力输出

一旦项目按这个思路搭好,后续不管是功能扩展、团队协作,还是系统级能力接入,都会非常顺畅。

相关推荐
一只大侠的侠6 小时前
Flutter开源鸿蒙跨平台训练营 Day14React Native表单开发
flutter·开源·harmonyos
听麟6 小时前
HarmonyOS 6.0+ APP AR文旅导览系统开发实战:空间定位与文物交互落地
人工智能·深度学习·华为·ar·wpf·harmonyos
空白诗6 小时前
高级进阶React Native 鸿蒙跨平台开发:slider 滑块组件 - 音量调节器完整实现
react native·react.js·harmonyos
●VON7 小时前
HarmonyOS应用开发实战(基础篇)Day01-《ArkTS基本知识》
学习·华为·harmonyos·鸿蒙·von
BlackWolfSky7 小时前
鸿蒙高级课程笔记2—应用性能优化
笔记·华为·harmonyos
ujainu7 小时前
护眼又美观:Flutter + OpenHarmony 鸿蒙记事本一键切换夜间模式(四)
android·flutter·harmonyos
一只大侠的侠7 小时前
Flutter开源鸿蒙跨平台训练营 Day 13从零开发注册页面
flutter·华为·harmonyos
森之鸟7 小时前
鸿蒙审核常见问题避坑指南_Scroll嵌套List_Grid滑动优化
华为·harmonyos
一只大侠的侠7 小时前
Flutter开源鸿蒙跨平台训练营 Day19自定义 useFormik 实现高性能表单处理
flutter·开源·harmonyos