手把手教你在鸿蒙应用中集成鸿蒙化abseil-cpp三方库,Demo已开源
[!NOTE]
加入开源鸿蒙跨平台社区:
・共享三方库移植方案、跨平台应用开发
・互助解决编译 / 运行问题
・第一时间获取鸿蒙三方库适配模板
一个人走得快,一群人走得远!
1. 概述
Abseil C++ 是 Google 开源的 C++ 基础库,与标准库互补,广泛用于 gRPC、Protobuf 等。本章节将介绍如何在鸿蒙应用集成abseil-cpp鸿蒙化三方库的完整示例。
| 项 | 说明 |
|---|---|
| 适配版本 | 20260107.1(Abseil LTS) |
| 源库地址 | abseil/abseil-cpp |
| 协议 | Apache-2.0 |
| 适配地址 | oh-tpc/abseil-cpp |
| 目标架构 | armeabi-v7a、arm64-v8a |
| 适配作者 | allincoding |
| 示例源代码 | AbseilCPPSample |

已完成适配abseil-cpp模块
| 方向 | 代表模块(路径/命名空间) | 提供的能力(你会用它做什么) | HarmonyOS NDK 示例默认推荐 |
|---|---|---|---|
| 字符串 | absl/strings/* |
string_view、拼接/分割/格式化、数字解析、匹配与裁剪、Cord |
推荐 |
| 状态返回 | absl/status/* |
Status/StatusOr<T>,统一错误码与消息的传递方式 |
强烈推荐 |
| 时间 | absl/time/* |
Time/Duration/TimeZone,Now(),FormatTime/ParseTime,Civil time |
推荐 |
| 容器 | absl/container/* |
flat_hash_map/set、node_hash_*、btree_*、InlinedVector 等 |
推荐(按场景选型) |
| 哈希 | absl/hash/* |
absl::Hash、组合哈希、与容器配套的哈希策略 |
推荐(配合容器/自定义 key) |
| 随机数 | absl/random/* |
BitGen、Uniform、各种分布 |
推荐(替代 rand()) |
| 数值/位运算 | absl/numeric/* |
int128/uint128、bits(popcount/rotl/rotr 等) |
推荐(需要时) |
| 算法封装 | absl/algorithm/* |
面向容器的算法(如 c_sort 等) |
可选 |
| 作用域清理 | absl/cleanup/* |
作用域退出执行清理(defer/RAII 风格) | 推荐(写 C++ glue 很好用) |
| CRC | absl/crc/* |
CRC32C 等检错校验、增量计算 | 可选(数据链路/存储格式需要时) |
| functional | absl/functional/* |
FunctionRef/bind_front/Overload/AnyInvocable 等(随版本) |
可选(回调体系复杂时很值) |
| memory | absl/memory/* |
内存/对齐/兼容性工具集合(随版本不同) | 可选(更偏底层工程) |
| 同步并发 | absl/synchronization/* |
线程同步原语、通知/屏障等 | 可选(Native 层多线程时) |
| 日志 | absl/log/* |
日志框架、sink、与 flags 配合 | 谨慎(移动端通常已有日志体系) |
| Flags | absl/flags/* |
命令行 flags 定义/解析/usage | 不推荐(移动端通常不用 CLI) |
| 调试/栈 | absl/debugging/* |
栈追踪、符号化、故障处理等 | 可选(调试/崩溃排障) |
| profiling | absl/profiling/* |
采样/剖析相关挂钩与组件 | 谨慎(体积/开销/产物控制) |
| 基础与平台 | absl/base/* |
配置/宏/端序/NoDestructor 等基石能力 |
隐式依赖(经常被上层带入) |
2. 创建NDK工程
NDK(Native Development Kit)是HarmonyOS SDK提供的Native API、相应编译脚本和编译工具链的集合,方便开发者使用C或C++语言实现应用的关键功能。NDK只覆盖了HarmonyOS一些基础的底层能力,如C运行时基础库libc、图形库、窗口系统、多媒体、压缩库、面向ArkTS/JS与C跨语言的Node-API等,没有提供ArkTS/JS API的完整能力。
- 通过如下两种方式,打开工程创建向导界面。
- 如果当前未打开任何工程,可以在DevEco Studio的欢迎页,选择**
Create Project**开始创建一个新NDK工程。 - 如果已经打开了工程,可以在菜单栏选择**
File > New > Create Project**来创建一个新NDK工程。
- 如果当前未打开任何工程,可以在DevEco Studio的欢迎页,选择**
- 根据工程创建向导,选择
Native C++工程模板,然后单击**Next**。

- 在工程配置页面,根据向导配置工程的基本信息后,单击Finish,工具会自动生成示例代码和相关资源,等待工程创建完成。

- 在工程entry/src/main目录下会包含cpp目录。

entry/src/main # 应用模块,编译构建生成一个HAP
├── cpp
│ ├── CMakeLists.txt # CMake配置文件,提供CMake构建脚本
│ ├── napi_init.cpp # 定义C++ API接口的文件
│ └── types # 用于存放C++的API接口描述文件
│ └── libentry
│ ├── Index.d.ts # 描述C++ API接口行为,如接口名、入参、返回参数等
│ └── oh-package.json5 # 配置.so三方包声明文件的入口及包名
├── ets # 用于存放ArkTS源码
├── module.json5 # 配置文件,包含HAP的配置信息、应用在具体设备上的配置信息以及应用的全局配置信息
└── resources # 用于存放应用所用到的资源文件,如图形、多媒体、字符串、布局文件等。
具体请参考工程目录结构。
项目结构
AbseilCPPSample/
├── AppScope/ # 应用级配置(包名、bundle 等)
│ └── app.json5
├── hvigor/ # hvigor 工程级配置
│ └── hvigor-config.json5
├── hvigorfile.ts # hvigor 构建入口脚本
├── build-profile.json5 # 工程构建 profile(产品/签名等)
├── oh-package.json5 # 工程级 ohpm 依赖声明
├── code-linter.json5 # 代码检查规则
├── entry/ # 主模块(Ability + UI + NDK)
│ ├── build-profile.json5 # 模块级构建配置
│ ├── oh-package.json5
│ └── src/main/
│ ├── module.json5 # 模块能力、请求权限等
│ ├── cpp/ # Native C++(生成 libentry.so)
│ │ ├── CMakeLists.txt # CMake:链接 Abseil、编译 napi_init.cpp
│ │ ├── napi_init.cpp # N-API 注册与各能力导出(体量较大)
│ │ ├── thirdparty/
│ │ │ └── abseil-cpp/ # 预编译 Abseil(按架构)
│ │ │ ├── arm64-v8a/
│ │ │ │ ├── include/absl/ # 头文件
│ │ │ │ └── lib/ # 静态库、cmake/pkgconfig
│ │ └── types/libentry/ # `libentry.so` 的 ArkTS 类型侧
│ │ ├── Index.d.ts # 导出函数/类型声明(与 napi 对齐)
│ │ └── oh-package.json5
│ ├── ets/
│ │ ├── entryability/
│ │ │ └── EntryAbility.ets # UI Ability 入口
│ │ ├── entrybackupability/
│ │ │ └── EntryBackupAbility.ets # 备份扩展(模板自带)
│ │ ├── model/
│ │ │ ├── AbseilModuleMeta.ets # 模块列表、摘要、是否含 NAPI 演示等元数据
│ │ │ └── ModuleNapiExports.ets # 各模块导出的 NAPI 符号表(与 Index.d.ts 对齐,供说明页等使用)
│ │ ├── common/ # 路由、主题、示例壳与 Markdown
│ │ │ ├── AbseilNavigation.ets # NavPathStack、专页名表、push/pop 实现(ModuleRouteHelper 由此 re-export)
│ │ │ ├── ModuleRouteHelper.ets # 打开「说明 / 示例 / 专页」的对外 API
│ │ │ ├── NeoDreamTheme.ets # 全局深色底、液晶面板/顶栏/卡片等配色(NeoModuleRoot)
│ │ │ ├── FormFactor.ets # 手机/平板断点:栅格列数、间距、字号等(@StorageLink)
│ │ │ ├── ExamplePageTheme.ets # 示例与说明液晶区内:章节字色、正文色、输入框描边(与 ModuleExamples 共用)
│ │ │ ├── DedicatedExamplePageShell.ets # 各 *Module 专页统一布局:顶栏 + 液晶 + 标准引导 + 业务 Column
│ │ │ ├── NapiDemoSupport.ets # runSafelyNapi、常见返回形状等
│ │ │ ├── AbseilDemoCard.ets # 演示卡片:intro / detail / arktsExample / 运行 / 结果
│ │ │ ├── MarkdownModel.ets # 概述页 Markdown AST 类型
│ │ │ ├── MarkdownParse.ets # Markdown → AST(README 常用子集)
│ │ │ └── MarkdownBody.ets # AST → ArkUI 排版
│ │ ├── home/ # 首页 Tab 与子界面
│ │ │ ├── IndexOverviewTab.ets # 总览 Tab(加载 rawfile/README.md)
│ │ │ ├── IndexIntroTab.ets # 模块入口(查看说明)
│ │ │ ├── IndexExamplesTab.ets # 交互示例 Tab(打开示例)
│ │ │ └── ModuleDocBody.ets # 仅说明正文(摘要/能力/详细说明)
│ │ └── pages/
│ │ ├── Index.ets # 主页面(多 Tab 容器)
│ │ ├── ModuleDoc.ets # 模块说明页(无 libentry 依赖)
│ │ ├── ModuleExamples.ets # 模块通用示例页(napi_base/strings/status 等内嵌卡片;无专页时占位提示)
│ │ ├── TimeModule.ets # ┐
│ │ ├── ContainerModule.ets # │
│ │ ├── HashModule.ets # │
│ │ ├── RandomModule.ets # ├─ 各 Abseil 方向的独立演示专页
│ │ ├── NumericModule.ets # │ (与 AbseilNavigation.DEDICATED_NAV_NAMES 一致)
│ │ ├── AlgorithmModule.ets # │
│ │ ├── CleanupModule.ets # │
│ │ ├── CrcModule.ets # │
│ │ ├── FunctionalModule.ets # │
│ │ ├── MemoryModule.ets # │
│ │ ├── SynchronizationModule.ets
│ │ ├── LogModule.ets # │
│ │ ├── FlagsModule.ets # │
│ │ ├── DebuggingModule.ets # │
│ │ ├── ProfilingModule.ets # │
│ │ └── BaseModule.ets # ┘
│ └── resources/
│ ├── rawfile/
│ │ └── README.md # 概述 Tab 全文(与仓库根 README.md 保持一致并随包发布)
│ └── base/
│ ├── profile/
│ │ └── main_pages.json # 页面路由注册(上述 pages 须在此列出)
│ ├── element/ # 颜色、字号等主题资源
│ └── media/ # 媒体与图层资源
└── ... # 构建产物见 entry/build/、.cxx/(通常不入库)
ArkTS 分层说明
| 目录/文件 | 作用 |
|---|---|
ets/model/AbseilModuleMeta.ets |
单一数据源:模块 id、标题、摘要、hasNativeDemo、说明段落等,驱动首页卡片与 ModuleDoc 内容。 |
ets/model/ModuleNapiExports.ets |
按模块 id 列出本工程在 libentry.so 中导出的符号说明(与 types/libentry/Index.d.ts 一致);更新 NAPI 时需同步。 |
ets/common/AbseilNavigation.ets |
NavPathStack 路由:DEDICATED_NAV_NAMES 与 Index.ets 中 navDestination 一一对应;新增专页时两处都要登记。 |
ets/common/ModuleRouteHelper.ets |
对外的 openModuleDocumentation / openModuleInteractiveDemo(由 AbseilNavigation re-export)。 |
ets/common/NeoDreamTheme.ets |
NeoModuleRoot、NeoPalette:应用级渐变底与「液晶」卡片视觉。 |
ets/common/FormFactor.ets |
窄屏/宽屏布局参数(如 demoGridColumns、水平边距);专页与 ModuleExamples 共用。 |
ets/common/ExamplePageTheme.ets |
示例/说明液晶区内的字色与输入框描边常量;ModuleExamples 与各专页共用,避免魔法色散落的。 |
ets/common/DedicatedExamplePageShell.ets |
专页壳组件:与 ModuleExamples 同风格的顶栏 + 外留白 + 液晶面板 +「Native 交互示例」引导语 + moduleLeadExtra + 子内容插槽。 |
ets/common/AbseilDemoCard.ets |
单条 NAPI 演示:介绍、示例详情、ArkTS 调用示例代码块、运行按钮、结果区(兼容旧版仅 desc)。 |
ets/common/NapiDemoSupport.ets |
runSafelyNapi 及常见结构化返回类型的 ArkTS 形状,供各页统一 try/展示错误。 |
ets/common/Markdown*.ets |
概述 Tab 用:模型、解析、渲染(子集 Markdown)。 |
ets/home/* |
首页三个 Tab;IndexOverviewTab 读取 resources/rawfile/README.md,经 MarkdownParse / MarkdownBody 排版。 |
resources/rawfile/README.md |
与仓库根目录 README.md 内容同步;更新后执行 cp README.md entry/src/main/resources/rawfile/README.md 再编译。 |
ets/pages/ModuleDoc.ets |
当前模块的功能说明(液晶面板 + ModuleDocBody)。 |
ets/pages/ModuleExamples.ets |
未拆专页的模块在此内嵌演示(如 napi_base、strings、status 等);布局与专页一致(同色常量、输入区、栅格间距)。 |
ets/pages/*Module.ets |
交互项多的模块独立成页(time、container、hash…);内部使用 DedicatedExamplePageShell,卡片字段与 ModuleExamples 对齐。 |
ets/pages/Index.ets |
主页面:Tab 容器 + Navigation/NavPathStack 与上述 pages 的 navDestination 注册。 |
Native 侧要点
| 路径 | 说明 |
|---|---|
cpp/napi_init.cpp |
所有导出到 ArkTS 的 N-API 实现;与 types/libentry/Index.d.ts 保持同名、同签名。 |
cpp/thirdparty/abseil-cpp/<arch>/ |
与当前 OHOS_ARCH 一致的预编译产物;勿混用架构目录。 |
3. 应用中集成abseil-cpp三方库
- 将
abseil-cpp三方库生成的二进制文件oh-tpc/abseil-cpp/output目录下的文件拷贝到应用工程目录。
注:为了更好的管理应用集成的三方库,在应用工程的
cpp目录新建一个thirdparty目录,将生成的二进制文件以及头文件拷贝到该目录下(根据实际的架构选择)。

- 打开
cpp/CMakeLists.txt文件配置静态链接和头文件。
在调用 CMake 时会注入 OHOS_ARCH。本仓库采用 absl_DIR + find_package(... CONFIG) 加载官方风格的 Abseil CMake 包,并对 entry 目标单独增加 target_include_directories(PRIVATE ${ABSL_ROOT}/include),避免仅依赖全局 include_directories 时遗漏 Abseil 头路径。
完整列表以 entry/src/main/cpp/CMakeLists.txt 为准:
cmake_minimum_required(VERSION 3.5.0)
project(AbseilCPPSample)
set(NATIVERENDER_ROOT_PATH ${CMAKE_CURRENT_SOURCE_DIR})
if(DEFINED PACKAGE_FIND_FILE)
include(${PACKAGE_FIND_FILE})
endif()
include_directories(${NATIVERENDER_ROOT_PATH}
${NATIVERENDER_ROOT_PATH}/include)
# ---------- abseil-cpp:按架构选包 ----------
if(${OHOS_ARCH} STREQUAL "armeabi-v7a")
set(ABSL_ROOT ${NATIVERENDER_ROOT_PATH}/thirdparty/abseil-cpp/armeabi-v7a)
elseif(${OHOS_ARCH} STREQUAL "arm64-v8a")
set(ABSL_ROOT ${NATIVERENDER_ROOT_PATH}/thirdparty/abseil-cpp/arm64-v8a)
else()
message(FATAL_ERROR "Unknown OHOS_ARCH=${OHOS_ARCH}, expected armeabi-v7a or arm64-v8a")
endif()
# 指向 abslConfig.cmake 所在目录(注意是 lib/cmake/absl,不是 lib/cmake 根目录)
set(absl_DIR ${ABSL_ROOT}/lib/cmake/absl)
find_package(absl REQUIRED CONFIG)
add_library(entry SHARED napi_init.cpp)
target_include_directories(entry PRIVATE ${ABSL_ROOT}/include)
target_link_libraries(entry PRIVATE
libace_napi.z.so
absl::strings
absl::string_view
absl::status
absl::statusor
absl::time
absl::time_zone
absl::civil_time
absl::cord
absl::cord_internal
absl::synchronization
absl::spinlock_wait
absl::hash
absl::city
absl::raw_hash_set
absl::random_random
absl::random_distributions
absl::random_seed_sequences
absl::int128
absl::base
absl::throw_delegate
absl::raw_logging_internal
absl::log_internal_check_op
absl::log_internal_message
absl::log_entry
absl::log_sink
absl::log_severity
absl::log_flags
absl::log_globals
absl::log_initialize
absl::log
absl::check
absl::log_sink_registry
absl::exponential_biased
absl::periodic_sampler
absl::sample_recorder
absl::str_format
absl::str_format_internal
absl::strerror
absl::flags
absl::flags_parse
absl::flags_usage
absl::debugging
absl::failure_signal_handler
absl::hashtable_profiler
absl::flat_hash_map
absl::flat_hash_set
absl::node_hash_map
absl::node_hash_set
absl::btree
absl::optional
absl::variant
absl::any
absl::span
absl::memory
absl::type_traits
absl::utility
absl::algorithm
absl::cleanup
absl::crc32c
absl::any_invocable
absl::bind_front
absl::function_ref
absl::overload
absl::numeric
absl::compare
absl::endian
absl::bits
)
说明:
find_package(absl REQUIRED CONFIG)依赖absl_DIR指向lib/cmake/absl;不要使用已过时的仅list(APPEND CMAKE_MODULE_PATH ${ABSL_ROOT}/lib/cmake)再find_package(absl)的写法,除非你能确认所用 Abseil 包布局仍支持。target_link_libraries(... PRIVATE ...):Native 动态库一般只需把 Abseil 静态进自己.so,用PRIVATE即可,避免向依赖方传递不必要的链接要求。- 链接列表较长是为了覆盖本示例
napi_init.cpp中演示到的 strings / status / time / 容器 / 哈希 / 随机 / 数值 / cleanup / crc / functional / debugging / flags / log 等模块;静态链接时顺序由 CMake 目标依赖处理,但仍建议不要随意删减除非你明确只用到子集并验证无未定义符号。
4. Native 接口实现(napi_init.cpp)
Native 侧集中在 entry/src/main/cpp/napi_init.cpp:在 Init(napi_env, napi_value exports) 中通过 napi_define_properties 将大量属性挂到导出对象上(与 HarmonyOS N-API 常规写法一致)。源码文件体量较大,这是为了把多模块演示集中在 单个 libentry.so 内,便于 ArkTS 侧 import testNapi from 'libentry.so' 一次导入。
4.1 与 ArkTS 类型的对应关系
- 唯一权威的类型列表:
entry/src/main/cpp/types/libentry/Index.d.ts。其中export function/export const与 C++ 里注册的 属性名字符串必须一致,参数与返回值形状也应保持同步,否则会出现编译通过但运行期找不到属性或类型不符的问题。 - 当前该文件中约有 两百个 导出符号(含
add与各类*Result接口形状),覆盖多类 Abseil 能力;不在 README 中逐条罗列,查阅时请直接在 IDE 中打开Index.d.ts,或按下面「子系统」在文件中搜索前缀。
4.2 按 Abseil 子系统划分的导出一览
下表概括 命名前缀或区域 与 Abseil 头文件层次 的对应关系;具体函数名、参数与注释以 Index.d.ts 为准。
| 子系统(ArkTS 命名特征) | 主要涉及的 Abseil 区域 | 说明 |
|---|---|---|
add |
(无) | 纯整数加法,用于验证 NAPI 链路。 |
strCat、startsWith、strSplit*、strJoin*、consume*、substitute* 等 |
absl/strings |
拼接、匹配、裁剪、分割、替换、格式化、string_view 相关演示。 |
status、makeStatus、statusOr*、invalidArgumentError 等 |
absl/status、absl/statusor |
Status / StatusOr、错误工厂与解析示例。 |
now、formatUnixMillis、parseRFC3339、parseDuration、formatDurationFromMillis 等 |
absl/time |
当前时间、格式化/解析、Duration 与毫秒运算。 |
stringView |
absl/string_view |
长度与前缀探测等轻量示例。 |
container* |
absl/container |
flat_hash_map/set、node_hash_set、btree_* 与字符串分词组合演示。 |
hashHex*、hashStringVsStringView |
absl/hash |
哈希值以十六进制字符串等形式返回,便于 ArkTS 展示。 |
random* |
absl/random |
BitGen / InsecureBitGen、均匀与多种分布(非密码学随机)。 |
algorithm* |
absl/algorithm |
与容器配合的查找、排序、累计等(输入多为逗号分隔整数 CSV)。 |
cleanup* |
absl/cleanup |
作用域退出清理、Cancel / Invoke / 移动语义。 |
crc32c* |
absl/crc |
CRC32C 计算、扩展、拼接与 MemcpyCrc32c 等。 |
functional* |
absl/functional |
bind_front、FunctionRef、AnyInvocable、Overload 与 visit 等。 |
memory* |
absl/memory |
与智能指针、分配器特征相关的可运行小示例。 |
sync* |
absl/synchronization |
互斥、读写锁、条件变量、Notification、BlockingCounter、Barrier 等;实现中会在 Native 内创建短生命周期 std::thread,仅用于演示。 |
log* |
absl/log |
通过 ToSinkOnly 等将日志正文捕获到返回值字符串;InitializeLog 在进程内通常仅首次有效。 |
flags* |
absl/flags |
本 so 内注册的演示用 ABSL_FLAG(如 abseil_demo_int 等)的读写与解析示例。 |
debugging* |
absl/debugging |
栈回溯摘要、符号化、LeakCheck 相关状态说明等(未在示例中安装进程级故障信号处理器,避免副作用)。 |
profiling* |
absl/profiling |
哈希表剖析数据预览、Hashtablez 全局配置、ExponentialBiased 等。 |
base* |
absl/base |
bit_cast、字节序、call_once、周期时钟采样、ErrnoSaver 等与 base 相关的可运行 API。 |
popcount*、rotlU32、uint128*、int128ToDecFromHalves 等 |
absl/numeric(bits、int128) |
位运算与 128 位整数十进制字符串形式往返。 |
4.3 实现与维护注意点
| 项 | 建议 |
|---|---|
| 新增导出 | 在 napi_init.cpp 的 napi_property_descriptor 表中增加一项,并在 Index.d.ts 中增加同名声明;复杂返回值优先用 普通对象 + 字段(与现有 *Result 一致),避免在 TS 侧难以表达的类型。 |
| 线程与全局状态 | sync*、logInitializeOnce、flags*、debuggingSymbolizerInitOnce 等会改变进程内全局或线程状态,演示页重复调用时行为可能与「首次调用」不同,属预期现象。 |
| 性能与体积 | 本文件为教学演示聚合了大量符号;若你仅需要 Abseil 的某一子集,可复制对应绑定函数并 裁剪 Init 中的描述符表与 CMakeLists.txt 中的 absl::* 链接项(见第 4.4 节)。 |
4.4 最小调用示例(ArkTS)
下列接口仍可作为「从 ArkTS 试通 Native」的最小用例;更多接口用法见各 pages/*Module.ets 与 ModuleExamples.ets。
import testNapi from 'libentry.so';
const sum = testNapi.add(2, 3);
const cat = testNapi.strCat('Hello', 'Abseil');
const st = testNapi.status(0); // StatusResult:含 ok、code、codeName、message、statusString 等
const ms = testNapi.now();
const sv = testNapi.stringView('Hello HarmonyOS');
5. ArkTS 调用 Native 接口
ArkTS 通过 ohpm 本地依赖 将 libentry.so 映射到带类型的包目录;业务页面再 import 该模块即可调用第 5 节注册的 NAPI。本仓库中 首页 Index.ets 不直接调用 testNapi,而是拆成 Tab 与子页;真正密集调用 Native 的是 ModuleExamples.ets、各 *Module.ets 专页等。
5.1 依赖声明与导入方式
模块级依赖(entry/oh-package.json5)将 libentry.so 指向类型与包元数据所在目录:
{
"dependencies": {
"libentry.so": "file:./src/main/cpp/types/libentry"
}
}
该目录下的 Index.d.ts 即为 TypeScript/ArkTS 侧类型来源;oh-package.json5(types/libentry 内)需与 NAPI 注册保持一致(一般由模板与 napi_init.cpp 同步维护)。
在任意 .ets 页面或组件中导入:
import testNapi from 'libentry.so';
之后即可使用 testNapi.add、testNapi.strCat 等与 Index.d.ts 中 export 一致的成员。
5.2 主界面结构(pages/Index.ets)
当前首页为 底部 Tabs,三个页签分别加载子组件(不在 Index 内写 NAPI 调用):
| Tab | 组件 | 作用 |
|---|---|---|
| 概述 | IndexOverviewTab |
工程与适配信息总览。 |
| 介绍 | IndexIntroTab |
模块卡片网格;「查看说明」 跳转说明页。 |
| 示例 | IndexExamplesTab |
已标注 hasNativeDemo 的模块;「打开示例」 进入专页或通用示例页。 |
路由 API 在 common/ModuleRouteHelper.ets(实现见 AbseilNavigation.ets):openModuleDocumentation(moduleId) → pages/ModuleDoc;openModuleInteractiveDemo(moduleId) → 专页(由 DEDICATED_NAV_NAMES 映射到 NavPathStack 名)或 pages/ModuleExamples。
5.3 哪些页面会用到 libentry.so
| 类型 | 代表路径 | 是否 import libentry.so |
|---|---|---|
| 纯说明 | pages/ModuleDoc.ets + home/ModuleDocBody.ets |
否,仅展示 AbseilModuleMeta 文案。 |
| 通用示例 | pages/ModuleExamples.ets |
是,供 未列入专页表的 moduleId(如 napi_base、strings、status);time 等已走专页。 |
| 专页 | pages/TimeModule.ets、ContainerModule.ets、… |
是,按主题拆分交互,避免单文件过大。 |
| 首页 Tab | home/Index*.ets |
否,只负责导航与元数据展示。 |
新增专页时:在 resources/base/profile/main_pages.json 注册 pages/xxx,在 Index.ets 的 navDestination 增加对应 NavDestination,并在 AbseilNavigation.ets 的 DEDICATED_NAV_NAMES 中增加 moduleId → 导航名(与 pushPathByName 一致)。
5.4 推荐调用习惯:安全封装与 UI 卡片
Native 侧若 napi_throw 或断言失败,ArkTS 可能收到异常。本仓库在 common/NapiDemoSupport.ets 中提供 runSafelyNapi(name, fn):在 try/catch 中执行 () => testNapi.xxx(...),返回 { ok, value?, error? },并把错误写入 hilog,便于在 UI 上展示「错误:…」而不打断页面。
演示 UI 使用 common/AbseilDemoCard.ets:推荐 intro / detail / arktsExample(介绍、示例详情、ArkTS 调用示例代码块),以及 title / result(@Prop 绑定) 与 onRun(内用 runSafelyNapi 写回 @State)。仍兼容仅填 desc 的旧用法。专页与 ModuleExamples 共用同一卡片组件。
5.5 代码片段:在组件中调用一项 NAPI
import testNapi from 'libentry.so';
import { runSafelyNapi } from '../common/NapiDemoSupport';
// 在 @Component 内:
@State addResult: string = '';
// 例如在 Button.onClick 或 AbseilDemoCard.onRun 中:
const r = runSafelyNapi('add', () => testNapi.add(2, 3) as Object);
this.addResult = r.ok ? `add(2,3) = ${r.value as number}` : `错误:${r.error}`;
直接调用(无 try/catch)在确定不会抛错的小脚本中也可行,与第 5.4 节最小示例一致:
import testNapi from 'libentry.so';
const n: number = testNapi.now();
6. 编译构建
6.1 推荐方式:DevEco Studio
- 使用 DevEco Studio 打开工程根目录(含
build-profile.json5、entry模块)。 - 菜单 Build > Build Hap(s)/APP(s)(或工具栏对应构建按钮)执行完整构建。
- 修改了
CMakeLists.txt、napi_init.cpp或thirdparty/abseil-cpp后,若 CMake 未自动重新配置,可执行 Build > Clean Project 后再 Rebuild,避免沿用旧的.cxx缓存。
构建过程中,NDK 会按当前产品配置分别 arm64-v8a 编译 Native 代码;Abseil 以静态库形式链入 libentry.so,再随 entry 模块打入 HAP。
6.2 命令行构建(可选)
HarmonyOS 工程通常通过 hvigor 驱动构建。是否能在本机命令行直接执行,取决于是否已安装 ohpm/hvigor 并配置好环境变量;本仓库根目录未附带 hvigorw 包装脚本,若你本地没有统一 CLI,请以 IDE 构建为准。
在已配置命令行工具的环境下,常见做法是在工程根目录执行 hvigor 提供的 assemble 类任务(具体任务名以当前 SDK / 工程模板为准,可在 DevEco 的 Build Output 或官方文档中查阅)。构建失败时优先查看 Build 窗口中的 Native 编译日志(CMake、clang++ 链接行)。
6.3 构建产物与查找 libentry.so
HAP 包路径随 product / buildMode 略有不同,一般在 entry/build/ 下。libentry.so 的中间产物常出现在 entry/build/default/intermediates/ 下按 ABI 分子目录(例如带 arm64-v8a、armeabi-v7a 的路径);精确子路径会随 HarmonyOS SDK 版本变化。若在文档中写死深层路径容易过期,建议在 IDE 中 全局搜索文件名 libentry.so,或查看当次构建日志中的链接输出。
下表给出典型输出目录形态(default 为常见 product 名,请以本机为准):
| ABI | 常见查找线索 |
|---|---|
| arm64-v8a | 在 entry/build/default/ 下搜索 arm64-v8a 与 libentry.so |
安装到真机/模拟器后,应用加载的仍是包内随 HAP 打包的 同一 libentry.so,无需手动拷贝到设备。
6.4 构建检查清单
| 项 | 说明 |
|---|---|
CMakeLists.txt 与第 4 节一致 |
absl_DIR、find_package(absl CONFIG)、target_include_directories 缺一会出现头文件或链接错误。 |
| ArkTS 编译通过 | Index.d.ts 与 napi_init.cpp 不一致时,常见为类型检查报错或运行期缺属性。 |
7. 常见问题
Q1: 编译报错找不到 absl/... 头文件
- 确认
thirdparty/abseil-cpp/<arch>/include/absl/存在,且<arch>与当前OHOS_ARCH一致。 - 确认
target_include_directories(entry PRIVATE ${ABSL_ROOT}/include)已配置(见第 4.2 节),不要只改全局include_directories却漏掉ABSL_ROOT。
Q2: 链接阶段 undefined reference 或大量缺符号
- Abseil 以多个
absl::*CMake 目标组织静态库,目标之间存在传递依赖;不要随意删减target_link_libraries中的列表,除非你明确只保留子集并已验证链接(见第 4.4 节)。 - 确认未混用 不同 LTS 版本 或 错误 ABI 的
libabsl_*.a。
Q3: find_package(absl) 失败 / Could not find absl
- 使用
set(absl_DIR ${ABSL_ROOT}/lib/cmake/absl)且find_package(absl REQUIRED CONFIG);absl_DIR必须指向abslConfig.cmake所在目录(lib/cmake/absl),而不是lib/cmake根目录。
Q4: 是否支持 x86_64 模拟器等其它架构?
当前预编译包与 CMake 分支仅处理 armeabi-v7a、arm64-v8a。若需 x86_64 等,需在 oh-tpc/abseil-cpp 获取对应架构产物,并在 CMakeLists.txt 中扩展 OHOS_ARCH 分支。
Q5: ArkTS 报找不到 libentry.so 上的属性,或类型与运行不一致
- 属性名须与
napi_init.cpp里napi_define_properties注册的字符串 完全一致(大小写敏感)。 entry/oh-package.json5中依赖"libentry.so": "file:./src/main/cpp/types/libentry"须存在;子包内oh-package.json5的types应指向Index.d.ts。- 修改
Index.d.ts后若 IDE 仍报错,可 Invalidate Caches / 重新同步 或 Clean 后重编。
Q6: 点击「运行」后 UI 结果字符串不更新
本示例中 AbseilDemoCard 使用 @Prop 绑定 result。若把卡片放在 @Builder 里并传入字面量或未绑定的状态,可能出现 子组件不随 @State 刷新。请对照 AbseilDemoCard.ets 的用法,保持 result 与外层 @State 双向绑定(见第 6.4 节)。
Q7: 跳转到新页面提示路由失败或白屏
- 新增
pages/XXX.ets后必须在entry/src/main/resources/base/profile/main_pages.json的src数组中注册。 - 从首页进入专页时,还需在
AbseilNavigation.ets的DEDICATED_NAV_NAMES中配置moduleId → 导航名,并与Index.ets里NavDestination.name一致(见第 6.3 节)。
Q8: sync* 等演示卡顿、偶现失败
synchronization 相关 NAPI 会在 Native 内创建 短生命周期线程 做演示。在真机低电量、调试器附加或极端调度下,超时类演示可能比桌面更敏感;若仅偶发,可先 重试;若必现,请结合 hilog 与 Native 日志排查是否被系统限制多线程。
Q9: 日志里出现 NAPI 抛错 / runSafelyNapi 返回 ok: false
多为 参数非法、Native 断言 或 未先初始化(如部分 debugging* / log* 依赖首次 Init)。请先看 error 字符串与 hilog 中的 abseilDemo 标签;专页上尽量 按界面提示的顺序点击(例如先 Initialize 再 Symbolize)。
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐

所有评论(0)