跳转至

OpenHarmony 平台

使用 CCGO 为 OpenHarmony (OHOS) 构建 C++ 库的完整指南。

概述

CCGO 提供全面的 OpenHarmony 支持:

  • 多架构:ARMv7、ARM64、x86_64
  • 输出格式:HAR 包、静态库 (.a)、共享库 (.so)
  • 构建方式:本地构建 (DevEco Studio) 或 Docker(跨平台)
  • IDE 支持:DevEco Studio 项目生成
  • 发布:OHPM 仓库集成
  • ArkTS 集成:原生模块接口 (NAPI) 支持
  • API 兼容性:OpenHarmony 3.2+

前置条件

方式 1:本地构建(需要 OpenHarmony SDK)

安装 DevEco Studio:

  1. OpenHarmony 开发者门户 下载
  2. 通过 DevEco Studio 安装 OpenHarmony SDK
  3. 配置 SDK 路径

所需工具:

# 安装 Node.js(用于 OHPM)
# 从 nodejs.org 下载

# 安装 OHPM (OpenHarmony 包管理器)
npm install -g @ohos/hpm-cli

# 验证安装
node --version
ohpm --version

环境设置:

# 设置 OHOS SDK 路径
export OHOS_SDK_HOME="/path/to/ohos-sdk"
export PATH="$OHOS_SDK_HOME/native/build-tools/cmake/bin:$PATH"

# 验证
cmake --version

方式 2:Docker 构建(任意操作系统)

在任何操作系统上使用 Docker 构建 OpenHarmony 库。

所需条件: - 已安装并运行 Docker Desktop - 4GB+ 磁盘空间用于 Docker 镜像

优势: - 可在任何操作系统上构建 - 无需 DevEco Studio - 一致的构建环境 - 预配置的 OHOS SDK

限制: - 无法在 OpenHarmony 设备上运行 - 无法使用 DevEco Studio 集成 - 首次下载较大(~1.5GB 镜像)

详见 Docker 构建 部分。

快速开始

基础构建

# 为默认架构构建 (arm64-v8a)
ccgo build ohos

# 使用 Docker 构建(从任意操作系统交叉编译)
ccgo build ohos --docker

# 指定架构
ccgo build ohos --arch armeabi-v7a      # 32位 ARM
ccgo build ohos --arch arm64-v8a        # 64位 ARM(默认)
ccgo build ohos --arch x86_64           # x86_64 模拟器

# 构建多个架构
ccgo build ohos --arch armeabi-v7a,arm64-v8a,x86_64

# 构建类型
ccgo build ohos --build-type debug      # Debug 构建
ccgo build ohos --build-type release    # Release 构建(默认)

# 链接类型
ccgo build ohos --build-as static      # 仅静态库
ccgo build ohos --build-as shared      # 仅共享库
ccgo build ohos --build-as both        # 两种类型(默认)

# 生成 HAR 包
ccgo build ohos --har                   # 创建 .har 包

生成 DevEco Studio 项目

# 生成 DevEco Studio 项目
ccgo build ohos --ide-project

# 在 DevEco Studio 中打开
# 文件 -> 打开 -> cmake_build/ohos/

输出结构

默认输出 (target/ohos/)

target/ohos/
├── MyLib_OHOS_SDK-1.0.0.zip            # 主包
│   ├── lib/
│   │   ├── static/
│   │   │   ├── armeabi-v7a/
│   │   │   │   └── libmylib.a          # 32位 ARM 静态库
│   │   │   ├── arm64-v8a/
│   │   │   │   └── libmylib.a          # 64位 ARM 静态库
│   │   │   └── x86_64/
│   │   │       └── libmylib.a          # x86_64 静态库
│   │   └── shared/
│   │       ├── armeabi-v7a/
│   │       │   └── libmylib.so         # 32位 ARM 共享库
│   │       ├── arm64-v8a/
│   │       │   └── libmylib.so         # 64位 ARM 共享库
│   │       └── x86_64/
│   │           └── libmylib.so         # x86_64 共享库
│   ├── haars/
│   │   └── mylib-1.0.0.har             # HAR 包
│   ├── include/
│   │   └── mylib/                      # 头文件
│   │       ├── mylib.h
│   │       └── version.h
│   └── build_info.json                 # 构建元数据
└── MyLib_OHOS_SDK-1.0.0-SYMBOLS.zip    # 调试符号
    └── obj/
        ├── armeabi-v7a/
        │   └── libmylib.so             # 未剥离的库
        ├── arm64-v8a/
        │   └── libmylib.so
        └── x86_64/
            └── libmylib.so

HAR 包

HAR (Harmony Archive) 是 OpenHarmony 的库包格式:

