AKI
简介
AKI (Alpha Kernel Interacting) 是一款简化Node-API(C/C++插件)语法的ArkTs FFI开发框架,针对OpenHarmony Native开发提供ETS与C/C++跨语言访问场景解决方案。支持极简语法糖使用方式,一行代码完成ETS与C/C++的无障碍跨语言互调,所键即所得。
效果展示
写同样功能的代码
-
napi代码

-
aki代码

-
框架展示

下载与安装
依赖配置(2选1)
-
源码依赖(推荐)
指定cpp路径下(如:项目根路径/entry/src/main/cpp)
cd entry/src/main/cpp git clone https://gitcode.com/openharmony-sig/aki.gitCMakeLists.txt添加依赖(假定编译动态库名为:libhello.so):
add_subdirectory(aki) target_link_libraries(hello PUBLIC aki_jsbind) -
ohpm har包依赖
指定路径下(如:项目根路径/entry),输入如下命令安装ohpm har包依赖
cd entry ohpm install @ohos/akiCMakeLists.txt添加依赖(假定编译动态库名为:libhello.so):
set(AKI_ROOT_PATH ${CMAKE_CURRENT_SOURCE_DIR}/../../../oh_modules/@ohos/aki) # 设置AKI根路径 set(CMAKE_MODULE_PATH ${AKI_ROOT_PATH}) find_package(Aki REQUIRED) ... target_link_libraries(hello PUBLIC Aki::libjsbind) # 链接二进制依赖 & 头文件
C++ 标准兼容性
AKI 同时支持 C++17 和 C++11,默认开启 C++17。由于 AKI 的核心实现大量依赖 C++ 模板元编程(如 napi_value.h、napi_value_trait.h 等头文件),C++ 标准设置不仅影响 AKI 自身编译,也会通过头文件引入影响用户工程的编译。在源码依赖和 HAR 包依赖两种模式下,C++ 标准和宏定义(AKI_ENABLE_CXX_STANDARD_11=1)均通过 CMake 属性自动传播到链接 AKI 的用户目标,无需额外配置。
切换到 C++11 模式,在项目的 build-profile.json5(如:项目根路径/entry/build-profile.json5)中添加编译参数:
{
"apiType": "stageMode",
"buildOption": {
"externalNativeOptions": {
"path": "./src/main/cpp/CMakeLists.txt",
"arguments": "-DAKI_ENABLE_CXX_STANDARD_11=ON",
"cppFlags": "",
}
},
"targets": [
{
"name": "default"
}
]
}
注意:
- OHPM 上发布的官方
@ohos/akiHAR 包为 C++17 预编译产物。若需通过 HAR 方式使用 C++11,需自行从源码构建 C++11 版本的 HAR(在 HAR 的build-profile.json5arguments中添加-DAKI_ENABLE_CXX_STANDARD_11=ON,然后重新构建打包)。- C++11 模式下,
std::optional<T>类型转换不可用(即 ETS 与 C/C++ 之间的 Optional 类型映射,以及相关的JSBIND_PROPERTYoptional 属性绑定)。其余所有 AKI 功能(全局函数、类绑定、枚举绑定、回调、线程安全函数、TaskRunner、AsyncWorker、aki::Value等)均通过内部 C++11 降级实现保持完全可用。- AKI 测试套件已覆盖 C++11 模式验证:optional 相关测试在 C++11 模式下跳过,其余功能测试均可通过。
约束与限制
兼容性
在下述版本验证通过
- DevEco Studio NEXT Release: 5.0.3.900, SDK: API12(Command Line Tools 5.0.3.900)
- DevEco Studio: 4.0.0.400, SDK: API10(4.0.9.6)
- DevEco Studio: 3.1.0.500, SDK: API9(3.2.12.2)
权限要求
无
使用示例
简单示例
Native C/C++ 侧代码#include <string>
#include <aki/jsbind.h>
std::string HelloWorld()
{
return "Hello World";
}
JSBIND_GLOBAL()
{
JSBIND_FUNCTION(HelloWorld);
}
JSBIND_ADDON(ModuleName);
ArkTS 侧代码
import libaki from "lib<ModuleName>.so"
console.log(libaki.HelloWorld());
补充示例
Native C/C++ 侧代码#include <string>
#include <aki/jsbind.h>
// 类/结构体
class Person {
public:
Person(std::string n,int a, double w)
: name(n), age(a), weight(w) {};
std::string SayHello() {
return "HELLO AKI";
}
std::string name;
int age;
double weight;
};
// 全局函数
Person MakePerson() {
Person person("aki", 99, 128.8);
return person;
}
// AKI JSBind 语法糖
JSBIND_GLOBAL() {
JSBIND_FUNCTION(MakePerson);
}
JSBIND_CLASS(Person) {
JSBIND_CONSTRUCTOR<std::string, int, double>();
JSBIND_METHOD(SayHello);
JSBIND_PROPERTY(name);
JSBIND_PROPERTY(age);
JSBIND_PROPERTY(weight);
}
JSBIND_ADDON(ModuleName);
ArkTS 侧代码
import libaki, {Person} from "lib<ModuleName>.so"
// 调用 C/C++ Person 构造函数
let P1:Person = new Person("aki", 10 , 100);
// 访问类/结构体成员属性
console.log(P1.name + " " + P1.age + " " + P1.weight);
// 调用类/结构体成员函数
P1.SayHello();
// 调用 C/C++ 全局函数
let P2:Person = libaki.MakePerson();
// 极简使用,支持全类型转换
console.log(P2.name + " " + P2.age + " " + P2.weight);
注意事项
所有通过aki绑定的函数、类、类属性等,与Node-API规则一致,都需要写到对应的导出文件中,比如index.d.ts
使用说明
⚠️ 重要提示:一个APP中,多个模块或者多个依赖项引入aki,需要保证各个aki版本一致,因为APP运行时各模块在同一进程中共享符号表,不同的aki版本加载的API符号可能会不一致,会出现各种crash。
- 了解ETS和C/C++两者语言之间的数据类型映射
- 了解如何通过AKI,让ETS和C/C++之间建立联系的方法
数据类型映射表
| ETS | C/C++ |
|---|---|
| Boolean | bool 参考 |
| Number | uint8_t, int8_t, uint16_t, int16_t, short, int32, int64, uint32_t, uint64_t, float, double, enum 参考 |
| String | const char*, std::string 参考 |
| Array | std::vector<T>, std::array<T, N> 参考 |
| Function | std::function<R (P...)> aki::Callback<R (P...)> aki::SafetyCallback<R (P...)> 参考 |
| Class Object | class |
| JsonObject | std::map<std::string,T> 参考 |
| Map/HashMap/HashSet | std::map<K,T>, std::unordered_map<K,T>, std::unordered_set<T> 参考 |
| ArrayBuffer, TypedArray |
aki::ArrayBuffer 参考 |
| Promise | JSBIND_PFUNCTION, JSBIND_PMETHOD |
| Optional | std::optional<T> 参考 |
| any | aki::Value, napi_value |
NOTE: 带有阴影部分的表示已支持
const char* 是以引用方式传递参数,如遇到异步操作,请使用传值方式:std::string
Boolean
如下示例,开发者直接声明函数入参及返回值类型,使用AKI绑定后,框架自适应对 C/C++ 的 bool 及 ETS 的 Boolean 类型进行转化。
示例:
-
C++
#include <aki/jsbind.h> bool Foo(bool flag) { ... return true; } JSBIND_GLOBAL() { JSBIND_FUNCTION(Foo, "foo"); } JSBIND_ADDON(hello) -
ETS
import libAddon from 'libhello.so' let flag = libAddon.foo(true);
Number
如下示例,开发者直接声明函数入参及返回值类型,使用AKI绑定后,框架自适应对 C/C++ 的 uint8_t, int8_t, uint16_t, int16_t, short, int32, int64, uint32_t, uint64_t, float, double, enum 及 ETS 的 Number 类型进行转化。
float:浮点型转换时存在精度丢失,对于高精度场景,请使用double;enum:枚举类型的转化请参考
示例:
-
C++
#include <aki/jsbind.h> int Foo(int num) { ... return 666; } JSBIND_GLOBAL() { JSBIND_FUNCTION(Foo, "foo"); } JSBIND_ADDON(hello) -
ETS
import libAddon from 'libhello.so' let num = libAddon.foo(888);
String
如下示例,开发者直接声明函数入参及返回值类型,使用AKI绑定后,框架自适应对 C/C++ 的 const char*, std::string 及 ETS 的 String 类型进行转化。
const char*是以引用方式传递参数,如遇到异步操作,请使用传值方式:std::string;
示例:
-
C++
#include <aki/jsbind.h> std::string Foo(const char* c_str, std::string str) { ... return "AKI 666"; } JSBIND_GLOBAL() { JSBIND_FUNCTION(Foo, "foo"); } JSBIND_ADDON(hello) -
ETS
import libAddon from 'libhello.so' let str = libAddon.foo("AKI", "666");
Array
如下示例,开发者直接声明函数入参及返回值类型,使用AKI绑定后,框架自适应对 C/C++ 的 std::vector<T>, std::array<T, N> 及 ETS 的 [] 类型进行转化。
- 数组类型仅支持同种类型的数组声明;
- aki暂不支持
std::vector<class>。替代方案为使用std::vector<aki::Value>接收ArkTs侧传下来的Array<class>;
示例:
-
C++
#include <aki/jsbind.h> std::vector<double> Foo(std::array<int, 3>) { std::vector<double> result; ... return result; } JSBIND_GLOBAL() { JSBIND_FUNCTION(Foo, "foo"); } JSBIND_ADDON(hello) -
ETS
import libAddon from 'libhello.so' let array = libAddon.foo([1, 2, 3]);
Map/HashMap/HashSet
AKI 支持使用 C/C++ 的 std::map<K, T>, std::unordered_map<K, T>, std::unordered_set<T> 映射 ETS 的 Map/HashMap/HashSet 类型。
- Map/HashMap 支持的键值类型为:
std::string,int,long,aki::Value - HashSet 支持的元素类型为:
int,long,std::string,aki::Value - 使用
aki::Value作为键或元素时,需要配合aki::Value::HashPair哈希函数使用
示例:
-
C++
#include <aki/jsbind.h> #include <unordered_map> #include <unordered_set> std::map<std::string, int> FooMap() { std::map<std::string, int> map = {{"key1", 1}, {"key2", 2}}; return map; } std::unordered_map<std::string, int> FooHashMap() { std::unordered_map<std::string, int> hashMap = {{"key1", 1}, {"key2", 2}}; return hashMap; } std::unordered_set<int> FooHashSet() { std::unordered_set<int> hashSet = {1, 2, 3}; return hashSet; } JSBIND_GLOBAL() { JSBIND_FUNCTION(FooMap); JSBIND_FUNCTION(FooHashMap); JSBIND_FUNCTION(FooHashSet); } JSBIND_ADDON(hello) -
ETS
import libAddon from 'libhello.so' let map = libAddon.FooMap(); let hashMap = libAddon.FooHashMap(); let hashSet = libAddon.FooHashSet();
Optional
AKI 支持使用 C++ 的 std::optional<T> 类型,用于表示可能不存在的值。
- ETS 侧
undefined会被转换为std::nullopt - C++ 侧
std::nullopt会被转换为 ETS 的undefined
示例:
-
C++
#include <aki/jsbind.h> #include <optional> std::optional<int> FooOptional(bool hasValue) { if (hasValue) { return 42; } return std::nullopt; } JSBIND_GLOBAL() { JSBIND_FUNCTION(FooOptional); } JSBIND_ADDON(hello) -
ETS
import libAddon from 'libhello.so' let value1 = libAddon.FooOptional(true); // 返回 42 let value2 = libAddon.FooOptional(false); // 返回 undefined
ArrayBuffer
二进制数据缓冲区ArrayBuffer, TypedArray 是 ETS AKI 提供了内建结构体:aki::ArrayBuffer用来支持该特性:
-
GetData()*获取 ArrayBuffer 数组缓冲区地址,aki::ArrayBuffer 本身不申请数据内存,data 都来源于ETS引擎分配的内存,也无需做内存生命周期管理,禁止对该内存进行危险的释放。 -
GetLength()获取 ArrayBuffer 数组缓冲区长度,以单字节为计量单位。 -
GetTyped()获取 ArrayBuffer 数组缓冲区的类型化类型。 -
GetCount()获取 ArrayBuffer 数组缓冲区的类型化数据元素个数。
示例:
- C++
#include <aki/jsbind.h>
aki::ArrayBuffer PassingArrayBufferReturnArrayBuffer(aki::ArrayBuffer origin) {
aki::ArrayBuffer buff(origin.GetData(), origin.GetCount());
uint8_t* data = buff.GetData();
data[4] = 4;
data[5] = 5;
data[6] = 6;
data[7] = 7;
return buff;
}
- ETS
import libAddon from 'libarraybuffer2native.so'
let buff: ArrayBuffer = new ArrayBuffer(8);
let uint8Buff1: Uint8Array = new Uint8Array(buff);
uint8Buff1[0] = 0;
uint8Buff1[1] = 1;
uint8Buff1[2] = 2;
uint8Buff1[3] = 3;
let result: ArrayBuffer = libAddon.PassingArrayBufferReturnArrayBuffer(buff);
uint8Buff1 = new Uint8Array(result);
let message: String = uint8Buff1.toString();
JsonObject
ETS支持使用JsonObject表示key-value结构的数据类型,如:
{
name: 'hanmeimei',
age: '17',
date: '1999-02-02'
}
AKI支持使用C/C++的std::map<std::string, T>映射ETS的JsonObject。
-
与
std::map<std::string, T>对应的JsonObject必须约束value类型一致 -
C++
void Foo(std::map<std::string, int> obj)
{
for (auto& iter : obj) {
......; // key: iter.first; value: iter.second
}
}
JSBIND_GLOBAL() {
JSBIND_FUNCTION(Foo);
}
- ETS
import libmap_for_object from 'libmap_for_object.so'
let a = {age: 100};
libmap_for_object.Foo(a);
Function
Function是JS的一种基本数据类型,当JS传入Function作为参数时,Native可在适当的时机调用触发回调。AKI 支持如下3中C++数据类型作为参数处理回调:
- aki::Callback<R (P...)>:指定回调类型为
R (*)(P...)的高性能回调。非线程安全,禁止在非JS线程使用,否则会发生异常; - aki::SafetyCallback<R (P...)>:指定回调类型为
R (*)(P...)的线程安全回调。因为需要创建线程安全资源,所以性能不如aki::Callback; - std::function<R (P...)>:用法与aki::SafetyCallback一致;
对象引用与指针
C++ 对象作为参数和返回类型,在 C++ & ETS 代码中可以使用如下形式进行传递:
- 值传递;
- 引用(T&)与指针(T*)传递;
- Example
ETS与C/C++建立联系步骤
- 快速接入AKI后正确包含头文件
#include <aki/jsbind.h>
注:使用aki只有一种方式,包含头文件aki/jsbind.h;不能在没有包含aki/jsbind.h的情况下只包含其他头文件,比如
#include "aki/definer/function_definer.h"
#include "aki/definer/class_definer.h"
#include "aki/value/value.h"
...
如果错误包含头文件可能会出现以下错误
1.error: no member named xxx in aki::Binder 异常
2.error: no template named xxx
3.error: use of undeclared xxx
...
- 注册 AKI 插件、FFI 特性
#include <aki/jsbind.h>
// Step 1 注册 AKI 插件
JSBIND_ADDON(hello) // 注册 AKI 插件名: 即为编译*.so名称,规则与NAPI一致
// Step 2 注册 FFI 特性、使用 JSBind 工具宏声明需要被绑定的类、函数
JSBIND_GLOBAL()
{
JSBIND_FUNCTION(funcName);
}
JSBIND_CLASS(className) {
JSBIND_CONSTRUCTOR<>();
JSBIND_METHOD(xxx);
JSBIND_PROPERTY(xxx);
JSBIND_PROPERTY(xxx);
···
}
- 导出绑定的类、函数等
接口说明
JSBind语法糖
| 语法糖 | AKI | 说明 | |
|---|---|---|---|
| 插件注册 | ETS 访问 C++ | JSBIND_ADDON | 注册OpenHarmony Native 插件。 使用指导 |
| C++ 访问 ETS | aki::Value::FromGlobal | 获取 ETS 侧globalThis下的属性。 使用指导 |
|
| 全局函数 | ETS 访问 C++ | JSBIND_FUNCTION JSBIND_PFUNCTION |
绑定 C++ 全局方法,ETS 可调用。 使用指导 |
| C++ 访问 ETS | aki::Value::operator() | ETS 全局方法函数调用运算符,C++ 可调用。 使用指导 |
|
| 类构造函数 | ETS 访问 C++ | JSBIND_CONSTRUCTOR<> | 绑定 C++ 类构造函数,ETS 可调用。构造函数可重载,需指定构造函数参数类型。 使用指导 |
| C++ 访问 ETS | - | 暂不支持 | |
| 类成员函数 | ETS 访问 C++ | JSBIND_METHOD JSBIND_PMETHOD |
绑定 C++ 类成员函数,ETS 可调用。 成员函数可以为:类静态函数,类成员函数,const类成员函数。 使用指导 |
| C++ 访问 ETS | aki::Value::CallMethod | 调用 ETS 对象的成员函数。 使用指导 |
|
| 类成员属性 | ETS 访问 C++ | JSBIND_PROPERTY JSBIND_FIELD |
JSBIND_PROPERTY 绑定 C++类成员属性; JSBIND_FIELD 绑定 C++ 类成员属性访问器(Get/Set)。 使用指导 |
| C++ 访问 ETS | aki::Value::operator[] | JS对象的属性访问运算符 使用指导 |
|
| 枚举类型 | ETS 访问 C++ | JSBIND_ENUM JSBIND_ENUM_VALUE |
C/C++侧默认枚举类型为POD中的int32_t,ETS侧对应的枚举类型属性为readonly。 使用指导 |
| C++ 访问 ETS | - | - | |
插件注册
JSBIND_ADDON(addonName)
使用JSBIND_ADDON注册OpenHarmony Native 插件,可从 ETS import 导入插件。
参数:
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| addonName | - | Y | 注册的OpenHarmony native 插件名,可从 ETS import lib${addonName}.so 导入插件,插件名必须符合函数命名规则。 |
示例:
- C++
#include <string>
#include <aki/jsbind.h>
JSBIND_ADDON(addon0)
- ETS
import addon from 'libaddon0.so' // 插件名为:addon0
JSBIND_ADDON_X(addonName constructorAlias)
用法与JSBIND_ADDON相似,用于支持插件名有特殊符号的场景,如包含'-';
参数:
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| addonName | - | Y | 注册的OpenHarmony native 插件名,可从 ETS import lib${addonName}.so 导入插件,插件名可包含特殊符号,如:'-'。 |
| constructorAlias | - | Y | 插件预构造函数名,只需填写符合函数命名规则名称即可,无其它特殊含义 |
示例:
- C++
#include <string>
#include <aki/jsbind.h>
JSBIND_ADDONX(hello-world, HelloWorld)
- ETS
import addon from 'libhello-world.so' // 插件名为:hello-world
绑定全局函数
JSBIND_GLOBAL
用于圈定需要绑定的全局函数 scope。
JSBIND_FUNCTION(func, alias)
在JSBIND_GLOBAL作用域下使用JSBIND_FUNCTION绑定 C++ 全局函数后,可从 ETS 直接调用。
- 调度线程为 ETS 线程;
参数:
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| func | 函数指针 | Y | 被绑定的C++函数指针,当alias未被指定时,ETS与C++函数名相同。 |
| alias | string | N | 函数别名 |
示例:
- C++
#include <string>
#include <aki/jsbind.h>
std::string SayHello(std::string msg)
{
return msg + " too.";
}
JSBIND_GLOBAL()
{
JSBIND_FUNCTION(SayHello);
}
JSBIND_ADDON(hello);
- ETS
import aki from 'libhello.so' // 插件名
let message = aki.SayHello("hello world");
JSBIND_PFUNCTION(func, alias)
使用JSBIND_PFUNCTION绑定 C++ 全局函数后,从 ETS 使用同Promise方式相同的异步调用。
- 调度线程为工作线程,由 ArkCompiler Runtime 决定;
参数:
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| func | 函数指针 | Y | 被绑定的C++函数指针。 |
| alias | string | N | 函数别名 |
示例:
- C++
int AsyncTaskReturnInt() {
// Do something;
return -1;
}
JSBIND_GLOBAL() {
JSBIND_PFUNCTION(AsyncTaskReturnInt);
}
JSBIND_ADDON(async_tasks);
- ETS
import libAddon from 'libasync_tasks.so'
libAddon.AsyncTaskReturnInt().then(res => {
console.log('[AKI] AsyncTaskReturnInt: ' + res)
});
绑定类/结构体
AKI 提供 JSBIND_CLASS 对 C++ 类/结构体进行绑定,在JSBIND_CLASS作用域下可绑定:类构造函数、类成员函数、类成员属性的类特性。
JSBIND_CLASS(class)
参数:
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| class | class/struct | Y | 被绑定的C++类对象/结构体,ETS与C++类名相同。 |
类构造函数
在JSBIND_CLASS作用域下使用绑定 C++ 类/结构体构造函数,其中为了支持多态,可通过类型模板指定构造函数参数类型。
JSBIND_CONSTRUCTOR需要在JSBIND_CLASS的作用域下;
参数:
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| T | any | N | 构造函数参数类型,可变类型参数。 |
示例:
- C++
#include <string>
#include <aki/jsbind.h>
class TestObject {
public:
TestObject();
explicit TestObject(double) {
// ...
}
~TestObject() = default;
} // TestObject
JSBIND_CLASS(TestObject)
{
JSBIND_CONSTRUCTOR<>();
JSBIND_CONSTRUCTOR<double>();
}
JSBIND_ADDON(hello);
- ETS
import aki from 'libhello.so' // 插件名
var obj1 = new aki.TestObject();
var obj2 = new aki.TestObject(3.14);
绑定类成员函数
JSBIND_METHOD(method)
AKI 使用 JSBIND_METHOD 对C++ 的3种类成员函数进行绑定:类静态函数、类成员函数、const 类成员函数。
JSBIND_METHOD需要在JSBIND_CLASS的作用域下;- 调度线程为 JS 线程;
参数:
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| method | R (C:😗)(P...) | Y | 同时支持类静态函数、类成员函数、const 类成员函数。 |
示例:
使用 AKI 对C++类成员函数绑定
#include <string>
#include <aki/jsbind.h>
class TestObject {
public:
TestObject();
explicit TestObject(double) {
// ...
}
~TestObject() = default;
static double MultiplyObject(TestObject obj1, TestObject obj2) {
return obj1.value_ * obj2.value_;
}
double Multiply(double mult) {
value_ *= mult;
return value_;
}
private:
double value_;
} // TestObject
JSBIND_CLASS(TestObject)
{
JSBIND_CONSTRUCTOR<>();
JSBIND_CONSTRUCTOR<double>();
JSBIND_METHOD(MultiplyObject);
JSBIND_METHOD(Multiply);
}
JSBIND_ADDON(hello);
例:ETS 侧调用绑定的C++类成员函数
import aki from 'libhello.so' // 插件名
var obj1 = new aki.TestObject();
var obj2 = new aki.TestObject(3.14);
obj1.Multiply(-1);
aki.TestObject.MultiplyObject(obj1, obj2) // 静态方法
JSBIND_PMETHOD(method)
JSBIND_PMETHOD用于绑定 C++ 类成员函数,从 ETS 使用同Promise方式相同的异步调用。
- 调度线程为工作线程,由 ArkCompiler Runtime 决定;
参数:
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| method | 类成员函数指针 | Y | 被绑定的C++类成员函数指针。 |
示例:
- C++
class TaskRunner {
public:
TaskRunner() = default;
std::string DoTask() {
// Do something;
return "done.";
}
};
JSBIND_CLASS(TaskRunner) {
JSBIND_CONSTRUCTOR<>();
JSBIND_PMETHOD(DoTask);
}
int AsyncTaskReturnInt() {
// Do something;
return -1;
}
JSBIND_GLOBAL() {
JSBIND_PFUNCTION(AsyncTaskReturnInt);
}
JSBIND_ADDON(async_tasks);
- ETS
import libAddon from 'libasync_tasks.so'
let taskRunner = new libAddon.TaskRunner();
taskRunner.DoTask().then(res => {
console.log('[AKI] DoTask: ' + res)
});
libAddon.AsyncTaskReturnInt().then(res => {
console.log('[AKI] AsyncTaskReturnInt: ' + res)
});
绑定类成员属性
JSBIND_PROPERTY(property) new in 1.0.7
AKI 使用JSBIND_PROPERTY、JSBIND_FIELD 对 C++ 的类成员属性、类成员属性访问器进行绑定
JSBIND_PROPERTY需要在JSBIND_CLASS的作用域下;
参数:
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| property | T | Y | 类成员属性名。 |
示例:
- C++
#include <string>
#include <aki/jsbind.h>
class TestObject {
public:
explicit TestObject(double) {
// ...
}
~TestObject() = default;
double value_;
} // TestObject
JSBIND_CLASS(TestObject)
{
JSBIND_CONSTRUCTOR<double>();
JSBIND_PROPERTY(value_);
}
- ETS
import aki from 'libhello.so' // 插件名
var obj = new aki.TestObject(3.14);
obj.value = 1;
let value = obj.value;
JSBIND_FIELD(field, getter, setter)
AKI 使用JSBIND_FIELD 对 C++ 的类成员属性进行监听
-
JSBIND_FIELD需要在JSBIND_CLASS的作用域下; -
调度线程为 ETS 线程;
参数:
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| field | T | Y | 类成员属性名。 |
| getter | T (void) | Y | get属性访问器。 |
| setter | void (T) | Y | set属性访问器。 |
示例:
- C++
#include <string>
#include <aki/jsbind.h>
class TestObject {
public:
explicit TestObject(double) {
// ...
}
~TestObject() = default;
double GetValue() const {
return value_;
}
void SetValue(double value) {
value_ = value;
}
private:
double value_;
} // TestObject
JSBIND_CLASS(TestObject)
{
JSBIND_CONSTRUCTOR<double>();
JSBIND_FIELD("value", GetValue, SetValue);
}
- ETS
import aki from 'libhello.so' // 插件名
var obj = new aki.TestObject(3.14);
obj.value = 1;
let value = obj.value;
类继承
AKI 支持绑定 C++ 类继承关系,子类可以继承父类的成员属性和方法。
JSBIND_EXTEND(parentClass)
在JSBIND_CLASS作用域下使用JSBIND_EXTEND指定父类,子类可以访问父类的公开成员。
参数:
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| parentClass | class/struct | Y | 父类名。 |
示例:
- C++
#include <string>
#include <aki/jsbind.h>
class Person {
public:
Person(std::string name, int age) : name_(name), age_(age) {}
~Person() = default;
virtual void SetName(std::string name) { name_ = name; }
virtual void SetAge(int age) { age_ = age; }
virtual std::string GetName() const { return name_; }
virtual int GetAge() const { return age_; }
private:
std::string name_;
int age_;
};
class Student : public Person {
public:
Student(std::string name, int age) : Person(name, age) {}
~Student() = default;
void SetGrade(int grade) { grade_ = grade; }
int GetGrade() const { return grade_; }
void SetAge(int age) override { Person::SetAge(age); }
int GetAge() const override { return Person::GetAge(); }
private:
int grade_;
};
JSBIND_CLASS(Person)
{
JSBIND_CONSTRUCTOR<std::string, int>();
JSBIND_METHOD(SetName);
JSBIND_METHOD(SetAge);
JSBIND_METHOD(GetName);
JSBIND_METHOD(GetAge);
}
JSBIND_CLASS(Student)
{
JSBIND_EXTEND(Person); // 导入父类
JSBIND_CONSTRUCTOR<std::string, int>();
JSBIND_METHOD(SetGrade);
JSBIND_METHOD(GetGrade);
JSBIND_METHOD(SetAge);
JSBIND_METHOD(GetAge);
}
JSBIND_ADDON(hello);
- ETS
import aki from 'libhello.so'
let stu = new aki.Student("Tom", 18);
stu.SetGrade(90);
stu.SetAge(19);
stu.GetName(); // 调用继承的方法
stu.GetGrade();
绑定枚举类型
JSBind语法糖JSBIND_ENUM、JSBIND_ENUM_VALUE支持绑定 C/C++ 枚举类型,映射为 ETS 的Number类型。
- C/C++侧默认枚举类型为POD中的int32_t;
- ETS侧对应的枚举类型属性为
readonly;
JSBIND_ENUM(enum)
参数:
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| enum | enum | Y | 被绑定的C++枚举类型。 |
JSBIND_ENUM_VALUE(value)
参数:
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| value | enum::value | Y | 被绑定的C++枚举值。 |
示例:
- C++
#include <string>
#include <aki/jsbind.h>
enum TypeFlags {
NONE,
NUM,
STRING,
BUTT = -1
};
JSBIND_ENUM(TypeFlags) {
JSBIND_ENUM_VALUE(NONE);
JSBIND_ENUM_VALUE(NUM);
JSBIND_ENUM_VALUE(STRING);
}
TypeFlags Passing(TypeFlags flag) {
return flag;
}
JSBIND_GLOBAL()
{
JSBIND_FUNCTION(Passing);
}
JSBIND_ADDON(enumeration);
- ETS
import libAddon from 'libenumeration.so' // 插件名
console.log('AKI libAddon.TypeFlags.NONE = ' + libAddon.TypeFlags.NONE);
console.log('AKI libAddon.TypeFlags.NUM = ' + libAddon.TypeFlags.NUM);
console.log('AKI libAddon.TypeFlags.Passing() = ' + libAddon.Foo(libAddon.TypeFlags.STRING));
try {
libAddon.TypeFlags.NUM = 10; // TypeError: Cannot set readonly property
} catch (error) {
console.error('AKI catch: ' + error);
}
线程安全函数
使用AKI的线程安全特性,绑定 ETS 的业务函数后,可由native直接调用。
- 线程安全:使用
AKI线程安全绑定的 ETS 函数是线程安全的,可在非 ETS 线程直接调用。最终会由框架调度 ETS 线程执行业务; - 阻塞式调用:C++ 触发调用 ETS 函数的调用是阻塞式的,对于在 ETS 线程执行业务这点没有疑义。但当C++触发 ETS 业务调用的线程是非JS线程时,就存在跨线程任务调度。此时由框架进行了阻塞式调用,即 C++ 会等待 ETS 函数执行结束后返回;
JSBind.bindFunction(name: string, func: function)
在 ETS 使用 JSBind.bindFunction 绑定 ETS 全局函数后,可从 C++ 直接调用。
参数:
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| name | string | Y | 指定绑定的ETS函数名,用于Native索引(索引标识需保证全局唯一)。 |
| func | function | Y | 被绑定的ETS函数 |
返回值:
| 类型 | 说明 |
|---|---|
| number | 当前被绑定的函数下标索引 |
// name: 指定函数名,func: ETS 全局函数
libAddon.JSBind.bindFunction(name: string, func: Function);
C++ 使用aki::JSBind::GetJSFunction获取指定 ETS 函数句柄后,使用Invoke触发调用
auto jsFunc = aki::JSBind::GetJSFunction("xxx"); // 获取指定函数句柄
auto result = jsFunc->Invoke<T>(...); // 调用ETS函数,Invoke<T>指定返回值类型
- ETS
import libAddon from 'libhello.so' // 插件名
function sayHelloFromJS (value) {
console.log('what do you say: ' + value);
return "hello from JS"
}
libAddon.JSBind.bindFunction("sayHelloFromJS", sayHelloFromJS);
- C++
#include <string>
#include <aki/jsbind.h>
void DoSomething() {
// 索引 ETS 函数句柄
auto jsFunc = aki::JSBind::GetJSFunction("sayHelloFromJS");
// Invoke 指定 ETS 方法的返回值类型
auto result = jsFunc->Invoke<std::string>("hello from C++"); // 可在非ETS线程执行
// result == "hello from JS"
}
查看示例:bind_from_js
JSBind.unbindFunction(name: string)
解绑之前绑定的 ETS 全局函数。
参数:
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| name | string | Y | 指定需要解绑的ETS函数名。 |
返回值:
| 类型 | 说明 |
|---|---|
| int | 0表示成功,-1表示失败。 |
// 解绑指定函数
aki::JSBind::unbindFunction("sayHelloFromJS");
napi_env获取
static napi_env aki::JSBind::GetScopedEnv();
线程安全函数,用于获取当前线程的 napi_env 对象。当在非 ETS 线程调用时,返回 nullptr。
参数:
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| key | string | Y | 需要读取的属性名。 |
示例:
// 在 ETS 线程执行
napi_value obj;
napi_env env = aki::JSBind::GetScopedEnv();
napi_create_object(env, &obj);
TaskRunner
TaskRunner提供 ETS 线程的任务调度器,开发人员可以很方便地往 ETS 线程PostTask
JSBind.initTaskRunner(name: string)
ETS侧的静态函数,用于初始化对应 ETS 线程的任务调度器。
参数:
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| runnerName | string | Y | 任务调度器别名。 |
示例:
import libAddon from "libaki.so"
libAddon.JSBind.initTaskRunner("name");
static void PostTask(const std::string& runnerName, Closure task);
静态函数,往指定任务调度器,投递任务。
参数:
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| runnerName | string | Y | 指定任务调度器,需先使用JSBind.initTaskRunner初始化任务调度器。 |
| task | Closure | Y | 任务表达式: std::function<void ()>。 |
示例:
void foo ()
{
aki::TaskRunner::PostTask("main", [] () {
// 在 ETS 线程执行
// do something
});
}
特别声明
PostTask是将任务task抛回到 ETS 线程中运行。在 ETS 线程运行期间构造的 ETS 对象是不会被系统GC的,需要使用者自己管理这些 ETS 对象的生命周期。如果使用者不对使用对象的生命周期进行管理,容易造成内存泄露问题。
一般使用napi_handle_scaope来对使用对象的生命周期进行管理:
void foo ()
{
aki::TaskRunner::PostTask("main", [] () {
// 在 JS 线程执行
napi_handle_scope scope;
napi_env env = Binding::GetScopedEnv();
napi_open_handle_scope(env, &scope);
// do something
napi_close_handle_scope(env, scope);
});
}
AsyncWorker
AsyncWorker提供异步工作队列的能力,支持在工作线程中执行耗时操作,并通过Promise返回结果。
AsyncWorker()
AsyncWorker(napi_async_execute_callback execute, napi_async_complete_callback complete, void *data)
创建AsyncWorker对象,可以指定执行回调、完成回调和用户数据。 (下同SetData、SetExecuteCallback、SetCompleteCallback的入参)。
int SetData(void *data)
设置用户数据,该数据为执行回调和完成回调的共享数据。
参数:
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| data | void* | Y | 用户数据指针。 |
返回值:
| 类型 | 说明 |
|---|---|
| int | 0表示成功,-1表示失败。 |
int SetExecuteCallback(napi_async_execute_callback execute)
设置异步执行回调函数,该函数在工作线程中执行。
参数:
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| execute | napi_async_execute_callback | Y | 执行回调函数。 |
返回值:
| 类型 | 说明 |
|---|---|
| int | 0表示成功,-1表示失败。 |
int SetCompleteCallback(napi_async_complete_callback complete)
设置异步完成回调函数,该函数在 ETS 线程中执行。
参数:
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| complete | napi_async_complete_callback | Y | 完成回调函数。 |
返回值:
| 类型 | 说明 |
|---|---|
| int | 0表示成功,-1表示失败。 |
napi_value CreateAsyncWorker(const char *resource_name = "default")
创建Promise对象和异步工作。
参数:
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| resource_name | const char* | N | 资源名称,不传参数则默认为"default"。 |
返回值:
| 类型 | 说明 |
|---|---|
| napi_value | Promise对象的napi_value句柄。 |
bool Queue()
将异步工作加入系统队列执行。
返回值:
| 类型 | 说明 |
|---|---|
| bool | true表示成功,false表示失败。 |
示例:
#include "aki/jsbind.h"
#include "aki/asyncworker/asyncworker.h"
void ExecuteCallback(napi_env env, void* data) {
// 在工作线程中执行耗时操作
std::this_thread::sleep_for(std::chrono::seconds(3));
}
void CompleteCallback(napi_env env, napi_status status, void* data) {
auto asyncData = static_cast<aki::AsyncWorker::AsyncData* >(data);
napi_deferred deferred = asyncData->deferred_;
napi_value result;
napi_create_string_utf8(env, "success", NAPI_AUTO_LENGTH, &result);
napi_resolve_deferred(env, deferred, result);
}
napi_value CreateAsyncWorker() {
aki::AsyncWorker worker;
worker.SetExecuteCallback(ExecuteCallback);
worker.SetCompleteCallback(CompleteCallback);
napi_value promise = worker.CreateAsyncWorker();
worker.Queue();
return promise;
}
aki-value
ETS 是弱类型语言,可用泛型any表示任意类型。C/C++使用aki::Value映射 ETS 的any类型
功能概览表
| 方法 | 签名 | 说明 |
|---|---|---|
| 静态工厂方法 | ||
| FromGlobal | static Value FromGlobal(const char* key) |
获取 ETS 侧 globalThis 下的属性 |
| NewObject | static Value NewObject() |
创建 ETS 对象 |
| NewArray | static Value NewArray() |
创建 ETS 数组对象 |
| 类型判断方法 | ||
| IsUndefined | bool IsUndefined() const |
判断是否为 undefined |
| IsNull | bool IsNull() const |
判断是否为 null |
| IsBool | bool IsBool() const |
判断是否为 boolean |
| IsNumber | bool IsNumber() const |
判断是否为 number |
| IsString | bool IsString() const |
判断是否为 string |
| IsArray | bool IsArray() const |
判断是否为数组 |
| IsFunction | bool IsFunction() const |
判断是否为 function |
| IsObject | bool IsObject() const |
判断是否为对象(排除数组、空值) |
| 类型转换方法 | ||
| As<T> | template<typename T> T As() const |
将 ETS 对象转换为 C/C++ 指定类型 |
| 属性/元素访问 | ||
| operator[] | Value operator[](const std::string& key) const |
访问对象属性 |
| operator[] | Value operator[](const size_t index) const |
访问数组元素 |
| Set | template<typename V> void Set(const char* key, const V& value) |
设置属性值 |
| 函数调用 | ||
| operator() | template<typename... Args> Value operator()(Args&&... args) const |
函数调用运算符 |
| CallMethod | template<typename... Args> Value CallMethod(const char* name, Args&&... args) |
调用成员函数 |
| 句柄获取 | ||
| GetHandle | napi_value GetHandle() const |
获取 napi_value 句柄 |
static Value FromGlobal(const char* key = nullptr)
用于获取 ETS 侧globalThis下的属性。
参数:
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| key | string | Y | 需要读取的属性名。 |
返回值:
| 类型 | 说明 |
|---|---|
| aki::Value | 对应属性的 ETS 对象句柄。 |
示例:
// 获取globalThis.JSON
aki::Value json = aki::Value::FromGlobal("JSON");
json["stringify"](obj);
static Value NewObject();
创建aki::Value泛型对象。
返回值:
| 类型 | 说明 |
|---|---|
| aki::Value | 返回泛型对象。 |
示例:
aki::Value val = aki::Value::NewObject();
val.Set("name", "aki"); // {'name': 'aki'};
static Value NewArray();
创建 ETS 数组对象。
返回值:
| 类型 | 说明 |
|---|---|
| aki::Value | 返回数组对象。 |
示例:
aki::Value arr = aki::Value::NewArray();
arr.Set(0, std::string("first"));
arr.Set(1, std::string("second"));
bool IsUndefined() const
判断 ETS 对象类型是否为undefined。
返回值:
| 类型 | 说明 |
|---|---|
| bool | true or false。 |
bool IsNull() const
判断 ETS 对象类型是否为null。
返回值:
| 类型 | 说明 |
|---|---|
| bool | true or false。 |
bool IsBool() const
判断 ETS 对象类型是否为boolean。
返回值:
| 类型 | 说明 |
|---|---|
| bool | true or false。 |
bool IsNumber() const
判断 ETS 对象类型是否为number。
返回值:
| 类型 | 说明 |
|---|---|
| bool | true or false。 |
bool IsString() const
判断 ETS 对象类型是否为string。
返回值:
| 类型 | 说明 |
|---|---|
| bool | true or false。 |
bool IsArray() const
判断 ETS 对象类型是否为数组[]。
返回值:
| 类型 | 说明 |
|---|---|
| bool | true or false。 |
bool IsFunction() const
判断 ETS 对象类型是否为function。
返回值:
| 类型 | 说明 |
|---|---|
| bool | true or false。 |
bool IsObject() const
判断 ETS 值是否为对象类型(排除数组、空值)。
返回值:
| 类型 | 说明 |
|---|---|
| bool | true or false。 |
template<typename T>
T As() const;
模板函数,用于将 ETS 对象转化为 C/C++ 指定数据类型
参数:
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| T | any | Y | 需要被转化的 C/C++ 数据类型。 |
返回值:
| 类型 | 说明 |
|---|---|
| T | 对应类型的值。 |
示例:
value.As<bool>(); // 将 ETS 对象 value 转化为 bool
value.As<int>(); // 将 ETS 对象 value 转化为 int
value.As<std::string>(); // 将 ETS 对象 value 转化为 string
Value operator[](const std::string& key) const;
Value operator[](const size_t index) const;
aki::Value对象的下标运算符
参数:
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| key | string | Y | 属性名下标。 |
| index | size_t | Y | 数组下标。 |
返回值:
| 类型 | 说明 |
|---|---|
| aki::Value | 返回泛型对象。 |
示例:
// value 映射为 ETS 数组对象 let value = ['aki', 'jsbind'];
// 访问下标为0的值:'aki';
aki::Value str = value[0]; // str = "aki"
// 调用 JSON.stringify(...);
aki::Value::FromGlobal("JSON")["stringify"](...);
template<typename V>
void Set(const char* key, const V& value);
用于给aki::Value泛型对象属性设值。
参数:
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| key | string | Y | 属性名。 |
| value | any | Y | 属性值。 |
示例:
// value 为 JS 对象;
value.Set("name", "aki");
template<typename... Args>
Value operator()(Args&&... args) const;
aki::Value对象的函数调用运算符
参数:
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| args | any | N | 函数所接收入参。 |
返回值:
| 类型 | 说明 |
|---|---|
| aki::Value | 返回泛型对象。 |
示例:
// 调用 JSON.parse({'aki': 'jsinbd'});
aki::Value::FromGlobal("JSON")["parse"]({"aki": "jsinbd"});
template<typename... Args>
Value CallMethod(const char* name, Args&&... args)
调用 ETS 对象的成员函数。
参数:
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| name | string | Y | 函数名。 |
| args | any | N | 成员函数接收的参数。 |
返回值:
| 类型 | 说明 |
|---|---|
| aki::Value | 返回泛型对象。 |
示例:
// value 映射为 ETS 数组对象 let value = ['aki'];
// 调用 value.push('jsbind');
value.CallMethod("push", "jsbind");
napi_value GetHandle() const
用于获取 ETS 对象的 napi_value 句柄。
返回值:
| 类型 | 说明 |
|---|---|
| napi_value | ETS 对象的 napi_value 句柄。 |
C/C++ 调用 @ohos.bundle.bundleManager (bundleManager模块)特性
示例:
-
期望在 C++ 调用如下@ohos.bundle.bundleManager (bundleManager模块) 特性:
如下
ArkTS代码为@ohos.bundle.bundleManager 示例import bundleManager from '@ohos.bundle.bundleManager'; import hilog from '@ohos.hilog'; let bundleFlags = bundleManager.BundleFlag.GET_BUNDLE_INFO_DEFAULT; try { bundleManager.getBundleInfoForSelf(bundleFlags).then((data) => { hilog.info(0x0000, 'testTag', 'getBundleInfoForSelf successfully. Data: %{public}s', JSON.stringify(data)); }).catch(err => { hilog.error(0x0000, 'testTag', 'getBundleInfoForSelf failed. Cause: %{public}s', err.message); }); } catch (err) { hilog.error(0x0000, 'testTag', 'getBundleInfoForSelf failed: %{public}s', err.message); }使用如下
C++代码实现上述功能/* 要求在ArkTS侧执行如下代码: * import bundleManager from '@ohos.bundle.bundleManager'; * globalThis.bundleManager = bundleManager; */ aki::Value bundleManager = aki::Value::FromGlobal("bundleManager"); /* 如下 C++ 代码等同于 ETS 代码: * let bundleFlags = bundleManager.BundleFlag.GET_BUNDLE_INFO_DEFAULT; * bundleManager.getBundleInfoForSelf(bundleFlags).then((data) => { * console.log('getBundleInfoForSelf successfully. Data:', JSON.stringify(data)); * }) */ std::function<void(aki::Value)> thenFunc = [](aki::Value data) { AKI_LOG(INFO) << aki::Value::FromGlobal("JSON")["stringify"](data).As<std::string>(); }; int bundleFlags = bundleManager["BundleFlag"]["GET_BUNDLE_INFO_DEFAULT"].As<int>(); bundleManager["getBundleInfoForSelf"](bundleFlags).CallMethod("then", thenFunc);
aki-promise
aki::Promise 提供了在 C++ 侧创建和管理 Promise 对象的能力,支持异步操作的返回值处理。
Promise()
Promise(napi_value promise)
创建 Promise 对象,可从现有的 napi_value 构造。
template<typename T>
void Resolve(T&& t) const
解决 Promise,返回成功结果。
参数:
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| t | T | Y | 要返回的值,支持任意 AKI 支持的类型。 |
template<typename T>
void Reject(T&& t) const
拒绝 Promise,返回错误信息。
参数:
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| t | T | Y | 错误信息,支持任意 AKI 支持的类型。 |
napi_value GetHandle()
获取 Promise 的 napi_value 句柄。
返回值:
| 类型 | 说明 |
|---|---|
| napi_value | Promise 的 napi_value 句柄。 |
示例:
#include <aki/jsbind.h>
#include <aki/promise.h>
aki::Promise CreatePromise() {
aki::Promise promise;
promise.Resolve("success");
return promise;
}
aki-ArrayBuffer
- 当在非 ETS 线程使用 aki::ArrayBuffer,需要关注数据字节流生命周期,并考虑是否需要结合
Commit()函数使用。
ArrayBuffer(uint8_t* ptr, size_t len, Typed typed = BUFF)
参数:
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| ptr | uint8_t* | Y | 构造 ArrayBuffer 的数据字节流内存地址。 |
| len | size_t | Y | 构造 ArrayBuffer 的数据字节流内存长度。 |
| typed | aki::ArrayBuffer::Typed | N | 构造的 ArrayBuffer | TypedArray 类型,默认为 ArrayBuffer。 |
示例:
uint8_t temp[4] = {10, 20, 30, 40};
aki::ArrayBuffer arrayBuffer(temp, 4);
uint8_t* GetData()
获取 ArrayBuffer 的数据字节流内存地址。
返回值:
| 类型 | 说明 |
|---|---|
| uint8_t* | ArrayBuffer 的数据字节流内存地址。 |
size_t GetLength()
获取 ArrayBuffer 的数据字节流内存长度。
返回值:
| 类型 | 说明 |
|---|---|
| size_t | ArrayBuffer 的数据字节流内存长度。 |
void Commit()
当在非 ETS 线程使用 ArrayBuffer 时,如果数据字节流的内存生命周期在 ArrayBuffer 使用前结束,则需要暂存。
返回值:
| 类型 | 说明 |
|---|---|
| size_t | ArrayBuffer 的数据字节流内存长度。 |
示例:
// 非 ETS 线程
aki::ArrayBuffer AsyncTaskReturnArrayBufferWithCommit() {
uint8_t temp[4] = {10, 20, 30, 40};
aki::ArrayBuffer arrayBuffer(temp, 4);
arrayBuffer.Commit();
return arrayBuffer;
}
aki::Binding
Binding 类是 AKI 框架的核心注册管理类,负责管理所有需要绑定到 ETS 的函数、类、枚举等对象的注册和查找。这是一个纯静态类。
static void SetScopedEnv(napi_env env)
设置当前线程的 NAPI 环境句柄。
参数:
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| env | napi_env | Y | NAPI 环境句柄。 |
static napi_env GetScopedEnv()
获取当前线程的 NAPI 环境句柄。
返回值:
| 类型 | 说明 |
|---|---|
| napi_env | 当前线程的 NAPI 环境句柄,非 ETS 线程返回 nullptr。 |
static std::forward_list<Function>& GetFunctionList()
static std::forward_list<Function>& GetFunctionList(const char* module)
获取全局函数列表。
参数:
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| module | const char* | N | 模块名,不传则获取全局函数列表。 |
返回值:
| 类型 | 说明 |
|---|---|
| std::forward_list& | 函数列表引用。 |
static void RegisterFunction(const char *name, int32_t invokerId, Binder* binder)
static void RegisterFunction(const char* module, const char *name, int32_t invokerId, Binder* binder)
注册全局函数。
参数:
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| module | const char* | N | 模块名,不传则注册在全局函数列表 |
| name | const char* | Y | 函数名。 |
| invokerId | int32_t | Y | 调用器ID。 |
| binder | Binder* | Y | 绑定器指针。 |
static std::forward_list<ClassBase*>& GetClassList()
获取已注册的类列表。
返回值:
| 类型 | 说明 |
|---|---|
| std::forward_list<ClassBase*>& | 类列表引用。 |
static void RegisterClass(ClassBase* xlass)
注册 C++ 类。
参数:
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| xlass | ClassBase* | Y | 类基类指针。 |
static std::forward_list<EnumerationBase*>& GetEnumerationList()
获取已注册的枚举列表。
返回值:
| 类型 | 说明 |
|---|---|
| std::forward_list<EnumerationBase*>& | 枚举列表引用。 |
static void RegisterEnumeration(EnumerationBase* enumeration)
注册枚举类型。
参数:
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| enumeration | EnumerationBase* | Y | 枚举基类指针。 |
static int RegisterJSFunction(const std::string& name, std::unique_ptr<JSFunction> func)
注册 ETS 函数回调。
参数:
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| name | std::string | Y | 函数名,用于 Native 索引。 |
| func | std::unique_ptr | Y | ETS 函数指针。 |
返回值:
| 类型 | 说明 |
|---|---|
| int | 当前被绑定的函数下标索引。 |
static int UnRegisterJSFunction(const std::string& name)
注销 ETS 函数回调。
参数:
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| name | std::string | Y | 需要注销的函数名。 |
返回值:
| 类型 | 说明 |
|---|---|
| int | 0表示成功,-1表示失败。 |
Binding::AssociationClassExtend
static void AssociationClassExtend(const char *name, const char *parentName)
关联类的继承关系。
参数:
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| name | const char* | Y | 子类名。 |
| parentName | const char* | Y | 父类名。 |
Binding::GetAssociationClassExtend
static std::forward_list<const char *> GetAssociationClassExtend(const char *name)
获取类的所有父类。
参数:
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| name | const char* | Y | 类名。 |
返回值:
| 类型 | 说明 |
|---|---|
| std::forward_list<const char *> | 父类名列表。 |
static std::map<std::string, std::unique_ptr<JSFunction>>& GetJSFunctionMap()
获取 ETS 函数映射表。
返回值:
| 类型 | 说明 |
|---|---|
| std::map<std::string, std::unique_ptr>& | 函数名到函数指针的映射表引用。 |
示例:
#include <aki/binding.h>
// 获取当前 NAPI 环境
napi_env env = aki::Binding::GetScopedEnv();
// 注册 ETS 函数回调
aki::Binding::RegisterJSFunction("callbackName", std::make_unique<JSFunction>(func));
aki::Version
Version 类提供 AKI 库的版本信息查询功能。
static const char* GetVersion()
返回 AKI 版本字符串。
返回值:
| 类型 | 说明 |
|---|---|
| const char* | 版本字符串(如 "1.2.26")。 |
示例:
#include <aki/version.h>
const char* version = aki::Version::GetVersion();
// 输出: "1.2.26"
aki::ScopedLogMessage
ScopedLogMessage 是 RAII 风格的日志消息类,在构造时记录日志上下文信息,在析构时输出日志。通常通过宏来使用。
ScopedLogMessage(LogLevel level, const char* file, int line, const char* condition)
参数:
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| level | LogLevel | Y | 日志级别。 |
| file | const char* | Y | 源文件名。 |
| line | int | Y | 源文件行号。 |
| condition | const char* | Y | 条件表达式字符串。 |
std::ostream& stream()
获取输出流,用于写入日志内容。
返回值:
| 类型 | 说明 |
|---|---|
| std::ostream& | 输出流引用。 |
日志级别定义:
| 级别常量 | 值 | 说明 |
|---|---|---|
| LOG_DEBUG | 0 | 调试信息 |
| LOG_INFO | 1 | 一般信息 |
| LOG_WARNING | 2 | 警告信息 |
| LOG_ERROR | 3 | 错误信息 |
| LOG_FATAL | 4 | 致命错误 |
主要宏定义:
| 宏 | 功能描述 |
|---|---|
AKI_LOG(level) |
输出指定级别的日志 |
AKI_DLOG(level) |
仅在 DEBUG 模式输出日志 |
AKI_CHECK(condition) |
断言检查,失败时输出 FATAL 日志并终止 |
AKI_DCHECK(condition) |
仅在 DEBUG 模式的断言检查 |
示例:
#include <aki/logging/logging.h>
AKI_LOG(INFO) << "Function called successfully";
AKI_LOG(ERROR) << "Failed to process data";
AKI_CHECK(ptr != nullptr) << "Pointer should not be null";
aki::NapiOverloader
NapiOverloader 类用于实现 C++ 函数/构造函数的重载支持,根据传入参数的数量选择正确的方法调用。
static napi_value Wrapper(napi_env env, napi_callback_info info)
重载函数包装器,根据参数数量选择正确的重载方法。
参数:
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| env | napi_env | Y | NAPI 环境句柄。 |
| info | napi_callback_info | Y | 回调信息。 |
返回值:
| 类型 | 说明 |
|---|---|
| napi_value | 调用结果。 |
static napi_value CreateValue(napi_env env, napi_callback_info info)
创建值的重载处理。
参数:
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| env | napi_env | Y | NAPI 环境句柄。 |
| info | napi_callback_info | Y | 回调信息。 |
返回值:
| 类型 | 说明 |
|---|---|
| napi_value | 创建的值。 |
static int32_t AddGroup()
添加一个新的重载组。
返回值:
| 类型 | 说明 |
|---|---|
| int32_t | 重载组ID。 |
static void AddMethod(int32_t groupId, int32_t arity, FuncPtr method)
向指定组添加方法。
参数:
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| groupId | int32_t | Y | 重载组ID。 |
| arity | int32_t | Y | 参数数量。 |
| method | FuncPtr | Y | 方法指针。 |
static OverloadGroup& GetGroup(int32_t groupId)
获取指定ID的重载组。
参数:
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| groupId | int32_t | Y | 重载组ID。 |
返回值:
| 类型 | 说明 |
|---|---|
| OverloadGroup& | 重载组引用。 |
NapiOverloader::SetExternalWrapper
static void SetExternalWrapper(int32_t groupId, napi_callback externalWrapper)
设置外部类型包装器。
参数:
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| groupId | int32_t | Y | 重载组ID。 |
| externalWrapper | napi_callback | Y | 外部类型包装器回调。 |
NapiOverloader::GetOverloaderGroups
static std::vector<OverloadGroup>& GetOverloaderGroups()
获取所有重载组。
返回值:
| 类型 | 说明 |
|---|---|
| std::vector& | 重载组列表引用。 |
使用场景: 内部用于支持 JSBIND_CONSTRUCTOR<> 的多参数重载。
aki::Persistent
Persistent 类是对 napi_ref 的封装,用于持有 ETS 值的持久引用。当需要在多个 NAPI 调用之间保持 ETS 对象的引用时使用。
Persistent()
explicit Persistent(napi_value value)
Persistent(const Persistent& other)
Persistent(Persistent&& other) noexcept
参数:
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| value | napi_value | Y | 构造持久引用的 napi_value(仅用于第二种构造函数)。 |
| other | Persistent | Y | 用于拷贝或移动构造的源对象。 |
bool IsValid() const
检查引用是否有效。
返回值:
| 类型 | 说明 |
|---|---|
| bool | true表示引用有效,false表示引用无效。 |
napi_value GetValue() const
从持久引用获取 napi_value。
返回值:
| 类型 | 说明 |
|---|---|
| napi_value | 持有的 napi_value 值。 |
示例:
#include <aki/persistent/persistent.h>
Persistent persistent(jsValue);
if (persistent.IsValid()) {
napi_value value = persistent.GetValue();
}
aki::NapiValueBase
NapiValueBase 是 NAPI 值类型的基础实现类,提供 ETS 值的类型检查和类型转换功能。
NapiValueBase() = default
NapiValueBase(napi_env env, napi_value value)
virtual ~NapiValueBase() = default
参数:
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| env | napi_env | Y | NAPI 环境句柄。 |
| value | napi_value | Y | napi_value 值。 |
类型检查方法:
| 方法签名 | 功能描述 |
|---|---|
static bool CheckUndefinedType(napi_env env, napi_value value) |
检查是否为 undefined |
static bool CheckNullType(napi_env env, napi_value value) |
检查是否为 null |
static bool CheckBoolType(napi_env env, napi_value value) |
检查是否为布尔类型 |
static bool CheckNumberType(napi_env env, napi_value value) |
检查是否为数字类型 |
static bool CheckStringType(napi_env env, napi_value value) |
检查是否为字符串类型 |
static bool CheckObjectType(napi_env env, napi_value value) |
检查是否为对象类型 |
static bool CheckArrayType(napi_env env, napi_value value) |
检查是否为数组类型 |
static bool CheckFunctionType(napi_env env, napi_value value) |
检查是否为函数类型 |
参数:
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| env | napi_env | Y | NAPI 环境句柄。 |
| value | napi_value | Y | 待检查的 napi_value。 |
返回值:
| 类型 | 说明 |
|---|---|
| bool | true表示类型匹配,false表示不匹配。 |
类型判断方法:
| 方法签名 | 功能描述 |
|---|---|
bool IsUndefined() const override |
判断是否为 undefined |
bool IsNull() const override |
判断是否为 null |
bool IsBool() const override |
判断是否为布尔值 |
bool IsNumber() const override |
判断是否为数字 |
bool IsString() const override |
判断是否为字符串 |
bool IsObject() const override |
判断是否为对象 |
bool IsArray() const override |
判断是否为数组 |
bool IsFunction() const override |
判断是否为函数 |
返回值:
| 类型 | 说明 |
|---|---|
| bool | true表示类型匹配,false表示不匹配。 |
值获取方法:
| 方法签名 | 功能描述 |
|---|---|
bool GetBool() const override |
获取布尔值 |
uint8_t GetUint8() const override |
获取 uint8_t 值 |
int8_t GetInt8() const override |
获取 int8_t 值 |
uint16_t GetUint16() const override |
获取 uint16_t 值 |
int16_t GetInt16() const override |
获取 int16_t 值 |
int32_t GetInt() const override |
获取 int32_t 值 |
uint32_t GetUInt() const override |
获取 uint32_t 值 |
uint64_t GetUInt64() const override |
获取 uint64_t 值 |
int64_t GetInt64() const override |
获取 int64_t 值 |
float GetFloat() const override |
获取 float 值 |
double GetDouble() const override |
获取 double 值 |
std::string GetString() const override |
获取字符串值 |
napi_value GetNapiValue() const |
获取原始 napi_value |
void* GetDataReference() override |
获取对象引用 |
ArrayBuffer GetArrayBuffer() const override |
获取 ArrayBuffer |
Promise GetPromise() override |
获取 Promise |
返回值:
| 类型 | 说明 |
|---|---|
| 对应类型 | 转换后的 C++ 类型值。 |
混合开发
AKI 支持与 Node-API 混合开发。接口 aki::JSBind::BindSymbols 用于绑定使用 AKI 的 Native 符号表给指定的 napi_value 对象。
如下示例:
examples/ohos/4_hybrid_napi/entry/src/main/hello.cpp
EXTERN_C_START
static napi_value Init(napi_env env, napi_value exports)
{
napi_property_descriptor desc[] = {
...
};
napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
exports = aki::JSBind::BindSymbols(env, exports); // aki::JSBind::BindSymbols 函数传入 ETS 对象绑定符号
return exports;
}
EXTERN_C_END
关于混淆
- 代码混淆,请查看代码混淆简介
- 如果希望aki在代码混淆过程中不会被混淆,需要在混淆规则配置文件obfuscation-rules.txt中添加相应的排除规则:
-keep
./oh_modules/@ohos/aki
具体用例参考混淆配置示例
Benchmark
- IDE:DevEco Studio NEXT Developer Beta6 5.0.3.706
- SDK:Command Line Tools 5.0.3.706
API接口压测,当前采用了OHOS上单元测试框架的数据驱动能力,详见benchmark
| API | 调用次数 | AKI (ms) | Node-API (ms) |
| bool (*)() | 10000 | 0.0032 | 0.0031 |
| string (*)(string) | 10000 | 0.0058 | 0.0057 |
| void (*)( std::function ) | 10000 | 0.0667 | 0.0176 |
| void (*)( aki::Callback ) | 10000 | 0.0178 | |
| void (*)( aki::SafetyCallback ) | 10000 | 0.0664 |
常见问题
目录结构
aki/
├── include/ # 公开头文件目录
│ └── aki/ # AKI 核心头文件
│ ├── jsbind.h # 主要绑定宏和 API
│ ├── function.h # 函数绑定支持
│ ├── binding.h # 绑定基础设施
│ ├── value.h # aki::Value 实现
│ ├── promise.h # Promise 支持
│ └── asyncworker/ # 异步工作相关
├── src/ # 源代码目录
│ ├── binding.cpp # 核心绑定实现
│ ├── jsbind.cpp # JSBind 实现
│ ├── value.cpp # 值转换实现
│ └── ...
├── example/ohos/ # OpenHarmony 示例
│ ├── 1_helloworld/ # 基础 Hello World 示例
│ ├── 2_applicationInfo/ # 应用信息示例
│ ├── 3_callback/ # 回调示例
│ ├── 4_hybrid_napi/ # 与 Node-API 混合开发
│ ├── 5_bind_from_js/ # JS 线程安全绑定
│ ├── 15_aki_value/ # aki::Value 使用
│ ├── 16_promise/ # Promise 使用
│ ├── 19_class_extend/ # 类继承示例
│ ├── 26_extern_work_scene/ # 代码混淆配置示例
│ └── ...
├── test/ # 单元测试目录
│ ├── callback/ # 回调测试
│ ├── class/ # 类绑定测试
│ ├── array/ # 数组类型测试
│ ├── map/ # Map 类型测试
│ └── ...
├── doc/ # 文档目录
│ ├── quick-start_zh.md # 快速开始(中文)
│ ├── quick-start.md # 快速开始(英文)
│ ├── type-conversion_zh.md # 类型转换完整说明
│ ├── bind_class.md # 类绑定详细说明
│ ├── bind_enum_zh.md # 枚举绑定说明
│ └── ...
├── benchmark/ # 性能基准测试
├── CMakeLists.txt # 主构建文件
├── README_zh.md # 中文 README (本文件)
├── README.md # 英文 README
├── LICENSE # 开源协议文件
├── CHANGELOG.md # 版本变更日志
└── OAT.xml # 开源协议遵循声明
贡献代码
使用过程中发现任何问题都可以提交Issue,当然,也非常欢迎提交PR。
开源协议
本项目遵循Apache-2.0 License