DEV Community

Cover image for HarmonyOS Private Repository Construction Practice
kouwei qing
kouwei qing

Posted on

HarmonyOS Private Repository Construction Practice

HarmonyOS Private Repository Construction Practice

Background

In Android and iOS development, dependencies and collaboration often rely on binary artifacts. Android uses Maven as the repository, while iOS uses CocoaPods. Developers can leverage open-source libraries on official platforms, significantly improving development efficiency. However, some company-specific business libraries are not intended for external use, making it unsafe to upload them to public repositories. Many companies build internal private repositories, which enhance security and accelerate artifact management.

HarmonyOS faces similar challenges. While developers can easily use third-party artifacts from official repositories, internal business dependencies require private repositories. This article describes how to build a private repository using official tools.

Introduction to HarmonyOS Shared Packages

HarmonyOS shared packages are categorized into static and dynamic types:

  • HAR (Harmony Archive): A static shared package containing code, C++ libraries, resources, and configuration files. HAR enables multiple modules or projects to share ArkUI components, resources, and related code. Unlike HAP, HAR cannot be independently installed or run on devices and can only be referenced as a dependency of application modules.
  • HSP (Harmony Shared Package): A dynamic shared package. Static shared packages are packaged into each dependent HAP, leading to larger package sizes and duplicate resources/code. Dynamic shared packages allow multiple HAPs to share common resources and code. HSP only supports in-application sharing, not cross-application sharing.

Building a Private Repository with ohpm-repo

The official ohpm-repo tool helps developers quickly set up a lightweight ohpm private repository, compatible with the ohpm package manager. It caches dependencies on demand to accelerate installations in private networks.

ohpm-repo supports single-point and multi-instance deployments:

  • Single-point deployment: ohpm-repo runs on a single machine.
  • Multi-instance deployment: ohpm-repo is deployed across multiple machines with identical configurations and shared data storage.