结构:

mylib-1.0.0.har
├── libs/
│   ├── armeabi-v7a/
│   │   └── libmylib.so
│   ├── arm64-v8a/
│   │   └── libmylib.so
│   └── x86_64/
│       └── libmylib.so
├── include/
│   └── mylib/
│       ├── mylib.h
│       └── version.h
├── oh-package.json5               # 包元数据
└── module.json5                   # 模块配置

oh-package.json5:

{
  "name": "mylib",
  "version": "1.0.0",
  "description": "My OpenHarmony library",
  "main": "index.ets",
  "author": "Your Name",
  "license": "MIT",
  "dependencies": {},
  "devDependencies": {}
}

构建元数据

build_info.json 包含:

{
  "project": {
    "name": "MyLib",
    "version": "1.0.0",
    "description": "My OpenHarmony library"
  },
  "build": {
    "platform": "ohos",
    "architectures": ["armeabi-v7a", "arm64-v8a", "x86_64"],
    "build_type": "release",
    "link_types": ["static", "shared"],
    "timestamp": "2024-01-15T10:30:00Z",
    "ccgo_version": "0.1.0",
    "ohos_sdk_version": "10",
    "api_version": "10"
  },
  "outputs": {
    "libraries": {
      "static": {
        "armeabi-v7a": "lib/static/armeabi-v7a/libmylib.a",
        "arm64-v8a": "lib/static/arm64-v8a/libmylib.a",
        "x86_64": "lib/static/x86_64/libmylib.a"
      },
      "shared": {
        "armeabi-v7a": "lib/shared/armeabi-v7a/libmylib.so",
        "arm64-v8a": "lib/shared/arm64-v8a/libmylib.so",
        "x86_64": "lib/shared/x86_64/libmylib.so"
      }
    },
    "har": "haars/mylib-1.0.0.har",
    "headers": "include/mylib/"
  }
}

在 OpenHarmony 中使用库

在 ArkTS/eTS 应用中

1. 添加 HAR 依赖:

// oh-package.json5
{
  "dependencies": {
    "mylib": "file:../mylib-1.0.0.har"
  }
}

2. 创建原生模块包装器:

// src/native/mylib_napi.cpp
#include <napi/native_api.h>
#include <mylib/mylib.h>

static napi_value DoWork(napi_env env, napi_callback_info info) {
    mylib::MyClass obj;
    obj.do_work();

    napi_value result;
    napi_create_int32(env, 0, &result);
    return result;
}

EXTERN_C_START
static napi_value Init(napi_env env, napi_value exports) {
    napi_property_descriptor desc[] = {
        { "doWork", nullptr, DoWork, nullptr, nullptr, nullptr, napi_default, nullptr }
    };
    napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
    return exports;
}
EXTERN_C_END

static napi_module myLibModule = {
    .nm_version = 1,
    .nm_flags = 0,
    .nm_filename = nullptr,
    .nm_register_func = Init,
    .nm_modname = "mylib",
    .nm_priv = nullptr,
    .reserved = { 0 },
};

extern "C" __attribute__((constructor)) void RegisterMyLibModule() {
    napi_module_register(&myLibModule);
}

3. 在 ArkTS 中使用:

// src/main/ets/pages/Index.ets
import mylib from 'libmylib.so';

@Entry
@Component
struct Index {
  build() {
    Button('Do Work')
      .onClick(() => {
        mylib.doWork();
      })
  }
}

在 C++ 应用中

CMakeLists.txt:

# 链接静态库
target_link_libraries(myapp PRIVATE
    ${CMAKE_SOURCE_DIR}/libs/${OHOS_ARCH}/libmylib.a
)

target_include_directories(myapp PRIVATE
    ${CMAKE_SOURCE_DIR}/include
)

直接使用:

#include <mylib/mylib.h>

int main() {
    mylib::MyClass obj;
    obj.do_work();
    return 0;
}

Docker 构建

在任何操作系统上使用 Docker 构建 OpenHarmony 库:

前置条件

# 安装 Docker Desktop
# 下载地址:https://www.docker.com/products/docker-desktop/

# 验证 Docker 运行
docker ps

使用 Docker 构建

# 首次构建会下载预构建镜像(~1.5GB)
ccgo build ohos --docker

# 后续构建很快
ccgo build ohos --docker --arch arm64-v8a

# 所有标准选项都可用
ccgo build ohos --docker --arch armeabi-v7a,arm64-v8a --har

工作原理

  1. CCGO 使用 Docker Hub 的预构建 ccgo-builder-ohos 镜像
  2. 项目目录挂载到容器中
  3. 使用 OHOS SDK 和工具链构建
  4. 输出写入主机文件系统

