# aki **Repository Path**: lc168/aki ## Basic Information - **Project Name**: aki - **Description**: No description available - **Primary Language**: Unknown - **License**: Apache-2.0 - **Default Branch**: master - **Homepage**: https://gitee.com/openharmony-sig/aki - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 48 - **Created**: 2023-08-30 - **Last Updated**: 2023-08-30 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README - [AKI项目介绍](#AKI-项目介绍) - [快速接入](#快速接入) - [用户指南](#用户指南) - [用例demos](https://gitee.com/openharmony-sig/aki/blob/master/example/ohos/README.md) - [如何反馈](#如何反馈) - [如何贡献](#如何贡献) # AKI 项目介绍 **`AKI (Alpha Kernel Interacting)` 是一款边界性编程体验友好的ArkTs FFI开发框架,针对OpenHarmony Native开发提供JS与C/C++跨语言访问场景解决方案。支持极简语法糖使用方式,一行代码完成JS与C/C++的无障碍跨语言互调,所见即所得。** ## 优势 1. 极简使用,解耦FFI代码与业务代码,友好的边界性编程体验; 2. 提供完整的数据类型转换、函数绑定、对象绑定、线程安全等特性; 3. 支持JS & C/C++互调; 4. 支持与Node-API嵌套使用; ![interacting.png](doc/interacting.png)
Native C/C++ 业务代码: ArkTS 风格代码:
#include <string>
#include <aki/jsbind.h>
  
// 类/结构体
struct Person {
    std::string SayHello();
    int age;
    std::string name;
    double weight;
};
  
// 全局函数
Person MakePerson() {
    Person person = {99, "aki", 128.8};
    return person;
}
  
// Aki JSBind语法糖
JSBIND_GLOBAL() {
    JSBIND_FUNCTION(MakePerson);
}
JSBIND_CLASS(Person) {
    JSBIND_CONSTRUCTOR<int>();
    JSBIND_METHOD(SayHello);
    JSBIND_PROPERTY(age);
    JSBIND_PROPERTY(name);
    JSBIND_PROPERTY(weight);
}
JSBIND_ADDON(<Name>)
import libaki from "lib<Name>.so"
  
// 调用 C/C++ Person 构造函数
let man = new libaki.Person(10);
  
// 访问类/结构体成员属性
console.log(man.age);
  
// 类/结构体成员函数
man.SayHello();
 
// 调用 C/C++ 全局函数
let woman = libaki.MakePerson();
 
