【鸿蒙优选三方库】@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 之上做了一层语法糖:

// AKI:一行绑定
JSBIND_FUNCTION(add) { return args[0].As<int>() + args[1].As<int>(); }
JSBIND_ADDON(add)
// 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 秒上手

源码依赖(推荐):

cd entry/src/main/cpp
git clone https://gitcode.com/CPF-ApplicationTPC/aki.git
add_subdirectory(aki)
target_link_libraries(hello PUBLIC aki_jsbind)

绑定一个 C++ 类:

#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)
import { Calculator } from 'libentry.so'

const calc = new Calculator()
calc.Add(3, 5)
console.info(calc.GetResult())   // 8

异步(不阻塞 UI):

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;
}
const userId = await fetchUser()   // 直接 await

社区已解决的典型问题

aki::Value 跨线程使用出问题(#310)
升级到新版后,aki::Value 跨线程使用触发多线程检测报错,而 1.2.25 版本没有。原因是旧版用全局线程本地 env,跨线程访问绕过了系统检查;新版改为存储创建线程的 env。维护者明确回复:napi_value 在哪个线程产生就只能在该线程使用,旧版能跑通其实是 AKI 的漏洞,实际运行存在稳定性隐患。

正确做法是跨线程只传纯 C++ 数据:

// ❌ 把 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 是那把让你"写一次就上头"的瑞士军刀。

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