限制

  • 无法运行:Docker 中没有 OpenHarmony 运行时
  • 无法测试:无法访问设备或模拟器
  • 无 DevEco Studio:无法生成 IDE 项目

发布到 OHPM

OHPM (OpenHarmony Package Manager) 是官方包仓库。

设置

# 登录 OHPM
ohpm login

# 配置仓库(如果使用私有仓库)
ohpm config set registry https://your-registry.com

发布

# 发布 HAR 到官方 OHPM 仓库
ccgo publish ohos --registry official

# 发布到私有仓库
ccgo publish ohos --registry private --url https://your-registry.com

# 跳过构建并发布现有 HAR
ccgo publish ohos --skip-build

包配置

确保 CCGO.toml 有正确的元数据:

[package]
name = "mylib"
version = "1.0.0"
description = "My OpenHarmony library"
authors = ["Your Name <your.email@example.com>"]
license = "MIT"
homepage = "https://github.com/yourusername/mylib"
repository = "https://github.com/yourusername/mylib"

[ohos]
min_api_version = 9
target_api_version = 10

平台配置

CCGO.toml 设置

[package]
name = "mylib"
version = "1.0.0"

[library]
type = "both"                      # static、shared 或 both

[build]
cpp_standard = "17"                # C++ 标准

[ohos]
min_api_version = 9                # 最低 API 版本
target_api_version = 10            # 目标 API 版本
compile_sdk_version = 10           # 编译 SDK 版本
ndk_version = "4.0.0"              # NDK 版本

CMake 变量

为 OpenHarmony 构建时:

${PLATFORM}                        # "ohos"
${OHOS_ARCH}                       # "armeabi-v7a"、"arm64-v8a" 或 "x86_64"
${BUILD_TYPE}                      # "Debug" 或 "Release"
${LINK_TYPE}                       # "static"、"shared" 或 "both"
${OHOS_API_VERSION}                # 目标 API 版本
${OHOS_SDK_HOME}                   # OHOS SDK 路径

条件编译

// 平台检测
#ifdef __OHOS__
    // OpenHarmony 特定代码
    #include <hilog/log.h>

    #ifdef __aarch64__
        // ARM64 特定代码
    #elif defined(__arm__)
        // ARMv7 特定代码
    #elif defined(__x86_64__)
        // x86_64 特定代码
    #endif
#endif

// API 版本检测
#if __OHOS_API_VERSION__ >= 10
    // API 10+ 特性
#else
    // 旧版 API 的回退
#endif

