在这里插入图片描述

每日一句正能量

最高级的养生,不在于昂贵补品或剧烈运动,而在于少虑、少怨、少悔。
不为未发生的事过度焦虑。不对已发生的不公反复抱怨。不让过去的错误持续消耗当下。身体的损耗,大多源于内心的消耗。情绪干净了,身体自然通透。

摘要

在 HarmonyOS 应用开发的规模化进程中,组件库的封装与发布是实现代码复用、提升团队协作效率、构建技术生态的关键环节。本文系统梳理 HAR(Harmony Archive)与 HSP(Harmony Shared Package)两种共享包的技术差异与选型策略,深入讲解组件库的标准目录结构、封装规范与导出约定,详细演示从组件开发、oh-package.json5 配置、必备文件准备到 OHPM 中心仓发布的完整流程。结合语义化版本管理、多环境发布策略与 CI/CD 自动化流水线,提供一套可复制、可落地的企业级组件库治理方案,助力开发者从"写代码"迈向"建生态"。


一、组件库封装的技术背景与核心价值

1.1 为什么需要组件库

在前序文章(第一百七十八至一百八十篇)中,我们深入探讨了插槽机制、渲染控制与组件复用等 ArkUI 核心技术。这些技术解决的是"单个应用内部"的组件化问题,但当团队规模扩大、项目数量增多时,跨项目、跨团队的代码复用需求便浮出水面。每个项目重复编写相同的按钮组件、网络请求封装、主题配置,不仅造成严重的资源浪费,更导致不同项目的 UI 风格割裂、技术债务累积。

组件库的本质是将高频复用的代码、资源、配置沉淀为标准化的共享包,通过依赖管理工具(OHPM)分发到各个项目中。它实现了三个层面的价值跃迁:

  • 代码层面:消除重复代码,统一技术实现标准
  • 设计层面:保障跨项目 UI/UX 一致性,维护品牌视觉规范
  • 生态层面:将内部能力对外开放,构建技术影响力与开发者生态

1.2 HarmonyOS 共享包体系概览

HarmonyOS 提供了两种共享包机制,分别对应不同的复用层级与发布范围:

维度 HAR(Harmony Archive) HSP(Harmony Shared Package)
加载方式 编译时静态拷贝 运行时动态加载
发布范围 中心仓 / 私仓 / 本地文件 仅限应用内,随 App 一起发布
状态共享 各模块实例独立 全局共享同一实例
包体积影响 多模块引用导致多份拷贝 运行时仅一份,显著减小体积
pages 声明 不支持(可用命名路由) 支持
适用场景 三方库、二方库、工具类 应用内公共模块、状态共享

二、HAR 与 HSP 选型决策

2.1 选型决策树

在这里插入图片描述

选型口诀:对外发布用 HAR,内部共享用 HSP;要共享状态用 HSP,纯工具类用 HAR。

选择 HAR 的场景

  • 需要发布到 OpenHarmony 三方库中心仓,供全网开发者使用
  • 需要发布到公司内部的 OHPM 私仓,供团队内其他应用依赖
  • 封装的是纯工具类、UI 组件库,不涉及跨模块状态共享
  • 需要被多个独立应用引用,每个应用拥有独立的组件实例

选择 HSP 的场景

  • 应用内多个 HAP 模块需要共享同一份代码和资源
  • 需要跨模块共享状态(如全局主题、用户会话)
  • 关注应用包体积,希望避免 HAR 多份拷贝导致的膨胀
  • 功能模块按需加载(动态特性模块)

2.2 规格能力对比

规格能力 HAP HAR HSP
声明 UIAbility / ExtensionAbility
声明 pages 页面 ✗(可用命名路由)
包含资源文件与 .so 文件
依赖其他 HAR
依赖其他 HSP
独立安装运行
发布到 OHPM 中心仓

重要约束:HAR 不支持引用 AppScope 目录中的资源,编译时 AppScope 内容不会打包到 HAR 中;HAR 不支持循环依赖,也不支持依赖传递。


三、组件库封装规范与目录结构

3.1 标准目录结构设计

一个规范的企业级组件库应具备清晰的目录层次,便于维护、扩展和按需引入。

在这里插入图片描述

