【鸿蒙优选三方库】@ohos/aki:一行代码让 ArkTS 调 C++
裸写 NAPI 绑定一个
add(a, b),要写三十行napi_get_value_int32、napi_create_int32。绑定一个 C++ 类?更是一场噩梦。@ohos/aki把它压缩成一行------同样的功能,代码量减少一半以上。
📦 仓库地址 |ohpm install @ohos/aki| v1.3.0 | Apache-2.0
它解决什么问题
鸿蒙应用一旦要复用 C/C++ 库、做高性能计算、调底层能力,就绕不开 Node-API。但 NAPI 的样板代码量惊人:
- 取参数、转类型、创建返回值,全是手写
- 异步要自己管
AsyncWorker/ThreadSafeFunction - C++ 类、继承、枚举、Promise 都要手写桥接
- JS 异常、C++ 异常、生命周期管理让人掉头发
AKI(Alpha Kernel Interacting)在 NAPI 之上做了一层语法糖:
cpp
// AKI:一行绑定
JSBIND_FUNCTION(add) { return args[0].As<int>() + args[1].As<int>(); }
JSBIND_ADDON(add)
typescript
// ArkTS:直接调
import { add } from 'libentry.so'
console.info('3 + 5 = ' + add(3, 5))
核心能力
| 能力 | 说明 |
|---|---|
| 函数绑定 | JSBIND_FUNCTION 一行 |
| 类绑定 | JSBIND_CLASS + JSBIND_METHOD + JSBIND_FIELD |
| 自动类型转换 | 基本类型、字符串、ArrayBuffer、对象、回调 |
| Promise 桥接 | aki::Promise,支持 Then/Catch |
| AsyncWorker | 耗时任务不阻塞 UI |
| TaskRunner | 跨线程调度 |
| 线程安全函数 | 多线程回调 ArkTS |
aki::Value |
通用 JS 值包装 |
Persistent |
跨线程持有 JS 引用防 GC |
| 混合开发 | 与现有 NAPI 代码共存 |
30 秒上手
源码依赖(推荐):
bash
cd entry/src/main/cpp
git clone https://gitcode.com/CPF-ApplicationTPC/aki.git
cmake
add_subdirectory(aki)
target_link_libraries(hello PUBLIC aki_jsbind)
绑定一个 C++ 类:
cpp
#include <aki/jsbind.h>
class Calculator {
public:
Calculator() : result_(0) {}
int Add(int a, int b) { result_ = a + b; return result_; }
int GetResult() const { return result_; }
private:
int result_;
};
JSBIND_CLASS(Calculator) {
JSBIND_CONSTRUCTOR();
JSBIND_METHOD(Add);
JSBIND_METHOD(GetResult);
}
JSBIND_ADDON(Calculator)
typescript
import { Calculator } from 'libentry.so'
const calc = new Calculator()
calc.Add(3, 5)
console.info(calc.GetResult()) // 8
异步(不阻塞 UI):
cpp
JSBIND_FUNCTION(fetchUser) {
aki::Promise promise;
std::thread([promise]() mutable {
std::this_thread::sleep_for(std::chrono::seconds(1));
promise.Resolve("user_001");
}).detach();
return promise;
}
typescript
const userId = await fetchUser() // 直接 await
社区已解决的典型问题
aki::Value 跨线程使用出问题 (#310) 升级到新版后,aki::Value 跨线程使用触发多线程检测报错,而 1.2.25 版本没有。原因是旧版用全局线程本地 env,跨线程访问绕过了系统检查;新版改为存储创建线程的 env。维护者明确回复:napi_value 在哪个线程产生就只能在该线程使用,旧版能跑通其实是 AKI 的漏洞,实际运行存在稳定性隐患。
正确做法是跨线程只传纯 C++ 数据:
cpp
// ❌ 把 aki::Value 带到子线程
std::thread([jsValue]() { auto d = jsValue.As<int>(); }).detach();
// ✅ JS 线程取出纯数据,只把数据带到子线程
int data = args[0].As<int>();
std::thread([data, promise]() mutable {
promise.Resolve(heavyCompute(data));
}).detach();
release 包崩溃无法定位 (#316) 线上包是 release 编译的,崩溃后没有符号表可回溯堆栈。仓库已提出符号表备份需求。发版时自己也要归档未 strip 的 .so,否则线上崩溃只能干瞪眼。
空指针崩溃 (#307) master 已对空指针场景做兼容处理,避免传入空值直接崩溃。但框架兼容是兜底不是免责,C++ 侧仍应主动做空值校验。
aki::Promise 支持 Then/Catch (#306) 此前 C++ 侧调用 JS 异步函数后无法处理其返回的 Promise。现已支持,实现真正的双向异步互调。
适合谁用
- 复用现有 C/C++ 库:OpenCV、SQLite、Eigen、加密算法
- 高性能计算:图像处理、音视频编解码、科学计算
- Native 插件开发:很多鸿蒙三方库底层就用 AKI
- NAPI 代码改造:渐进式迁移,与现有代码共存
- 跨语言团队协作:C++ 工程师专注算法,ArkTS 工程师专注 UI
303 个 Issue 已关闭。AKI 的价值不只是少写代码------它把 NAPI 里那些容易出错的类型转换、线程安全、生命周期管理都封装好了,踩坑概率显著下降。
如果你正在为鸿蒙应用接入 C/C++,AKI 是那把让你"写一次就上头"的瑞士军刀。