// 日志记录
#ifdef __OHOS__
    #define LOG_TAG "MyLib"
    #define LOG_INFO(fmt, ...) \
        OH_LOG_INFO(LOG_APP, fmt, ##__VA_ARGS__)
#else
    #define LOG_INFO(fmt, ...) \
        printf(fmt "\n", ##__VA_ARGS__)
#endif

最佳实践

1. 使用 HAR 包

将库打包为 HAR 以便轻松分发:

# 始终生成 HAR
ccgo build ohos --har

2. 支持多个架构

为所有常见架构构建:

# 构建所有架构
ccgo build ohos --arch armeabi-v7a,arm64-v8a,x86_64

3. 实现 NAPI 包装器

为 C++ 代码提供 ArkTS/eTS 绑定:

// 始终使用 NAPI 包装原生代码
static napi_value ExportFunction(napi_env env, napi_callback_info info) {
    // 实现
}

4. 使用 HiLog 进行日志记录

使用 OpenHarmony 的日志系统:

#include <hilog/log.h>

#define LOG_DOMAIN 0x0001
#define LOG_TAG "MyLib"

void log_message() {
    OH_LOG_INFO(LOG_APP, "Message from MyLib");
}

5. 处理 API 版本控制

在运行时检查 API 版本:

#include <parameter/system_parameter.h>

int get_api_version() {
    char value[32];
    int ret = GetParameter("const.ohos.apiversion", "", value, sizeof(value));
    if (ret > 0) {
        return atoi(value);
    }
    return 0;
}

6. 在真实设备上测试

始终在物理 OpenHarmony 设备上测试: - 不同的 API 版本(9、10、11+) - 不同的架构(ARM32、ARM64) - 不同的 OEM 和设备类型

7. 最小化库大小

减小 HAR 大小以便更快下载:

[build]
cxxflags = ["-Os", "-flto"]        # 优化大小
strip_symbols = true               # 剥离调试符号

故障排除

找不到 OHOS SDK

Error: OHOS SDK not found

解决方案:

# 设置 OHOS SDK 路径
export OHOS_SDK_HOME="/path/to/ohos-sdk"

# 或在 CCGO.toml 中
[ohos]
sdk_path = "/path/to/ohos-sdk"

# 验证
ls $OHOS_SDK_HOME/native

HAR 导入失败

Error: Failed to import HAR package

解决方案:

  1. 检查 oh-package.json5:

    {
      "dependencies": {
        "mylib": "file:../path/to/mylib-1.0.0.har"  // 使用正确的路径
      }
    }
    

  2. 验证 HAR 结构:

    unzip -l mylib-1.0.0.har
    # 应包含:libs/、include/、oh-package.json5
    

  3. 重新安装依赖:

    ohpm install
    

找不到 NAPI 符号

Error: Cannot find module 'libmylib.so'

解决方案:

  1. 检查库是否在 HAR 中:

    unzip -l mylib-1.0.0.har | grep libmylib.so
    

  2. 验证模块名称匹配:

    // 在 NAPI 代码中
    .nm_modname = "mylib",  // 必须匹配导入名称
    

  3. 检查 build.gradle:

    externalNativeBuild {
        cmake {
            targets "mylib"  // 模块名称
        }
    }
    

API 版本不匹配

Error: Minimum API version not met

解决方案:

更新设备或降低最低 API 版本:

[ohos]
min_api_version = 9  # 降低以支持更多设备

不支持的架构

Error: No native library found for architecture

解决方案:

为缺失的架构构建:

# 构建所有架构
ccgo build ohos --arch armeabi-v7a,arm64-v8a,x86_64

性能提示

1. 使用 ARM NEON 指令

为 ARM 启用 NEON 优化:

[build]
cxxflags = ["-mfpu=neon", "-mfloat-abi=softfp"]  # ARMv7
# ARM64 默认启用 NEON

2. 链接时优化

[build]
cxxflags = ["-flto"]
ldflags = ["-flto"]

3. 优化大小

OpenHarmony 设备通常存储有限:

[build]
cxxflags = ["-Os", "-ffunction-sections", "-fdata-sections"]
ldflags = ["-Wl,--gc-sections"]

4. 静态链接以提高性能

静态库可能更快:

ccgo build ohos --build-as static

5. 在设备上进行性能分析

使用 HiPerf 进行性能分析:

# 在设备上
hiperfcmd start -o perf.data
# 运行应用
hiperfcmd stop
hiperfcmd report -i perf.data

迁移指南

从原生 C++ 模块

之前:

// 独立 C++ 模块
namespace mylib {
    void do_work();
}

之后:

  1. 创建 CCGO 项目:

    ccgo new mylib
    

  2. 添加 NAPI 包装器:

    // 添加 NAPI 绑定
    static napi_value DoWork(napi_env env, napi_callback_info info) {
        mylib::do_work();
        return nullptr;
    }
    

  3. 构建 HAR:

    ccgo build ohos --har
    

从 Android NDK 库

与 Android 有许多相似之处:

差异: - 使用 HAR 而不是 AAR - 使用 OHPM 而不是 Maven - 使用 NAPI 而不是 JNI - 不同的构建系统(Hvigor vs Gradle)

迁移步骤:

  1. 将 C++ 代码复制到 CCGO 项目
  2. 更新构建配置:

    [ohos]
    min_api_version = 9
    

  3. 用 NAPI 替换 JNI:

    // JNI
    JNIEXPORT jint JNICALL Java_com_example_MyLib_doWork(JNIEnv* env, jobject obj)
    
    // NAPI
    static napi_value DoWork(napi_env env, napi_callback_info info)
    

  4. 构建:

    ccgo build ohos --har
    

高级主题

多模块 HAR

创建包含多个模块的 HAR:

mylib/
├── core/              # 核心模块
│   ├── src/
│   └── include/
├── ui/                # UI 模块
│   ├── src/
│   └── include/
└── CCGO.toml
[package]
name = "mylib"

[[modules]]
name = "core"
path = "core"

[[modules]]
name = "ui"
path = "ui"
dependencies = ["core"]

嵌入资源

在 HAR 中包含资源:

mylib-1.0.0.har
├── libs/
├── include/
├── resources/
│   ├── base/
│   │   └── element/
│   └── rawfile/
│       └── data.bin
└── oh-package.json5

代码签名

为分发签名 HAR:

# 生成密钥
hapsigner generate-keypair -keyAlias mylib -keyAlg RSA

# 签名 HAR
hapsigner sign-app -mode localSign \
    -keyAlias mylib \
    -signAlg SHA256withRSA \
    -inputFile mylib-1.0.0.har \
    -outputFile mylib-1.0.0-signed.har

混淆

保护 C++ 代码:

[build]
cxxflags = ["-fvisibility=hidden", "-ffunction-sections"]
strip_symbols = true

另请参阅