@myorg/harmony-ui-kit/                    # 组件库根目录
├── src/main/ets/
│   ├── components/                        # UI 组件目录
│   │   ├── Button/
│   │   │   ├── MyButton.ets             # 按钮组件实现
│   │   │   └── MyButtonModel.ets        # 按钮数据模型
│   │   ├── Card/
│   │   │   ├── MyCard.ets
│   │   │   └── MyCardTypes.ets
│   │   ├── Input/
│   │   │   └── MyInput.ets
│   │   └── List/
│   │       └── MyList.ets
│   ├── utils/                             # 工具函数
│   │   ├── DateUtil.ets
│   │   ├── Network.ets
│   │   └── Validator.ets
│   ├── themes/                            # 主题配置
│   │   ├── Colors.ets
│   │   ├── Typography.ets
│   │   └── Spacing.ets
│   └── Index.ets                          # 统一出口文件
├── src/main/resources/
│   └── base/
│       ├── media/                         # 图标、图片资源
│       ├── string/                        # 多语言文本
│       └── color/                         # 颜色资源
├── oh-package.json5                       # 包元数据配置
├── module.json5                           # 模块配置
├── build-profile.json5                    # 编译构建配置
├── README.md                              # 使用文档(必填)
├── CHANGELOG.md                           # 版本变更记录(必填)
└── LICENSE                                # 开源协议(必填)

3.2 统一导出规范(Index.ets)

组件库必须提供统一的出口文件,遵循"按需导入、命名清晰"的原则:

// src/main/ets/Index.ets
// UI 组件导出
export { MyButton } from './components/Button/MyButton'
export { MyButtonModel } from './components/Button/MyButtonModel'
export { MyCard } from './components/Card/MyCard'
export { MyCardProps } from './components/Card/MyCardTypes'
export { MyInput } from './components/Input/MyInput'
export { MyList } from './components/List/MyList'

// 工具函数导出
export { DateUtil } from './utils/DateUtil'
export { NetworkClient } from './utils/Network'
export { FormValidator } from './utils/Validator'

// 主题配置导出
export { ThemeColors } from './themes/Colors'
export { ThemeTypography } from './themes/Typography'
export { ThemeSpacing } from './themes/Spacing'

3.3 命名约定与代码规范

规范项 推荐做法 示例
包名 @组织名/包名 格式 @myorg/ui-kit
组件名 PascalCase,带组织前缀避免冲突 MyButtonMyCard
模型名 PascalCase + 后缀 ArticleModelUserProfile
工具函数 camelCase,语义化命名 formatDate()validatePhone()
主题常量 UPPER_SNAKE_CASE PRIMARY_COLORFONT_SIZE_LARGE
资源文件 小写 + 下划线分隔 ic_button_primary.png

四、oh-package.json5 配置详解

oh-package.json5 是组件库的"身份证",包含了包的元数据、入口文件、依赖关系等关键信息。以下是一个生产级组件库的完整配置示例:

{
  "name": "@myorg/harmony-ui-kit",
  "version": "1.2.0",
  "description": "企业级 HarmonyOS UI 组件库,提供按钮、卡片、输入框、列表等高频组件及主题系统",
  "main": "src/main/ets/Index.ets",
  "author": "MyOrg Tech Team <tech@myorg.com>",
  "license": "Apache-2.0",
  "keywords": [
    "harmonyos",
    "arkui",
    "ui-components",
    "design-system"
  ],
  "homepage": "https://github.com/myorg/harmony-ui-kit",
  "repository": {
    "type": "git",
    "url": "https://github.com/myorg/harmony-ui-kit.git"
  },
  "bugs": {
    "url": "https://github.com/myorg/harmony-ui-kit/issues"
  },
  "engines": {
    "harmony": ">=5.0.0"
  },
  "dependencies": {
    "@ohos/lottie": "^2.0.0",
    "@ohos/pulltorefresh": "^1.1.0"
  },
  "devDependencies": {
    "@types/node": "^20.0.0"
  },
  "types": "src/main/ets/Index.d.ts",
  "files": [
    "src/main/ets/**",
    "src/main/resources/**",
    "README.md",
    "CHANGELOG.md",
    "LICENSE"
  ]
}

必填字段说明

字段 说明 注意事项
name 包唯一标识 遵循 @组织名/包名 格式,全局唯一
version 语义化版本号 格式 MAJOR.MINOR.PATCH,发布后不可修改
main 入口文件路径 指向 Index.ets 统一出口
license 开源协议 推荐 Apache-2.0MIT,需与 LICENSE 文件一致

关键约束:所有直接依赖必须在模块级 oh-package.json5 中声明完整,不能依赖工程级配置。否则外部项目引用时会出现依赖缺失错误。