// 极简使用,支持全类型转换
console.log(woman.name);
## 已测试兼容环境 * OpenHarmony(API 9) SDK (3.2.12.2): **通过** * DevEco Studio (3.1.0.500): **通过** # 快速接入 - [1 依赖配置](#1-依赖配置) - [2 用户自定义业务](#2-用户自定义业务) - [3 JSBind语法糖绑定](#3-JSBind语法糖绑定) - [4 编译构建使用](#4-编译构建使用) ## **1 依赖配置** * **源码依赖(推荐)** 指定cpp路径下(如:项目根路径/entry/src/main/cpp) ``` cd entry/src/main/cpp git clone https://gitee.com/openharmony-sig/aki.git ``` CMakeLists.txt添加依赖: ```cmake add_subdirectory(aki) target_link_libraries(entry PUBLIC aki_jsbind) ``` * **ohpm har包依赖** 指定路径下(如:项目根路径/entry),输入如下命令安装ohpm har包依赖 ``` cd entry ohpm install @ohos/aki ``` CMakeLists.txt添加依赖: ```cmake 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(${YOUR_TARGET} PUBLIC Aki::libjsbind) # 链接二进制依赖 & 头文件 ``` ## **2 用户自定义业务** 用户业务 C++ 代码 hello.cpp:
全程无感`node-API` ```C++ #include std::string SayHello(std::string msg) { return msg + " too."; } ``` ## **3 JSBind语法糖绑定** 使用`JSBind`工具宏声明需要被绑定的类、函数: ```C++ #include // Step 1 注册 AKI 插件 JSBIND_ADDON(${YOUR_TARGET}) // 注册 AKI 插件名: 即为编译*.so名称,规则与NAPI一致 // Step 2 注册 FFI 特性 JSBIND_GLOBAL() { JSBIND_FUNCTION(SayHello); } ``` ## **4 编译构建使用** OpenHarmony工程代码调用: ```javascript import aki from 'lib.so' // 工程编译出来的*.so aki.SayHello("hello world"); ``` # 用户指南 - [hello world](#hello_world) - [用户自定义创建工程](#用户自定义创建工程) - [绑定特性](#绑定特性) - [JSBind 语法糖](#jsbind-语法糖) - [类型转换](#类型转换) - [数据类型](#数据类型) - [any](#any) - [JsonObject](#jsonobject) - [ArrarBuffer](#arrarbuffer) - [绑定 Native](#绑定-native) - [插件注册](#插件注册) - [绑定全局函数](#绑定全局函数) - [绑定类构造函数](#绑定类构造函数) - [绑定类成员函数](#绑定类成员函数) - [绑定类成员属性](#绑定类成员属性) new in 1.0.7 - [回调](#回调) - [绑定枚举类型](#绑定枚举类型) new in 1.0.2 - [Promise异步函数](#promise异步函数) - [等价类](#等价类) - [AKI hybrid Node-API 混合开发](#aki-hybrid-node-api-混合开发) - [绑定 JavaScript](#绑定-javascript) - [绑定全局函数](#bind_js_function) - [生成声明文件 .d.ts](#生成声明文件-dts) - [Benchmark](#benchmark) ## hello world 拉取示例代码: ```base git clone https://gitee.com/openharmony-sig/aki.git ``` DevEco打开工程:example/ohos/1_helloworld 进入 enter 目录并 install: ```bash cd entry/src/main/cpp git clone https://gitee.com/openharmony-sig/aki.git ``` 通过DevEco build entry 安装到设备上 && 完成! ### 更多示例请查看:example ## 用户自定义创建工程 1. 创建平台工程 通过DevEco 创建包含C++的工程 ```base File > New > Create Project | Module ``` 2. 配置依赖并安装 * **源码依赖(推荐)** 指定路径下(如:项目根路径/entry/src/main/cpp) ``` cd entry/src/main/cpp git clone https://gitee.com/openharmony-sig/aki.git ``` CMakeLists.txt添加依赖: ```cmake add_subdirectory(aki) target_link_libraries(entry PUBLIC aki_jsbind) ``` 3. 编译工程 && 运行 ## 绑定特性 ### JSBind 语法糖
语法糖 AKI 说明
插件注册 C++ JSBIND_ADDON 注册OpenHarmony Native 插件。
使用指导
全局函数 C++ JSBIND_FUNCTION 绑定 C++ 全局方法,JS 可调用。
使用指导
JavaScript JSbind.bindFunction 绑定 JS 全局方法,C++ 可调用。
使用指导
类构造函数 C++ JSBIND_CONSTRUCTOR<> 绑定 C++ 类构造函数,JS 可调用。构造函数可重载,需指定构造函数参数类型。
使用指导
JavaScript - 暂不支持
类成员函数 C++ JSBIND_METHOD 绑定 C++ 类成员函数,JS 可调用。
成员函数可以为:类静态函数,类成员函数,const类成员函数。
使用指导
JavaScript - 暂不支持
类成员属性 C++ JSBIND_PROPERTY
JSBIND_FIELD
JSBIND_PROPERTY 绑定 C++类成员属性;
JSBIND_FIELD 绑定 C++ 类成员属性访问器(Get/Set)。
使用指导
JavaScript - 暂不支持
### 类型转换 | **JavaScript** | **C++** | | ---------------- | ------------------------ | | Boolean | `bool` | | Number | short, `int32`, `uint32`, `int64`, `double`, enum | | String | `const char*`, `std::string` | | Array | std::vector, std::array | | Function | `std::function`
`aki::Callbackn`
`aki::SafetyCallbackn`
See [回调](#bind_cpp_callback) | | Class Object | `class` | | JsonObject | `std::map` [参考](#JsonObject) | | ArrayBuffer,
TypedArray | `aki::ArrayBuffer` [参考](#二进制数据缓冲区_ArrarBuffer_&_TypedArray) | | Promise | `JSBIND_PFUNCTION`, `JSBIND_PMETHOD` | | any | `aki::Value` | NOTE: 带有阴影部分的表示已支持 `const char*` 是以引用方式传递参数,如遇到异步操作,请使用传值方式:std::string ## 数据类型 ### any v1.2.0 JavaScript 是弱类型语言,可用泛型`any`表示任意类型。C/C++使用`aki::Value`映射 JavaScript 的`any`类型,如下例: - 期望在 C++ 调用如下@ohos.bundle.bundleManager (bundleManager模块)特性: 如下`ArkTS`代码为[@ohos.bundle.bundleManager 示例](https://docs.openharmony.cn/pages/v3.2/zh-cn/application-dev/reference/apis/js-apis-bundleManager.md/) ```JavaScript 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++`代码实现上述功能 ```C++ /* 要求在ArkTS侧执行如下代码: * import bundleManager from '@ohos.bundle.bundleManager'; * globalThis.bundleManager = bundleManager; */ aki::Value bundleManager = aki::Value::FromGlobal("bundleManager"); /* 如下 C++ 代码等同于 JS 代码: * let bundleFlags = bundleManager.BundleFlag.GET_BUNDLE_INFO_DEFAULT; * bundleManager.getBundleInfoForSelf(bundleFlags).then((data) => { * console.log('getBundleInfoForSelf successfully. Data:', JSON.stringify(data)); * }) */ std::function thenFunc = [](aki::Value data) { AKI_LOG(INFO) << aki::Value::FromGlobal("JSON")["stringify"](data).As(); }; int bundleFlags = bundleManager["BundleFlag"]["GET_BUNDLE_INFO_DEFAULT"].As(); bundleManager["getBundleInfoForSelf"](bundleFlags).CallMethod("then", thenFunc); ``` **接口描述:** - aki::Value::FromGlobal 获取 JS 侧 globalThis下的属性; - aki::Value::As<T> 转换类型为T类型 - aki::Value::CallMethod; 调用类成员函数 - [Example](https://gitee.com/openharmony-sig/aki/tree/master/example/ohos/15_aki_value) ### 对象引用&指针 C++ 对象作为参数和返回类型,在 C++ & JavaScript 代码中可以使用如下形式进行传递: - 值传递; - 引用(T&)与指针(T*)传递; - [Example](https://gitee.com/openharmony-sig/aki/tree/master/example/ohos/14_reference_and_pointer) ### JsonObject JavaScript支持使用`JsonObject`表示key-value结构的数据类型,如: ```javascript { name: 'hanmeimei', age: '17', date: '1999-02-02' } ``` `AKI`支持使用C/C++的`std::map`映射JavaScript的`JsonObject`。 - 与`std::map`对应的`JsonObject`必须约束value类型一致 - [Example](https://gitee.com/openharmony-sig/aki/tree/master/example/ohos/10_map_for_object) - C++ ``` C++ void Foo(std::map obj) { for (auto& iter : obj) { ......; // key: iter.first; value: iter.second } } JSBIND_GLOBAL() { JSBIND_FUNCTION(Foo); } ``` - JavaScript ``` JavaScript import libmap_for_object from 'libmap_for_object.so' let a = {age: 100}; libmap_for_object.Foo(a); ``` ### ArrarBuffer 二进制数据缓冲区`ArrayBuffer`, `TypedArray` 是 JavaScript AKI 提供了内建结构体:`aki::ArrayBuffer`用来支持该特性: - `GetData()*` 获取 ArrayBuffer 数组缓冲区地址,aki::ArrayBuffer 本身不申请数据内存,data 都来源于JavaScript引擎分配的内存,也无需做内存生命周期管理,**禁止对该内存进行危险的释放**。 - `GetLength()` 获取 ArrayBuffer 数组缓冲区长度,以单字节为计量单位。 - `GetTyped()` 获取 ArrayBuffer 数组缓冲区的类型化类型。 - `GetCount()` 获取 ArrayBuffer 数组缓冲区的类型化数据元素个数。 #### Example - C++ ``` C++ #include 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; } ``` - JavaScript ``` JavaScript 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(); ``` ## 绑定 Native 使用`AKI`的 C++ 库,绑定`native`的业务功能后,可由 JavaScript 直接调用。 ### 插件注册 #### JSBIND_ADDON(addonName) 使用`JSBIND_ADDON`注册OpenHarmony Native 插件,可从 JavaScript `import` 导入插件。 **参数:** | **参数名** | **类型** | **必填** | **说明** | | ----------- | -------- | ------- | ------------------------ | | addonName | - | Y | 注册的OpenHarmony native 插件名,可从 JavaScript `import lib${addonName}.so` 导入插件 | - C++ ``` C++ #include #include JSBIND_ADDON(addon0) ``` - JavaScript ``` JavaScript import addon from 'libaddon0.so' // 插件名为:addon0 ``` ### 绑定全局函数 #### JSBIND_FUNCTION(func, alias) 在`JSBIND_GLOBAL`作用域下使用`JSBIND_FUNCTION`绑定 C++ 全局函数后,可从 JavaScript 直接调用。 **参数:** | **参数名** | **类型** | **必填** | **说明** | | ----------- | -------- | ------- | ------------------------ | | func | 函数指针 | Y | 被绑定的`C++`函数指针,当alias未被指定时,`JavaScript`与`C++`函数名相同。 | | alias | string | N | 指定`JavaScript`调用的`C++`函数 | - C++ ``` C++ #include #include std::string SayHello(std::string msg) { return msg + " too."; } JSBIND_GLOBAL() { JSBIND_FUNCTION(SayHello); } ``` - JavaScript ``` JavaScript import aki from 'libhello.so' // 插件名 let message = aki.SayHello("hello world"); ``` ### 绑定类/结构体 `AKI` 提供 `JSBIND_CLASS` 对 C++ `类/结构体`进行绑定,在`JSBIND_CLASS`作用域下可绑定:类构造函数、类成员函数、类成员属性的类特性。 #### JSBIND_CLASS(class) **参数:** | **参数名** | **类型** | **必填** | **说明** | | ----------- | -------- | ------- | ------------------------ | | class | class/struct | Y | 被绑定的C++`类对象/结构体`,`JavaScript`与`C++`类名相同。 | ### 绑定类构造函数 在`JSBIND_CLASS`作用域下使用绑定 C++ 类/结构体构造函数,其中为了支持多态,可通过类型模板指定构造函数参数类型。 - `JSBIND_CONSTRUCTOR` 需要在`JSBIND_CLASS`的作用域下; #### JSBIND_CONSTRUCTOR\() **参数:** | **参数名** | **类型** | **必填** | **说明** | | ----------- | -------- | ------- | ------------------------ | | T | any | N | 构造函数参数类型,可变类型参数。 | - C++ ``` C++ #include #include class TestObject { public: TestObject(); explicit TestObject(double) { // ... } ~TestObject() = default; } // TestObject JSBIND_CLASS(TestObject) { JSBIND_CONSTRUCTOR<>(); JSBIND_CONSTRUCTOR(); } ``` - JavaScript ``` JavaScript import aki from 'libhello.so' // 插件名 var obj1 = new aki.TestObject(); var obj2 = new aki.TestObject(3.14); ``` ### 绑定类成员函数 `AKI` 使用 `JSBIND_METHOD` 对C++ 的3种类成员函数进行绑定:类静态函数、类成员函数、const 类成员函数。 - `JSBIND_METHOD` 需要在`JSBIND_CLASS`的作用域下; #### JSBIND_METHOD(method) **参数:** | **参数名** | **类型** | **必填** | **说明** | | ----------- | -------- | ------- | ------------------------ | | method | R (C::*)(P...) | Y | 同时支持类静态函数、类成员函数、const 类成员函数。 | 例:使用 `AKI` 对C++类成员函数绑定 ``` C++ #include #include 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(); JSBIND_METHOD(MultiplyObject); JSBIND_METHOD(Multiply); } ``` 例:JavaScript 侧调用绑定的C++类成员函数 ``` JavaScript 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) // 静态方法 ``` ### 绑定类成员属性 `AKI` 使用`JSBIND_PROPERTY`、`JSBIND_FIELD` 对 C++ 的类成员属性、类成员属性访问器进行绑定 - `JSBIND_PROPERTY`、`JSBIND_FIELD` 需要在`JSBIND_CLASS`的作用域下; #### JSBIND_PROPERTY(property) new in 1.0.7 **参数:** | **参数名** | **类型** | **必填** | **说明** | | ----------- | -------- | ------- | ------------------------ | | property | T | Y | 类成员属性名。 | ``` C++ #include #include class TestObject { public: explicit TestObject(double) { // ... } ~TestObject() = default; private: double value_; } // TestObject JSBIND_CLASS(TestObject) { JSBIND_CONSTRUCTOR(); JSBIND_PROPERTY(value); } ``` - JavaScript ``` JavaScript import aki from 'libhello.so' // 插件名 var obj = new aki.TestObject(3.14); obj.value = 1; let value = obj.value; ``` #### JSBIND_FIELD(field, getter, setter) **参数:** | **参数名** | **类型** | **必填** | **说明** | | ----------- | -------- | ------- | ------------------------ | | field | T | Y | 类成员属性名。 | | getter | T (void) | Y | get属性访问器。 | | setter | void (T) | Y | set属性访问器。 | - C++ ``` C++ #include #include 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(); JSBIND_FIELD("value", GetValue, SetValue); } ``` - JavaScript ``` JavaScript import aki from 'libhello.so' // 插件名 var obj = new aki.TestObject(3.14); obj.value = 1; let value = obj.value; ``` ### 回调 Function是JS的一种基本数据类型,当JS传入Function作为参数时,Native可在适当的时机调用触发回调。`AKI` 支持如下3中C++数据类型作为参数处理回调: - aki::Callback:指定回调类型为`R (*)(P...)`的**高性能**回调。**非线程安全,禁止在非JS线程使用**,否则会发生异常; - aki::SafetyCallback:指定回调类型为`R (*)(P...)`的线程安全回调。因为需要创建线程安全资源,所以性能不如aki::Callback; - std::function:用法与aki::SafetyCallback一致; ### 绑定枚举类型 `JSBind`语法糖`JSBIND_ENUM`、`JSBIND_ENUM_VALUE`支持绑定 C/C++ 枚举类型,映射为 JavaScript 的Number类型。 - C/C++侧默认枚举类型为POD中的int32_t; - JavaScript侧对应的枚举类型属性为`readonly`; #### JSBIND_ENUM(enum) **参数:** | **参数名** | **类型** | **必填** | **说明** | | ----------- | -------- | ------- | ------------------------ | | enum | enum | Y | 被绑定的`C++`枚举类型。 | #### JSBIND_ENUM_VALUE(value) **参数:** | **参数名** | **类型** | **必填** | **说明** | | ----------- | -------- | ------- | ------------------------ | | value | enum::value | Y | 被绑定的`C++`枚举值。 | - C++ ``` C++ #include #include 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); ``` - JavaScript ``` JavaScript 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); } ``` ### Promise异步函数 `JSBind`语法糖`JSBIND_PFUNCTION`、`JSBIND_PMETHOD`支持绑定 C/C++ 函数为异步函数,映射为 JavaScript 的Promise类型。 - C/C++侧使用`JSBIND_PFUNCTION`、`JSBIND_PMETHOD`绑定的函数不在JS线程执行; #### JSBIND_PFUNCTION(func) 使用`JSBIND_FUNCTION`绑定 C++ 全局函数后,从 JavaScript 使用同Promise方式相同的异步调用。 **参数:** | **参数名** | **类型** | **必填** | **说明** | | ----------- | -------- | ------- | ------------------------ | | func | 函数指针 | Y | 被绑定的`C++`函数指针。 | #### JSBIND_PMETHOD(method) `JSBIND_PMETHOD`用于绑定 C++ 类成员函数,从 JavaScript 使用同Promise方式相同的异步调用。 **参数:** | **参数名** | **类型** | **必填** | **说明** | | ----------- | -------- | ------- | ------------------------ | | method | 类成员函数指针 | Y | 被绑定的`C++`类成员函数指针。 | - C++ ``` C++ class TaskRunner { public: TaskRunner() = default; void DoTask() { // Do something; } }; JSBIND_CLASS(TaskRunner) { JSBIND_CONSTRUCTOR<>(); JSBIND_PMETHOD(DoTask); } void AsyncTaskReturnVoid() { // Do something; } JSBIND_GLOBAL() { JSBIND_PFUNCTION(AsyncTaskReturnVoid); } JSBIND_ADDON(async_tasks); ``` - JavaScript ``` JavaScript import libAddon from 'libasync_tasks.so' let taskRunner = new libAddon.TaskRunner(); taskRunner.DoTask().then(res => { console.log('[AKI] DoTask: ' + res) }); libAddon.AsyncTaskReturnVoid().then(res => { console.log('[AKI] AsyncTaskReturnVoid: ' + res) }); ``` ### 等价类 等价类用于绑定 JavaScript && C++ 的类对象,在进行跨语言调用传值时,可保证两端类成员属性保持一致。 **约束** 1. C++ 侧**必须**给类对象显示加上成员函数 `void Equals(aki::Matcher matcher);` (函数暂不用实现); 2. JavaScript 侧**必须**给类对象加上成员函数 `equals(matcher: (...) => void)` ,并将matcher方法依次按照 C++ 构造函数形式传值; - C++ ``` C++ #include class EquivalenceTest { public: EquivalenceTest(int value); static int ShowByValue(EquivalenceTest obj) { return obj.value_; } void Equals(aki::Matcher matcher) { // 暂不实现 } private: int value_; }; JSBIND_CLASS(EquivalenceTest) { JSBIND_CONSTRUCTOR(); JSBIND_METHOD(ShowByValue); } ``` - JavaScript ``` JavaScript import aki from 'libhello.so' // 插件名 class EquivalenceTest { constructor(value: Number) { this.value = value; } private equals(matcher: (v: Number) => void) { try { matcher(this.value); } catch(e) { console.log(e) } } value: Number; } var value = new EquivalenceTest(250); var result = aki.EquivalenceTest.ShowByValue(value); ``` ## AKI hybrid Node-API 混合开发 `AKI` 支持与 Node-API 混合开发。接口 `aki::BindSymbols` 用于绑定使用 `AKI` 的 Native 符号表给指定的 napi_value 对象。 如下示例: examples/ohos/4_hybrid_napi/entry/src/main/hello.cpp ```C++ 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::BindSymbols(env, exports); // aki::BindSymbols 函数传入 js 对象绑定符号 return exports; } EXTERN_C_END ``` ## 绑定 JavaScript 使用`AKI`的 JavaScript 插件,绑定 JavaScript 的业务功能后,可由`native`直接调用。 - **线程安全**:使用`AKI`绑定的 JavaScript 函数是线程安全的,可在非JS线程直接调用。最终会由框架调度JS线程执行业务; - **阻塞式调用**:C++ 触发调用 JavaScript 函数的调用是阻塞式的,对于在JS线程执行业务这点没有疑义。但当C++触发 JavaScript 业务调用的线程是非JS线程时,就存在跨线程任务调度。此时由框架进行了阻塞式调用,即 C++ 会等待 JavaScript 函数执行结束后返回; ### 绑定全局函数 #### JSBind.bindFunction(name: string, func: function) 在 JavaScript 使用 `JSBind.bindFunction` 绑定 JavaScript 全局函数后,可从 C++ 直接调用。 **参数:** | **参数名** | **类型** | **必填** | **说明** | | ----------- | -------- | ------- | ------------------------ | | name | string | Y | 指定绑定的`JavaScript`函数名,用于Native索引。 | | func | function | Y | 被绑定的`JavaScript`函数 | **返回值:** | **类型** | **说明** | | ----------- | -------- | | number | 当前被绑定的函数下标索引 | ``` JavaScript // name: 指定函数名,func: JavaScript 全局函数 libAddon.JSBind.bindFunction(name: string, func: Function); ``` C++ 使用aki::JSBind::GetJSFunction获取指定 JavaScript 函数句柄后,使用Invoke触发调用 ``` C++ auto jsFunc = aki::JSBind::GetJSFunction("xxx"); // 获取指定函数句柄 auto result = jsFunc->Invoke(...); // 调用JavaScript函数,Invoke指定返回值类型 ``` - JavaScript ``` JavaScript 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++ ``` C++ #include #include void DoSomething() { // 索引 JS 函数句柄 auto jsFunc = aki::JSBind::GetJSFunction("sayHelloFromJS"); // Invoke 指定 JS 方法的返回值类型 auto result = jsFunc->Invoke("hello from C++"); // 可在非JS线程执行 // result == "hello from JS" } ``` 查看示例:bind_from_js ## 生成声明文件 .d.ts 暂未支持自动生成TypeScript声明文件。 ## Benchmark * IDE: DevEco Studio 3.1.1.130 * SDK:3.2.10.6 API接口压测,当前采用了OHOS上单元测试框架的数据驱动能力,详见benchmark
API 调用次数 AKI (ms) Node-API (ms)
bool (*)() 10000 0.0032 0.0031
string (*)(string) 10000 0.0058 0.0043
void (*)( std::function ) 10000 0.0667 0.0176
void (*)( aki::Callback ) 10000 0.0178
void (*)( aki::SafetyCallback ) 10000 0.0664
# 如何反馈 * issue # 如何贡献 * 贡献代码