一、核心结论:逐个创建,统一管理
features/ 目录本质上只是一个普通的文件夹,它不像 entry 那样有特殊的系统含义。创建多个 HSP 的方式就是逐个在 features 目录下创建 Shared Library 模块 ,然后通过 oh-package.json5 管理它们之间的依赖关系。
二、创建步骤(DevEco Studio 操作)
步骤 1:创建 features 目录
在工程根目录下,新建一个名为 features 的空文件夹:
php
MyApp/
├── entry/ ← 已有的 Entry 模块
├── features/ ← 手动创建的空文件夹(右键 → New → Directory)
└── ...
步骤 2:逐个创建 HSP 模块
操作入口(任选其一):
- 方法 A :鼠标移到
features目录上 → 右键 → New → Module - 方法 B :菜单栏 → File → New → Module
在弹出的创建向导中:
vbnet
┌──────────────────────────────────────────┐
│ New Module │
│ │
│ Template: Shared Library ← 选这个! │
│ │
│ Module name: home ← 第一个 HSP │
│ Device type: Phone / Tablet / ... │
│ Enable native: □ (是否需要 C++) │
│ │
│ [Finish] │
└──────────────────────────────────────────┘
⚠️ 模板选择 :一定要选 Shared Library,不要选 Static Library(那是 HAR)。
步骤 3:重复操作,创建多个 HSP
对 features/ 目录重复上述操作,逐个创建:
vbnet
右键 features → New → Module → Shared Library → 输入「message」→ Finish
右键 features → New → Module → Shared Library → 输入「mine」 → Finish
右键 features → New → Module → Shared Library → 输入「search」 → Finish
步骤 4:验证结果
完成后,工程目录应如下:
java
MyApp/
├── entry/
├── features/ ← 手动创建的文件夹
│ ├── home/ ← HSP 模块(Shared Library)
│ │ ├── src/main/ets/
│ │ ├── index.ets ← 对外导出入口
│ │ ├── oh-package.json5
│ │ ├── module.json5
│ │ └── build-profile.json5
│ ├── message/ ← HSP 模块
│ ├── mine/ ← HSP 模块
│ └── search/ ← HSP 模块
├── oh-package.json5 ← 工程级依赖
└── build-profile.json5 ← 工程级构建配置
三、配置模块间依赖关系
每个 HSP 模块独立存在,需要通过 oh-package.json5 声明谁来依赖谁。
典型依赖配置
bash
entry → features/home
entry → features/message
entry → features/mine
features/home → common/uicomponents
features/message → common/network
json5
// entry/oh-package.json5 --- 主模块依赖各个 feature
{
"name": "@hm/entry",
"dependencies": {
"@hm/home": "file:../features/home",
"@hm/message": "file:../features/message",
"@hm/mine": "file:../features/mine",
"@hm/common": "file:../common"
}
}
json5
// features/home/oh-package.json5 --- feature 依赖公共层
{
"name": "@hm/home",
"dependencies": {
"@hm/uicomponents": "file:../../common/uicomponents"
}
}
json5
// features/message/oh-package.json5
{
"name": "@hm/message",
"dependencies": {
"@hm/network": "file:../../common/network"
}
}
添加依赖的操作方式
在 DevEco Studio 中,编辑完 oh-package.json5 后,把鼠标放在报错处会弹出提示,点击 Run 'ohpm install' 即可自动完成依赖映射。
四、每个 HSP 模块的内部结构
创建完模块后,需要按 MVVM 分层组织内部代码:
arduino
features/home/
├── src/main/
│ ├── ets/
│ │ ├── model/ ← 数据模型
│ │ │ └── ArticleItem.ets
│ │ ├── viewmodel/ ← 业务逻辑
│ │ │ └── HomeViewModel.ets
│ │ ├── view/ ← UI 页面和组件
│ │ │ ├── HomePage.ets
│ │ │ └── ArticleCard.ets
│ │ ├── pages/ ← 对外暴露的页面
│ │ │ └── HomePage.ets
│ │ └── constants/ ← 模块内常量
│ └── resources/ ← 模块专属资源
├── index.ets ← ★ 统一导出
├── oh-package.json5
├── module.json5
└── build-profile.json5
index.ets --- 统一对外出口
typescript
// features/home/index.ets
// 只导出需要被其他模块使用的部分
// 导出页面(供 entry 通过 router 跳转)
export { HomePage } from './src/main/ets/pages/HomePage'
// 导出 ViewModel(供 entry 直接使用)
export { HomeViewModel } from './src/main/ets/viewmodel/HomeViewModel'
// 导出公共组件
export { ArticleCard } from './src/main/ets/view/ArticleCard'
// 不导出内部实现:model 层的具体结构、工具函数等
五、在 Entry 中使用 HSP 的接口
typescript
// entry/src/main/ets/pages/Index.ets
import { HomeViewModel, HomePage, ArticleCard } from '@hm/home'
import router from '@ohos.router'
@Entry
@ComponentV2
struct MainPage {
private homeVM: HomeViewModel = new HomeViewModel()
aboutToAppear(): void {
this.homeVM.loadArticles()
}
build() {
Column() {
// 使用 HSP 导出的组件
ArticleCard({ title: '今日推荐' })
Button('跳转首页')
.onClick(() => {
// 通过页面路由跳转到 HSP 中的页面
router.pushUrl({
url: '@bundle:com.example.myapp/home/ets/pages/HomePage'
// └─ 格式:@bundle:包名/模块名/路径/页面文件名(不加.ets)
})
})
}
}
}
六、运行调试配置
多个 HSP 模块需要一起编译才能运行。在 DevEco Studio 中:
markdown
1. 点击顶部工具栏的运行配置下拉框
2. 选择 Edit Configurations...
3. 在 Deploy Multi Hap 标签页 → 勾选:
☑ entry
☑ home (HSP)
☑ message (HSP)
☑ mine (HSP)
4. 点击 OK
5. 点击 Run 按钮
七、完整实践示例(创建 3 个 Feature HSP)
假设项目需求是三个 Tab 页面:首页、消息、我的。
第一步:创建目录与模块
bash
# 在工程根目录执行(或通过 DevEco Studio GUI 操作)
mkdir features
# 通过 DevEco Studio 在 features 下创建三个 Shared Library 模块
# → 名为 home、message、mine
第二步:各模块编写代码
bash
features/
├── home/
│ ├── index.ets ← export { HomeViewModel, HomePage }
│ └── src/main/ets/
│ ├── model/HomeData.ets
│ ├── viewmodel/HomeViewModel.ets
│ └── view/HomePage.ets
│
├── message/
│ ├── index.ets ← export { MessageViewModel, MessagePage }
│ └── src/main/ets/
│ ├── model/MessageItem.ets
│ ├── viewmodel/MessageViewModel.ets
│ └── view/MessagePage.ets
│
└── mine/
├── index.ets ← export { MineViewModel, MinePage }
└── src/main/ets/
├── model/UserInfo.ets
├── viewmodel/MineViewModel.ets
└── view/MinePage.ets
第三步:Entry 模块组合所有 Feature
typescript
// entry/src/main/ets/pages/MainTabs.ets
import { HomePage } from '@hm/home'
import { MessagePage } from '@hm/message'
import { MinePage } from '@hm/mine'
@Entry
@ComponentV2
struct MainTabs {
@Local currentIndex: number = 0
@Builder
TabBuilder(index: number) {
Tabs({ index: this.currentIndex }) {
TabContent() { HomePage() }
.tabBar('首页')
TabContent() { MessagePage() }
.tabBar('消息')
TabContent() { MinePage() }
.tabBar('我的')
}
}
build() {
this.TabBuilder(0)
}
}
八、关键约束(务必注意)
| 约束 | 说明 |
|---|---|
| 不能单独运行 HSP | HSP 必须跟随 HAP 一起安装运行,不能独立部署到设备 12 |
| 不能声明 Ability | HSP 不支持在 module.json5 中声明 UIAbility 或 ExtensionAbility |
| 版本号一致 | HSP 的 versionName / versionCode 必须与宿主 HAP 严格一致 |
| 不支持循环依赖 | A 依赖 B,B 就不能再依赖 A |
| 不支持依赖传递 | A 依赖 B,B 依赖 C → A 不能直接使用 C 的接口 |
| API 版本要求 | HSP 及其使用方都必须是 API 10+ 的 Stage 模型 |
| 只支持模块化编译 | 所有相关模块都必须开启 modularize 编译模式 |
九、总结
在 features 下创建多个 HSP 的本质就是: 对 features 目录反复执行「右键 → New → Module → Shared Library」,每执行一次就多一个 HSP 模块。然后通过
oh-package.json5把依赖关系串起来,通过各自的index.ets控制对外暴露的接口。
这套流程不复杂,但需要记住三个关键点:
- 模板选 Shared Library(不是 Static Library)
- 依赖只向下(entry → features → common)
- index.ets 守好门(只导出该暴露的,不泄露实现细节)