Dependent Environment Installation

  1. ohpm-repo relies on Node.js (version 16.x or higher). Install Node.js and configure the environment. Download Node.js from the official website (https://nodejs.org/download/release/latest/).

Downloading ohpm-repo

  1. Download the ohpm-repo tool from: https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/ide-software-download-0000001507075446
  2. Unzip the ohpm-repo package.

Configuring ohpm-repo Environment Variables

  1. Add the path to the bin directory in the unzipped ohpm-repo package to the system environment variable PATH: export PATH=$OHPM-REPO-PATH/bin:$PATH
  2. Verify the installation by running ohpm-repo -v to check the version.

Configuring the ohpm-repo Service Configuration File

Go to the conf directory in the unzipped package and open config.yaml. The default configuration is as follows:

##### server configuration section #####
listen: 0.0.0.0:8088
# listen:
# - localhost:8088            # 监听本机环回地址
# - http://localhost:8088     # 监听本机环回地址
# - 0.0.0.0:8088              # 监听本机所有地址 (INADDR_ANY)
# 协议可配置 http 或者 https,默认为 http
# port: 1-65535(Windows系统)/ 1024-65535(Linux或Mac系统)

# 可选 (listen 为 https 协议时必须配置)
https_key: ''                 # https 服务使用的 key 的路径  (不配置默认为'')
https_cert: ''                # https 服务使用的 crt 的路径  (不配置默认为'')

##### server deploy root section #####
deploy_root: ''                # 安装根目录 (不配置默认为 `<现有用户home目录>/ohpm-repo`),只支持绝对路径,且路径目录必须存在

##### server numeric limit section #####
max_package_size: 100          # 上传包大小限制,单位是MB (0, 100],不配置默认为 100
max_extract_size: 500          # 压缩包解压后大小限制,单位是MB [max_package_size, 500],不配置默认为 500
max_extract_file_num: 10240    # 压缩包解压后文件个数限制 (0, 102400],不配置默认为 10240
user_rate_limit: 100           # 用户访问频率控制,单位是次/s (0, 10000],不配置默认为 100
fetch_timeout: 60              # 请求/响应的超时时间,单位是秒 (0, 3600],不配置默认为 60
keep_alive_timeout: 60         # TCP 保持连接的超时时间,单位是秒 (0, 3600],不配置默认为 60
api_timeout: 60                # api超时时间,单位是秒(0, 3600],不配置默认为 60
upload_lock_hour: 24           # 下架某一三方包所有版本后,限时禁止同名三方包上传,单位是小时 (0, 168],不配置,默认为 24
upload_max_times: 100          # 单用户24小时内上传次数限制 (0, 10000],不配置默认为 100

##### metadata storage section #####
## 数据存储类型 filedb 和 mysql 二选一,不可都配置
db:                         # 必须用 yaml 数组形式写法
  type: filedb
  config:                   # 如果想修改存储路径且保留旧的数据,则需要把旧路径下的数据文件迁移至新路径
    path: ./db              # 本地数据存储路径,不配置默认为<deploy_root>/db;

#db:                        # 必须用yaml数组形式写法
#  type: mysql
#  config:
#    host: "localhost"      # 数据库主机地址
#    port: 3306             # 数据库端口 (0,65535]
#    username: root         # 数据库的用户名
#    password: "password"   # 数据库的用户密码(请配置明文, 最终在部署目录中会转换为密文)
#    database: "repo"       # 数据库名

##### storage section #####
## 文件存储类型fs,sftp 和 custom 三选一,不可多选。

store:                               # 必须用 yaml 数组形式写法
  type: fs
  config:                            # 上传资源后如若要修改存储路径,则需要把旧路径下的数据迁移至新路径中
    path: ./storage                  # 已上架三方库存储路径,不配置默认为 <deploy_root>/storage;
    #server: http://localhost:8088   # 三方库下载链接,不配置默认取值

# 文件存储类型为 sftp 时,最多配置三个 sftp服务
#store:                               # 必须用 yaml 数组形式写法
#  type: sftp                         # 当且仅当 db 的类型为 mysql 时,store 的类型才能为 sftp
#  config:
#    location:
#      -
#        name: test_one_sftp          # 主机名字,名字不能与其他sftp配置重复
#        host: "localhost"            # 主机地址
#        port: 22                     # 主机端口 (0,65535]
#        read_username: "read"        # 主机有读权限的用户名字
#        read_password: "password"    # 主机有读权限的用户密码(请配置明文, 最终在部署目录中会转换为密文)
#        write_username: "write"      # 主机有写权限的用户名字
#        write_password: "password"   # 主机有写权限的用户密码(请配置明文, 最终在部署目录中会转换为密文)
#        path: /source22              # 相对 sftp 根目录的文件路径,仅限/开头,且路径文件夹必须存在
#      -
#        name: test_two_sftp
#        host: "localhost"
#        port: 24
#        read_username: "read"
#        read_password: "password"
#        write_username: "write"
#        write_password: "password"
#        path: /source24
#    #server: http://localhost:8088   # 本地仓库下载链接地址,不配置默认取 listen 的值、

#store:
#  type: custom                                            # custom是自定义存储插件类型,自定义存储插件开发流程见指导文档
#  config:
#    export_name: CustomStorage                            # 插件export的类名
#    plugin_path: ../plugins/CustomStorage.js              # 插件的绝对路径或者相对于ohpm-repo软件包的路径,建议将插件放在软件包的plugins目录下
#    custom_field: "test"                                  # 自定义字段,通过引入libs/common/getStorageConfigInfo.js的getStorageConfigInfo方法获取自定义字段的值
#    #server: http://localhost:8088                        # 本地仓库下载链接地址,不配置默认取listen的值
##### uplink section #####
uplink_cache_path: ./uplink      # 缓存路径,不配置默认为 <deploy_root>/uplink
uplink_cache_time: 168           # 远程包 metadata 缓存时间,单位为小时,默认 168 小时,取值范围为 (0, 8760]

##### log section #####
logs_path: ./logs                # 日志路径,不配置默认为 <deploy_root>/logs

##### log level section #####
# 日志级别: 级别由低到高分别是 all、trace、debug、info、warn、error、fatal、mark、off
# run,operate 和 access 不配置或者配置错误,默认为 info
loglevel_run: info
loglevel_operate: info
loglevel_access: info
Enter fullscreen mode Exit fullscreen mode

The configuration includes listening ports, HTTPS settings, private repository deployment directory deploy_root, server configurations, storage settings db, logs, etc. Configure them according to actual needs.

Storage module notes:

  • db configures metadata storage, supporting fileDB (local) or MySQL.
  • store configures file storage, supporting local storage, SFTP storage, or custom plugin storage.

How to modify the configuration file after the private repository starts successfully:

  • If the configuration file was specified during the first startup with the install command: Modify the specified configuration file, then re-run install with the updated file and start the repository.
  • If no configuration file was specified during the first startup: Modify the configuration file in the conf directory of the unzipped package, then re-run install and start.

Installation and Startup

Run ohpm-repo install to install. After installation, configure environment variables as needed, then start the service with ohpm-repo start.

Using Private Repository Shared Packages

By default, the ohpm client pulls dependencies only from the official public repository. To pull from a private repository, use one of the following configurations:

  1. Configure the private repository for all projects: ohpm config set registry <private_repo_address>/repos/ohpm
  2. Configure for a specific dependency installation: ohpm install @ohos/lottie --registry <private_repo_address>/repos/ohpm

The private_repo_address is the store.config.server address in the configuration file. For example, if store.config.server is http://127.0.0.1:8088, the registry is http://127.0.0.1:8088/repos/ohpm. If store.config.server is not configured, use the default value.

Publishing Shared Packages

Local shared packages (both static and dynamic) can be published via ohpm commands or a web interface. Command-line publishing is typically preferred for efficiency:

  1. Generate an SSH key locally: ssh-keygen -m PEM -t RSA -b 4096 -f <your_key_path>
  2. Log in to the ohpm-repo management interface, go to Profile, add a public key, and paste the content of <your_key_path>.pub.
  3. Set the private key path: ohpm config set key_path <your_key_path>
  4. Log in to the ohpm-repo management interface, copy the publish ID from Profile.
  5. Configure the publish ID in .ohpmrc: ohpm config set publish_id <your_publish_id>
  6. Publish a static shared library: ohpm publish demo.har
  7. Publish a dynamic shared package: ohpm publish demo.tgz
    • HSP packages cannot be published directly; convert them to .tgz first.
    • Switch to release mode during compilation to generate .tgz packages.

Module Configuration

In the library module (at the same level as the src folder), add the following files:

  • README.md: Must include package introduction and usage. Add detailed descriptions as needed.
  • CHANGELOG.md: Record version updates for the HAR.
  • LICENSE: License file.

The README.md is displayed on the private repository web platform, so clear documentation is essential.

oh_package.json5 configuration example:

{  
    "parameterFile": "../dependencies.json5",  
    "keywords": [  
        "asr"  
    ],  
    "name": "@xx/base-asr",  
    "version": "1.0.0-rc.9",  
    "repository": "http://gerrit.google.com/mobile_harmony/base_asr",  
    "description": "asr sdk",  
    "main": "Index.ets",  
    "author": "qingkouwei",  
    "license": "Apache-2.0",  
    "dependencies": {  

    }  
}
Enter fullscreen mode Exit fullscreen mode

Module name, version, and description must meet requirements; otherwise, uploads will fail. Version numbers must increase sequentially (unlike Android's SNAPSHOT overwrite capability).

Best Practices

In practical development, projects with multiple SDKs may require frequent uploads to the private repository for debugging. Manually compiling and uploading each SDK is tedious, especially when SDKs have dependencies.

The optimal solution is to use scripts for one-click compilation, upload, and dependency-ordered publishing:

  1. Create version.json5 to store SDK versions:
{  
  "project": {  
    "sdk_version": "1.1.0-rc.1",  
  }  
}
Enter fullscreen mode Exit fullscreen mode
  1. Automatic packaging script:
def run_commands(modulename, productname):  
    hvigor_home = '/Applications/DevEco-Studio.app/Contents/tools/hvigor'  

    # 打包命令
    command1 = 'node %s/bin/hvigorw.js --mode module -p product=default -p module=%s@default -p buildMode=debug assembleHar --analyze --parallel --incremental --daemon' %(hvigor_home,modulename)  

    # 等待第一个命令执行完成  
    process1.wait()  

    # 上传命令  
    ohpm publish productname
    process2.wait()
Enter fullscreen mode Exit fullscreen mode
  1. Automatic version update script:
def changeVersionAModule():  
    with open('version.json5', 'r') as f:  
        data = json5.load(f)  
        versionName = data['project']['sdk_version']  

        with open('AModule/oh-package.json5', 'r') as f:  
            aData = json5.load(f)  
            aData['version'] = versionName  
            with open('AModule/oh-package.json5', 'w') as f:  
                json.dump(aData, f, indent=4)  

        with open('dependencies.json5', 'r') as depf:  
            depData = json5.load(depf)  
            depData['version_base']['base-a'] = versionName  
            with open('dependencies.json5', 'w') as depf:  
                json.dump(depData, depf, indent=4)
Enter fullscreen mode Exit fullscreen mode

Summary

This article introduces the construction of HarmonyOS private repositories, the dependency and publishing process for shared packages, and best practices for one-click packaging/uploading in complex module dependency scenarios.

References

Top comments (0)