五、组件库实战:封装企业级 UI 组件库

5.1 创建库模块

在 DevEco Studio 中,通过 File > New > Module > Static Library 创建 HAR 模块。若需创建 HSP,则选择 Shared Library

5.2 封装核心组件

以下是一个遵循插槽机制与渲染控制最佳实践的按钮组件封装示例:

// src/main/ets/components/Button/MyButton.ets
@Component
export struct MyButton {
  // 按钮类型
  @Prop type: 'primary' | 'secondary' | 'danger' | 'ghost' = 'primary'
  // 按钮尺寸
  @Prop size: 'small' | 'medium' | 'large' = 'medium'
  // 是否禁用
  @Prop disabled: boolean = false
  // 是否加载中
  @Prop loading: boolean = false
  // 按钮文本
  @Prop text: string = ''
  // 点击回调
  onClick?: () => void

  // 插槽:自定义内容(优先级高于 text)
  @Builder
  defaultContent() {
    if (this.loading) {
      Row({ space: 6 }) {
        LoadingProgress()
          .width(16)
          .height(16)
          .color(this.getTextColor())
        Text('加载中...')
          .fontSize(this.getFontSize())
          .fontColor(this.getTextColor())
      }
    } else {
      Text(this.text)
        .fontSize(this.getFontSize())
        .fontColor(this.getTextColor())
        .fontWeight(FontWeight.Medium)
    }
  }

  @BuilderParam contentBuilder: () => void = this.defaultContent

  private getBgColor(): ResourceColor {
    if (this.disabled) return '#E0E0E0'
    switch (this.type) {
      case 'primary': return '#1976D2'
      case 'secondary': return '#E3F2FD'
      case 'danger': return '#F44336'
      case 'ghost': return 'transparent'
      default: return '#1976D2'
    }
  }

  private getTextColor(): ResourceColor {
    if (this.disabled) return '#9E9E9E'
    switch (this.type) {
      case 'primary': return Color.White
      case 'secondary': return '#1976D2'
      case 'danger': return Color.White
      case 'ghost': return '#1976D2'
      default: return Color.White
    }
  }

  private getFontSize(): number {
    switch (this.size) {
      case 'small': return 12
      case 'medium': return 14
      case 'large': return 16
      default: return 14
    }
  }

  private getHeight(): number {
    switch (this.size) {
      case 'small': return 28
      case 'medium': return 36
      case 'large': return 44
      default: return 36
    }
  }

  build() {
    Button() {
      this.contentBuilder()
    }
    .width('100%')
    .height(this.getHeight())
    .backgroundColor(this.getBgColor())
    .enabled(!this.disabled && !this.loading)
    .onClick(() => {
      if (this.onClick && !this.loading) {
        this.onClick()
      }
    })
  }
}

5.3 主题系统设计

组件库应提供统一的主题系统,支持颜色、字体、间距的集中管理,并预留扩展接口:

// src/main/ets/themes/Colors.ets
export class ThemeColors {
  // 品牌色
  static readonly PRIMARY: ResourceColor = '#1976D2'
  static readonly PRIMARY_LIGHT: ResourceColor = '#E3F2FD'
  static readonly PRIMARY_DARK: ResourceColor = '#0D47A1'

  // 功能色
  static readonly SUCCESS: ResourceColor = '#4CAF50'
  static readonly WARNING: ResourceColor = '#FF9800'
  static readonly ERROR: ResourceColor = '#F44336'
  static readonly INFO: ResourceColor = '#2196F3'

  // 中性色
  static readonly TEXT_PRIMARY: ResourceColor = '#212121'
  static readonly TEXT_SECONDARY: ResourceColor = '#757575'
  static readonly TEXT_DISABLED: ResourceColor = '#BDBDBD'
  static readonly BORDER: ResourceColor = '#E0E0E0'
  static readonly BACKGROUND: ResourceColor = '#F5F5F5'
  static readonly SURFACE: ResourceColor = '#FFFFFF'

  // 暗黑模式适配(预留)
  static readonly DARK_BACKGROUND: ResourceColor = '#121212'
  static readonly DARK_SURFACE: ResourceColor = '#1E1E1E'
  static readonly DARK_TEXT_PRIMARY: ResourceColor = '#FFFFFF'
}

