如何在一个features下面创建多个HSP?

16 阅读4分钟

一、核心结论:逐个创建,统一管理

features/ 目录本质上只是一个普通的文件夹,它不像 entry 那样有特殊的系统含义。创建多个 HSP 的方式就是逐个在 features 目录下创建 Shared Library 模块,然后通过 oh-package.json5 管理它们之间的依赖关系。


二、创建步骤(DevEco Studio 操作)

步骤 1:创建 features 目录

在工程根目录下,新建一个名为 features 的空文件夹:

MyApp/
├── entry/           ← 已有的 Entry 模块
├── features/        ← 手动创建的空文件夹(右键 → New → Directory)
└── ...

步骤 2:逐个创建 HSP 模块

操作入口(任选其一):

  • 方法 A:鼠标移到 features 目录上 → 右键 → NewModule
  • 方法 B:菜单栏 → FileNewModule

在弹出的创建向导中:

┌──────────────────────────────────────────┐
│  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/ 目录重复上述操作,逐个创建:

右键 features → NewModuleShared Library → 输入「message」→ Finish
右键 features → NewModuleShared Library → 输入「mine」    → Finish
右键 features → NewModuleShared Library → 输入「search」  → Finish

步骤 4:验证结果

完成后,工程目录应如下:

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 声明谁来依赖谁。

典型依赖配置

entry → features/home
entry → features/message
entry → features/mine
features/home → common/uicomponents
features/message → common/network
// 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"
  }
}
// features/home/oh-package.json5 — feature 依赖公共层
{
  "name": "@hm/home",
  "dependencies": {
    "@hm/uicomponents": "file:../../common/uicomponents"
  }
}
// features/message/oh-package.json5
{
  "name": "@hm/message",
  "dependencies": {
    "@hm/network": "file:../../common/network"
  }
}

添加依赖的操作方式

在 DevEco Studio 中,编辑完 oh-package.json5 后,把鼠标放在报错处会弹出提示,点击 Run 'ohpm install' 即可自动完成依赖映射。


四、每个 HSP 模块的内部结构

创建完模块后,需要按 MVVM 分层组织内部代码:

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 — 统一对外出口

// 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 的接口

// 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 中:

1. 点击顶部工具栏的运行配置下拉框
2. 选择 Edit Configurations...
3. 在 Deploy Multi Hap 标签页 → 勾选:
   ☑ entry
   ☑ home (HSP)
   ☑ message (HSP)
   ☑ mine (HSP)
4. 点击 OK
5. 点击 Run 按钮

七、完整实践示例(创建 3 个 Feature HSP)

假设项目需求是三个 Tab 页面:首页、消息、我的。

第一步:创建目录与模块

# 在工程根目录执行(或通过 DevEco Studio GUI 操作)
mkdir features

# 通过 DevEco Studio 在 features 下创建三个 Shared Library 模块
# → 名为 home、message、mine

第二步:各模块编写代码

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

// 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)
  }
}

八、关键约束(务必注意)

约束说明
不能单独运行 HSPHSP 必须跟随 HAP 一起安装运行,不能独立部署到设备 12
不能声明 AbilityHSP 不支持在 module.json5 中声明 UIAbilityExtensionAbility
版本号一致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 控制对外暴露的接口。

这套流程不复杂,但需要记住三个关键点:

  1. 模板选 Shared Library(不是 Static Library)
  2. 依赖只向下(entry → features → common)
  3. index.ets 守好门(只导出该暴露的,不泄露实现细节)