前言
随着 HarmonyOS 生态的快速发展,越来越多的应用需要从 Android 平台迁移到 HarmonyOS。本系列文章将以一个真实的云应用客户端项目为例,详细记录从 Android 到 HarmonyOS 6.1 的完整适配过程。
项目背景:
- 原项目是一个基于 WebSocket 的云桌面/云应用客户端
- 使用 C++ 实现核心功能(视频解码、网络通信、输入处理)
- Android 端使用 JNI 封装,HarmonyOS 需要改用 N-API
- 依赖多个第三方库:OpenSSL、FFmpeg、Protobuf、Poco、Boost 等
本文作为系列第一篇,重点介绍环境搭建和编译系统的适配工作。
一、开发环境准备
1.1 工具链安装
必需工具:
bash
# HarmonyOS NDK(包含在 DevEco Studio 中)
路径:D:\Program Files\Huawei\DevEco Studio\sdk\default\openharmony\native
# CMake 3.16+
# Ninja 构建工具
# Python 3.x(用于构建脚本)
关键环境变量:
bash
export OHOS_SDK_NATIVE=/path/to/ohos/native
export PATH=$OHOS_SDK_NATIVE/llvm/bin:$PATH
1.2 工具链特点
HarmonyOS NDK 使用的是 LLVM/Clang 工具链,与 Android NDK 类似,但有几个关键差异:
| 特性 | Android NDK | HarmonyOS NDK |
|---|---|---|
| 编译器 | Clang (Android 定制) | Clang (OpenHarmony) |
| 标准库 | libc++ | libc++ |
| 目标三元组 | aarch64-linux-android | aarch64-linux-ohos |
| 系统根目录 | sysroot | sysroot |
重点注意: 目标架构名称的差异会影响到第三方库的交叉编译。
二、CMake 配置适配
2.1 平台识别
首先需要在 CMakeLists.txt 中添加 HarmonyOS 平台的识别:
cmake
# 检测 HarmonyOS 平台
if(CMAKE_SYSTEM_NAME STREQUAL "OHOS")
set(OHOS_PLATFORM ON)
add_definitions(-DOHOS -DOHOS_PLATFORM)
message(STATUS "Building for HarmonyOS platform")
endif()
2.2 编译器和链接器配置
cmake
if(OHOS_PLATFORM)
# 设置编译器
set(CMAKE_C_COMPILER "${OHOS_SDK_NATIVE}/llvm/bin/clang")
set(CMAKE_CXX_COMPILER "${OHOS_SDK_NATIVE}/llvm/bin/clang++")
# 设置 sysroot
set(CMAKE_SYSROOT "${OHOS_SDK_NATIVE}/sysroot")
# 目标架构
set(CMAKE_SYSTEM_PROCESSOR aarch64)
# 编译选项
add_compile_options(
--target=aarch64-linux-ohos
--sysroot=${CMAKE_SYSROOT}
-D__MUSL__
)
# 链接选项
add_link_options(
--target=aarch64-linux-ohos
--sysroot=${CMAKE_SYSROOT}
)
endif()
2.3 条件编译宏的使用
在代码中需要大量使用条件编译来区分平台:
cpp
// 平台检测示例
#if defined(OHOS) || defined(OHOS_PLATFORM)
// HarmonyOS 特定代码
#include <native_window/external_window.h>
#include <hilog/log.h>
#elif defined(__ANDROID__)
// Android 特定代码
#include <android/native_window.h>
#include <android/log.h>
#elif defined(_WIN32)
// Windows 特定代码
#include <windows.h>
#endif
最佳实践:
- 使用
#if defined(OHOS) || defined(OHOS_PLATFORM)而不是#ifdef OHOS - 在 CMake 中同时定义两个宏,确保兼容性
- 关键分支点添加日志,便于排查条件编译错误
三、第三方库交叉编译
3.1 OpenSSL 编译
OpenSSL 是网络通信的基础库,编译步骤:
bash
# 配置
./Configure linux-aarch64 \
--prefix=/path/to/install \
--cross-compile-prefix=aarch64-linux-ohos- \
CC=clang \
--sysroot=$OHOS_SDK_NATIVE/sysroot \
no-shared \
no-tests
# 编译
make -j8
make install
关键点:
- 使用
linux-aarch64配置(没有专门的 ohos 配置) - 必须指定
--cross-compile-prefix - 建议编译静态库(
no-shared)
3.2 FFmpeg 编译
FFmpeg 是视频解码的核心库,配置较为复杂:
bash
./configure \
--prefix=/path/to/install \
--enable-cross-compile \
--cross-prefix=aarch64-linux-ohos- \
--arch=aarch64 \
--target-os=linux \
--cc=clang \
--cxx=clang++ \
--sysroot=$OHOS_SDK_NATIVE/sysroot \
--extra-cflags="--target=aarch64-linux-ohos" \
--extra-ldflags="--target=aarch64-linux-ohos" \
--disable-shared \
--enable-static \
--disable-programs \
--disable-doc \
--enable-decoder=h264 \
--enable-decoder=hevc \
--enable-parser=h264 \
--enable-parser=hevc
make -j8
make install
重点配置说明:
--target-os=linux:HarmonyOS 内核基于 Linux,使用 linux 配置--extra-cflags和--extra-ldflags:必须显式指定目标三元组- 裁剪配置:只编译需要的解码器,减小体积
3.3 Protobuf 编译
Protobuf 用于消息序列化,需要注意宿主机和目标机的兼容性:
bash
# 第一步:编译宿主机版本(用于生成代码)
mkdir build-host
cd build-host
cmake .. -DCMAKE_INSTALL_PREFIX=/path/to/protobuf-host
make -j8
make install
# 第二步:交叉编译目标版本
mkdir build-ohos
cd build-ohos
cmake .. \
-DCMAKE_SYSTEM_NAME=OHOS \
-DCMAKE_C_COMPILER=clang \
-DCMAKE_CXX_COMPILER=clang++ \
-DCMAKE_SYSROOT=$OHOS_SDK_NATIVE/sysroot \
-DCMAKE_C_FLAGS="--target=aarch64-linux-ohos" \
-DCMAKE_CXX_FLAGS="--target=aarch64-linux-ohos" \
-Dprotobuf_BUILD_TESTS=OFF \
-DCMAKE_INSTALL_PREFIX=/path/to/protobuf-ohos
make -j8
make install
为什么需要两个版本?
- 宿主机版本的
protoc用于在编译时生成.pb.cc和.pb.h文件 - 目标版本的
libprotobuf.a用于链接到最终的 HarmonyOS 应用中
3.4 Poco 编译
Poco 是一个 C++ 网络库,用于 HTTP 和 WebSocket 通信:
bash
mkdir build-ohos
cd build-ohos
cmake .. \
-DCMAKE_SYSTEM_NAME=Linux \
-DCMAKE_C_COMPILER=clang \
-DCMAKE_CXX_COMPILER=clang++ \
-DCMAKE_SYSROOT=$OHOS_SDK_NATIVE/sysroot \
-DCMAKE_C_FLAGS="--target=aarch64-linux-ohos" \
-DCMAKE_CXX_FLAGS="--target=aarch64-linux-ohos -std=c++17" \
-DENABLE_NETSSL_WIN=OFF \
-DENABLE_NETSSL=ON \
-DENABLE_CRYPTO=ON \
-DENABLE_TESTS=OFF \
-DCMAKE_INSTALL_PREFIX=/path/to/poco-ohos
make -j8
make install
注意事项:
CMAKE_SYSTEM_NAME使用Linux而不是OHOS- 需要启用
ENABLE_NETSSL和ENABLE_CRYPTO支持 HTTPS - 关闭测试以加快编译速度
四、主项目 CMake 配置
4.1 第三方库集成
cmake
# 设置第三方库路径
set(THIRD_PARTY_DIR "${CMAKE_SOURCE_DIR}/3rdparty")
if(OHOS_PLATFORM)
set(OPENSSL_ROOT "${THIRD_PARTY_DIR}/openssl-ohos")
set(FFMPEG_ROOT "${THIRD_PARTY_DIR}/ffmpeg-ohos")
set(PROTOBUF_ROOT "${THIRD_PARTY_DIR}/protobuf-ohos")
set(POCO_ROOT "${THIRD_PARTY_DIR}/poco-ohos")
endif()
# 添加头文件路径
include_directories(
${OPENSSL_ROOT}/include
${FFMPEG_ROOT}/include
${PROTOBUF_ROOT}/include
${POCO_ROOT}/include
)
# 链接库
link_directories(
${OPENSSL_ROOT}/lib
${FFMPEG_ROOT}/lib
${PROTOBUF_ROOT}/lib
${POCO_ROOT}/lib
)
4.2 源文件组织
cmake
# 公共源文件
set(COMMON_SOURCES
src/cloud_client.cc
src/net/control_client.cc
src/FFmpegDecoder.cpp
# ... 其他公共文件
)
# 平台特定源文件
if(OHOS_PLATFORM)
set(PLATFORM_SOURCES
src/gles/GLViewOHOS.cpp
src/gles/GLViewBase.cpp
# ... HarmonyOS 特定文件
)
elseif(ANDROID)
set(PLATFORM_SOURCES
src/gles/GLViewAndroid.cpp
# ... Android 特定文件
)
endif()
# 创建静态库
add_library(cloudappclient STATIC
${COMMON_SOURCES}
${PLATFORM_SOURCES}
)
4.3 链接配置
cmake
if(OHOS_PLATFORM)
target_link_libraries(cloudappclient
# 系统库
ace_napi.z
hilog_ndk.z
native_window
EGL
GLESv3
# 第三方库(注意顺序)
PocoNetSSL
PocoNet
PocoCrypto
PocoFoundation
ssl
crypto
avcodec
avutil
swscale
protobuf
pthread
dl
z
)
endif()
链接顺序很重要:
- 依赖关系:PocoNetSSL → PocoNet → PocoCrypto → OpenSSL
- 错误的顺序会导致符号未定义错误
五、常见问题与解决方案
5.1 找不到系统头文件
错误信息:
fatal error: 'hilog/log.h' file not found
解决方案:
cmake
# 显式添加系统头文件路径
include_directories(
${OHOS_SDK_NATIVE}/sysroot/usr/include
)
5.2 链接时未定义符号
错误信息:
undefined reference to `OH_NativeWindow_CreateNativeWindowFromSurfaceId'
解决方案:
cmake
# 确保链接了正确的系统库
target_link_libraries(your_target
native_window # 注意:不是 native_window.z
)
5.3 C++ 标准库问题
错误信息:
error: no member named 'make_unique' in namespace 'std'
解决方案:
cmake
# 设置 C++ 标准为 17 或更高
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
5.4 OpenSSL 版本兼容
如果第三方库(如 Poco)依赖特定版本的 OpenSSL,需确保:
bash
# 查看依赖的 OpenSSL 版本
strings libPocoNetSSL.a | grep "OpenSSL"
# 编译时指定 OpenSSL 路径
cmake .. \
-DOPENSSL_ROOT_DIR=/path/to/openssl-3.x \
-DOPENSSL_INCLUDE_DIR=/path/to/openssl-3.x/include \
-DOPENSSL_LIBRARIES="/path/to/openssl-3.x/lib/libssl.a;/path/to/openssl-3.x/lib/libcrypto.a"
六、构建脚本示例
为了简化编译流程,建议编写自动化脚本:
bash
#!/bin/bash
# build_ohos.sh
set -e
# 环境变量
export OHOS_SDK_NATIVE="/path/to/ohos/native"
export PATH=$OHOS_SDK_NATIVE/llvm/bin:$PATH
# 创建构建目录
BUILD_DIR="build_ohos_arm64"
rm -rf $BUILD_DIR
mkdir $BUILD_DIR
cd $BUILD_DIR
# 配置
cmake .. \
-DCMAKE_SYSTEM_NAME=OHOS \
-DCMAKE_SYSTEM_PROCESSOR=aarch64 \
-DCMAKE_C_COMPILER=clang \
-DCMAKE_CXX_COMPILER=clang++ \
-DCMAKE_SYSROOT=$OHOS_SDK_NATIVE/sysroot \
-DCMAKE_C_FLAGS="--target=aarch64-linux-ohos" \
-DCMAKE_CXX_FLAGS="--target=aarch64-linux-ohos -std=c++17" \
-DCMAKE_BUILD_TYPE=Release \
-GNinja
# 编译
ninja -j8
# 复制输出文件
cp api/libdlca_cloudapp.so ../output/
echo "Build completed successfully!"
七、总结
本文介绍了 HarmonyOS 6.1 云应用客户端适配的第一步:环境搭建和编译系统配置。关键要点:
- 工具链理解 :HarmonyOS NDK 基于 LLVM,目标三元组为
aarch64-linux-ohos - CMake 配置:正确设置编译器、sysroot 和目标架构
- 第三方库编译:需要单独交叉编译每个依赖库
- 条件编译:使用宏区分不同平台的代码路径
- 链接顺序:注意库的依赖关系,避免符号未定义
下一篇预告:
在完成编译系统配置后,下一篇将深入介绍视频渲染的适配,包括 Native Window API 的使用、EGL 初始化、OpenGL ES 纹理渲染等核心功能的实现。
参考资料
作者: Frame Not Work
日期: 2026年6月
系列文章: HarmonyOS 6.1 云应用客户端适配实战