// src/main/ets/themes/Spacing.ets
export class ThemeSpacing {
  static readonly XS: number = 4
  static readonly SM: number = 8
  static readonly MD: number = 16
  static readonly LG: number = 24
  static readonly XL: number = 32
  static readonly XXL: number = 48
}

六、发布到 OHPM 中心仓的完整流程

6.1 发布流程全景

在这里插入图片描述

6.2 步骤详解

步骤一:账号与组织准备

前往 OpenHarmony 三方库中心仓(ohpm.openharmony.cn)注册账号并完成实名认证。若需以组织名义发布,在"组织管理"中新增组织,包名需遵循 @组织名/包名 格式。

步骤二:生成并配置密钥

OHPM 使用 RSA 公私钥校验发布权限,仅支持 PEM 格式。生成密钥时必须输入密码(密码不能为空):

# 生成 4096 位 RSA 密钥对
ssh-keygen -m PEM -t RSA -b 4096 -f ~/.ssh_ohpm/mykey

# 配置私钥路径
ohpm config set key_path ~/.ssh_ohpm/mykey

# 登录中心仓官网获取发布码,并配置
ohpm config set publish_id your_publish_id

步骤三:上传公钥

登录中心仓官网,进入「个人中心」-「认证管理」,新增 OHPM 公钥,将 mykey.pub 的内容粘贴保存。

步骤四:准备必备文件

库模块根目录下必须包含以下三个文件,且内容不能为空

  • README.md:包含包的介绍、安装命令和基本使用示例
  • CHANGELOG.md:填写每个版本的变更记录
  • LICENSE:真实的许可证全文(推荐 Apache-2.0)

步骤五:Release 模式构建

# 务必使用 Release 模式构建,避免 Debug 包中包含源码导致泄露
# 在 DevEco Studio 中:Build > Make Module <模块名>
# 或在命令行中:
hvigorw --mode module -p module=library@default -p product=default assembleHar

安全警告:请务必使用 Release 模式构建,避免使用 Debug 模式,因为 Debug 包中会含有源码,存在代码泄露风险。

步骤六:执行发布

# 发布 HAR 包
ohpm publish ./library/build/default/outputs/default/library.har

# 发布时需输入生成密钥时设置的密码

步骤七:等待审核

发布成功后,中心仓会发送"创建上架审核单成功"通知。审核通过后,其他开发者即可通过 ohpm install @myorg/harmony-ui-kit 安装使用。

6.3 发布到私有仓库

对于企业内部组件库,可搭建 OHPM 私仓(基于 Verdaccio)进行发布:

# 1. 搭建 Verdaccio 私仓
npm i -g verdaccio
verdaccio

# 2. 配置私有 registry
ohpm config set registry http://localhost:4873

# 3. 登录私仓
ohpm login

# 4. 发布
ohpm publish ./library.har

七、版本管理与迭代策略

7.1 语义化版本规范

组件库的版本号必须遵循语义化版本(Semantic Versioning)规范:MAJOR.MINOR.PATCH

版本位 递增条件 示例
MAJOR 存在不兼容的 API 变更 1.x.x2.0.0
MINOR 新增向下兼容的功能 1.1.x1.2.0
PATCH 修复向下兼容的问题 1.1.11.1.2

关键约束:版本号一旦发布并审核通过,该特定名称及版本号将被永久占用,无法再次使用。后续迭代必须递增版本号。

7.2 版本迭代流程

在这里插入图片描述

v1.0.0  →  初始发布,包含基础组件
v1.1.0  →  新增 MyTable 组件,新增暗黑模式支持
v1.1.1  →  修复 MyButton 在 disabled 状态下的颜色异常
v1.2.0  →  新增 MyForm 表单组件,优化主题系统
v2.0.0  →  重构主题 API(Breaking Change),移除废弃组件

7.3 多环境发布策略

环境 发布目标 使用方式 适用阶段
开发环境 本地文件 ohpm install ./modules/shared 本地联调
测试环境 私有 Registry ohpm install @myorg/ui-kit@beta 集成测试
生产环境 OHPM 中心仓 ohpm install @myorg/ui-kit 正式发布

八、CI/CD 自动化发布流水线

8.1 GitLab CI 配置示例

# .gitlab-ci.yml
stages:
  - build
  - test
  - publish

variables:
  HAR_MODULE: "library"
  OHPM_REGISTRY: "https://ohpm.openharmony.cn"

# 编译阶段
build_har:
  stage: build
  image: harmonyos/build-env:latest
  script:
    - hvigorw --mode module -p module=$HAR_MODULE@default -p product=default assembleHar
  artifacts:
    paths:
      - library/build/default/outputs/default/*.har
    expire_in: 1 hour

# 测试阶段
unit_test:
  stage: test
  image: harmonyos/build-env:latest
  script:
    - ohpm install
    - hvigorw test
  only:
    - merge_requests
    - main

# 发布阶段(仅 main 分支且 tag 触发)
publish_ohpm:
  stage: publish
  image: harmonyos/build-env:latest
  script:
    - ohpm config set key_path $OHPM_KEY_PATH
    - ohpm config set publish_id $OHPM_PUBLISH_ID
    - ohpm publish library/build/default/outputs/default/library.har
  only:
    - tags
  when: manual  # 需要手动确认发布

8.2 GitHub Actions 配置示例

# .github/workflows/publish.yml
name: Publish to OHPM
on:
  push:
    tags:
      - 'v*'

jobs:
  publish:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      
      - name: Setup HarmonyOS SDK
        uses: harmonyos/setup-sdk@v1
        with:
          api-version: '12'
      
      - name: Install dependencies
        run: ohpm install
      
      - name: Build HAR (Release)
        run: |
          hvigorw --mode module -p module=library@default -p product=default assembleHar
      
      - name: Publish to OHPM
        env:
          OHPM_KEY_PATH: ${{ secrets.OHPM_KEY_PATH }}
          OHPM_PUBLISH_ID: ${{ secrets.OHPM_PUBLISH_ID }}
        run: |
          ohpm config set key_path $OHPM_KEY_PATH
          ohpm config set publish_id $OHPM_PUBLISH_ID
          ohpm publish library/build/default/outputs/default/library.har

九、最佳实践与避坑指南

9.1 十大最佳实践

  1. 统一命名空间:包名使用 @组织名/包名 格式,组件名带前缀避免全局冲突
  2. 完整依赖声明:所有直接依赖必须在模块级 oh-package.json5 中声明,不可依赖工程级配置
  3. Release 模式构建:发布前务必切换为 Release 模式,防止源码泄露
  4. 三文件必备:README.md、CHANGELOG.md、LICENSE 必须存在且内容非空
  5. 语义化版本:严格遵循 MAJOR.MINOR.PATCH 规范,版本号一旦发布不可复用
  6. 统一出口管理:通过 Index.ets 集中导出,避免外部直接引用内部文件路径
  7. 主题系统预留:组件库应提供主题配置接口,支持颜色、字体、间距的自定义
  8. 插槽机制应用:复杂组件预留 @BuilderParam 插槽,提升组件扩展性
  9. 性能优化内建:列表组件内置 @Reusable 标记,遵循渲染控制最佳实践
  10. 文档即代码:README 中提供完整的安装命令、使用示例和 API 说明

9.2 常见错误与解决方案

错误现象 根本原因 解决方案
ohpm install 找不到依赖 依赖仅在工程级声明 在模块级 oh-package.json5 中补全依赖
发布审核被拒 README/CHANGELOG/LICENSE 为空 补充完整内容后重新提交
HAR 中资源引用失败 引用了 AppScope 资源 HAR 不支持 AppScope,资源应放在模块内
多模块引用后包体积膨胀 使用 HAR 而非 HSP 应用内共享场景改用 HSP
版本号冲突无法发布 该版本已存在 递增版本号后重新发布
私钥密码错误 生成密钥时未输入密码 重新生成带密码的密钥对

十、总结

本文从 HarmonyOS 共享包体系出发,系统解析了 HAR 与 HSP 的技术差异与选型策略,深入讲解了组件库的标准目录结构、封装规范、oh-package.json5 配置及统一导出约定。通过完整的发布流程演示——从密钥生成、必备文件准备到 Release 模式构建与 OHPM 中心仓上架——帮助开发者掌握组件库从开发到生态共享的全链路技术。结合语义化版本管理、多环境发布策略与 CI/CD 自动化流水线,提供了一套可复制、可落地的企业级组件库治理方案。

组件库不仅是代码复用的载体,更是技术团队能力沉淀与生态影响力建设的核心抓手。掌握组件库封装与发布的完整技能链,是每一位 HarmonyOS 开发者从"写代码"迈向"建生态"的必经之路。


转载自:https://blog.csdn.net/u014727709/article/details/163540974
欢迎 👍点赞✍评论⭐收藏,欢迎指正

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