AKI 项目介绍
AKI (Alpha Kernel Interacting)
是一款边界性编程体验友好的ArkTs FFI开发框架,针对OpenHarmony Native开发提供JS与C/C++跨语言访问场景解决方案。支持极简语法糖使用方式,一行代码完成JS与C/C++的无障碍跨语言互调,所键即所得。
优势
- 极简使用,解耦FFI代码与业务代码,友好的边界性编程体验;
- 提供完整的数据类型转换、函数绑定、对象绑定、线程安全等特性;
- 支持JS & C/C++互调;
- 支持与Node-API嵌套使用;
已测试兼容环境
- OpenHarmony(API 10) SDK (4.0.9.6): 通过
- DevEco Studio (4.0.0.400): 通过
- OpenHarmony(API 9) SDK (3.2.12.2): 通过
- DevEco Studio (3.1.0.500): 通过
1 依赖配置(2选1)
-
源码依赖(推荐)
指定cpp路径下(如:项目根路径/entry/src/main/cpp)
cd entry/src/main/cpp git clone https://gitee.com/openharmony-sig/aki.git
CMakeLists.txt添加依赖(假定编译动态库名为:libhello.so):
add_subdirectory(aki) target_link_libraries(hello PUBLIC aki_jsbind)
-
ohpm har包依赖
指定路径下(如:项目根路径/entry),输入如下命令安装ohpm har包依赖
cd entry ohpm install @ohos/aki
CMakeLists.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) # 链接二进制依赖 & 头文件
2 用户自定义业务
用户业务 C++ 代码 hello.cpp:
全程无感node-API
#include <string>
std::string SayHello(std::string msg)
{
return msg + " too.";
}
3 使用 AKI
使用JSBind
工具宏声明需要被绑定的类、函数:
#include <aki/jsbind.h>
// Step 1 注册 AKI 插件
JSBIND_ADDON(hello) // 注册 AKI 插件名: 即为编译*.so名称,规则与NAPI一致
// Step 2 注册 FFI 特性
JSBIND_GLOBAL()
{
JSBIND_FUNCTION(SayHello);
}
4 编译构建使用
OpenHarmony工程代码调用:
import aki from 'libhello.so' // 工程编译出来的*.so
aki.SayHello("hello world");
JSBind 语法糖
插件注册
JSBIND_ADDON(addonName)
使用JSBIND_ADDON
注册OpenHarmony Native 插件,可从 JavaScript import
导入插件。
参数:
参数名 | 类型 | 必填 | 说明 |
---|---|---|---|
addonName | - | Y | 注册的OpenHarmony native 插件名,可从 JavaScript import lib${addonName}.so 导入插件,插件名必须符合函数命名规则。 |
示例:
- C++
#include <string>
#include <aki/jsbind.h>
JSBIND_ADDON(addon0)
- JavaScript
import addon from 'libaddon0.so' // 插件名为:addon0
JSBIND_ADDON_X(addonName constructorAlias)
用法与JSBIND_ADDON
相似,用于支持插件名有特殊符号的场景,如包含'-';
参数:
参数名 | 类型 | 必填 | 说明 |
---|---|---|---|
addonName | - | Y | 注册的OpenHarmony native 插件名,可从 JavaScript import lib${addonName}.so 导入插件,插件名可包含特殊符号,如:'-'。 |
constructorAlias | - | Y | 插件预构造函数名,只需填写符合函数命名规则名称即可,无其他特殊含义 |
示例:
- C++
#include <string>
#include <aki/jsbind.h>
JSBIND_ADDON(hello-world, HelloWorld)
- JavaScript
import addon from 'libhello-world.so' // 插件名为:hello-world
绑定全局函数
JSBIND_GLOBAL
用于圈定需要绑定的全局函数 scope。
JSBIND_FUNCTION(func, alias)
在JSBIND_GLOBAL
作用域下使用JSBIND_FUNCTION
绑定 C++ 全局函数后,可从 JavaScript 直接调用。
- 调度线程为 JS 线程;
参数:
参数名 | 类型 | 必填 | 说明 |
---|---|---|---|
func | 函数指针 | Y | 被绑定的C++ 函数指针,当alias未被指定时,JavaScript 与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);
- JavaScript
import aki from 'libhello.so' // 插件名
let message = aki.SayHello("hello world");
JSBIND_PFUNCTION(func, alias)
使用JSBIND_PFUNCTION
绑定 C++ 全局函数后,从 JavaScript 使用同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);
- JavaScript
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++类对象/结构体 ,JavaScript 与C++ 类名相同。 |
JSBIND_CONSTRUCTOR<T>()
在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);
- JavaScript
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);
例:JavaScript 侧调用绑定的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++ 类成员函数,从 JavaScript 使用同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);
- JavaScript
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 | 类成员属性名。 |
示例:
#include <string>
#include <aki/jsbind.h>
class TestObject {
public:
explicit TestObject(double) {
// ...
}
~TestObject() = default;
private:
double value_;
} // TestObject
JSBIND_CLASS(TestObject)
{
JSBIND_CONSTRUCTOR<double>();
JSBIND_PROPERTY(value);
}
- 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)
AKI
使用JSBIND_FIELD
对 C++ 的类成员属性进行监听
JSBIND_FIELD
需要在JSBIND_CLASS
的作用域下;调度线程为 JS 线程;
参数:
参数名 | 类型 | 必填 | 说明 |
---|---|---|---|
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);
}
- JavaScript
import aki from 'libhello.so' // 插件名
var obj = new aki.TestObject(3.14);
obj.value = 1;
let value = obj.value;
绑定枚举类型
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++
#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);
- 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);
}
线程安全函数
使用AKI
的线程安全特性,绑定 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 | 当前被绑定的函数下标索引 |
// name: 指定函数名,func: JavaScript 全局函数
libAddon.JSBind.bindFunction(name: string, func: Function);
C++ 使用aki::JSBind::GetJSFunction获取指定 JavaScript 函数句柄后,使用Invoke触发调用
auto jsFunc = aki::JSBind::GetJSFunction("xxx"); // 获取指定函数句柄
auto result = jsFunc->Invoke<T>(...); // 调用JavaScript函数,Invoke<T>指定返回值类型
- 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++
#include <string>
#include <aki/jsbind.h>
void DoSomething() {
// 索引 JS 函数句柄
auto jsFunc = aki::JSBind::GetJSFunction("sayHelloFromJS");
// Invoke 指定 JS 方法的返回值类型
auto result = jsFunc->Invoke<std::string>("hello from C++"); // 可在非JS线程执行
// result == "hello from JS"
}
类型转换
JavaScript | C++ |
---|---|
Boolean |
bool |
Number |
uint8_t , int8_t , uint16_t , int16_t , short , int32 , uint32 , int64 , 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> |
ArrayBuffer, TypedArray |
aki::ArrayBuffer |
Promise |
JSBIND_PFUNCTION , JSBIND_PMETHOD
|
any |
aki::Value , napi_value
|
NOTE: 带有阴影部分的表示已支持
const char*
是以引用方式传递参数,如遇到异步操作,请使用传值方式:std::string
Boolean
如下示例,开发者直接声明函数入参及返回值类型,使用AKI
绑定后,框架自适应对 C/C++ 的 bool
及 JavaScript 的 Boolean
类型进行转化。
示例:
-
C++
#include <aki/jsbind.h> bool Foo(bool flag) { ... return true; } JSBIND_GLOBAL() { JSBIND_FUNCTION(Foo, "foo"); } JSBIND_ADDON(hello)
-
JavaScript
import libAddon from 'libhello.so' let flag = libAddon.foo(true);
Number
如下示例,开发者直接声明函数入参及返回值类型,使用AKI
绑定后,框架自适应对 C/C++ 的 uint8_t
, int8_t
, uint16_t
, int16_t
, short
, int32
, uint32
, int64
, float
, double
, enum
及 JavaScript 的 Number
类型进行转化。
-
float:
浮点型转换时存在精度丢失,对于高精度场景,请使用double
;
示例:
-
C++
#include <aki/jsbind.h> int Foo(int num) { ... return 666; } JSBIND_GLOBAL() { JSBIND_FUNCTION(Foo, "foo"); } JSBIND_ADDON(hello)
-
JavaScript
import libAddon from 'libhello.so' let num = libAddon.foo(888);
String
如下示例,开发者直接声明函数入参及返回值类型,使用AKI
绑定后,框架自适应对 C/C++ 的 const char*
, std::string
及 JavaScript 的 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)
-
JavaScript
import libAddon from 'libhello.so' let str = libAddon.foo("AKI", "666");
Array
如下示例,开发者直接声明函数入参及返回值类型,使用AKI
绑定后,框架自适应对 C/C++ 的 std::vector<T>
, std::array<T, N>
及 JavaScript 的 []
类型进行转化。
- 数组类型仅支持同种类型的数组声明;
示例:
-
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)
-
JavaScript
import libAddon from 'libhello.so' let array = libAddon.foo([1, 2, 3]);
ArrarBuffer
二进制数据缓冲区ArrayBuffer
, TypedArray
是 JavaScript AKI 提供了内建结构体:aki::ArrayBuffer
用来支持该特性:
GetData()*
获取 ArrayBuffer 数组缓冲区地址,aki::ArrayBuffer 本身不申请数据内存,data 都来源于JavaScript引擎分配的内存,也无需做内存生命周期管理,禁止对该内存进行危险的释放。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;
}
- 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();
JsonObject
JavaScript支持使用JsonObject
表示key-value结构的数据类型,如:
{
name: 'hanmeimei',
age: '17',
date: '1999-02-02'
}
AKI
支持使用C/C++的std::map<std::string, T>
映射JavaScript的JsonObject
。
与
std::map<std::string, T>
对应的JsonObject
必须约束value类型一致Example
C++
void Foo(std::map<std::string, int> obj)
{
for (auto& iter : obj) {
......; // key: iter.first; value: iter.second
}
}
JSBIND_GLOBAL() {
JSBIND_FUNCTION(Foo);
}
- JavaScript
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++ & JavaScript 代码中可以使用如下形式进行传递:
- 值传递;
- 引用(T&)与指针(T*)传递;
API参考
napi_env 获取
static napi_env aki::JSBind::GetScopedEnv();
线程安全函数,用于获取当前线程的 napi_env 对象。当在非 JS 线程调用时,返回 nullptr。
参数:
参数名 | 类型 | 必填 | 说明 |
---|---|---|---|
key | string | Y | 需要读取的属性名。 |
示例:
// 在 JS 线程执行
napi_value obj;
napi_env env = aki::JSBind::GetScopedEnv();
napi_create_object(env, &obj);
TaskRunner 任务调度器
TaskRunner
提供JS线程的任务调度器,开发人员可以很方便地往JS线程PostTask
JSBind.initTaskRunner(name: string)
JS
侧的静态函数,用于初始化对应JS线程的任务调度器。
参数:
参数名 | 类型 | 必填 | 说明 |
---|---|---|---|
runnerName | string | Y | 任务调度器别名。 |
示例:
import libAddon from "libaki.so"
libAddon.JSBind.initTaskRunner("name");
PostTask
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", [] () {
// 在 JS 线程执行
// do something
});
}
aki::Value v1.2.0
JavaScript 是弱类型语言,可用泛型any
表示任意类型。C/C++使用aki::Value
映射 JavaScript 的any
类型
aki::Value::FromGlobal
static Value FromGlobal(const char* key = nullptr)
用于获取 JS 侧globalThis
下的属性。
参数:
参数名 | 类型 | 必填 | 说明 |
---|---|---|---|
key | string | Y | 需要读取的属性名。 |
返回值:
类型 | 说明 |
---|---|
aki::Value | 对应属性的 JS 对象句柄。 |
示例:
// 获取globalThis.JSON
aki::Value json = aki::Value::FromGlobal("JSON");
json["stringify"](obj);
aki::Value::As
template<typename T>
T As() const;
模板函数,用于将 JS 对象转化为 C/C++ 指定数据类型
参数:
参数名 | 类型 | 必填 | 说明 |
---|---|---|---|
T | any | Y | 需要被转化的 C/C++ 数据类型。 |
返回值:
类型 | 说明 |
---|---|
T | 对应类型的值。 |
示例:
value.As<bool>(); // 将 JS 对象 value 转化为 bool
value.As<int>(); // 将 JS 对象 value 转化为 int
value.As<std::string>(); // 将 JS 对象 value 转化为 string
aki::Value::GetHandle
napi_value GetHandle() const
用于获取 JS 对象的 napi_value 句柄。
返回值:
类型 | 说明 |
---|---|
napi_value | JS 对象的 napi_value 句柄。 |
aki::Value::CallMethod
template<typename... Args>
Value CallMethod(const char* name, Args&&... args)
调用 JS 对象的成员函数。
参数:
参数名 | 类型 | 必填 | 说明 |
---|---|---|---|
name | string | Y | 函数名。 |
args | any | N | 成员函数接收的参数。 |
返回值:
类型 | 说明 |
---|---|
aki::Value | 返回泛型对象。 |
示例:
// value 映射为 JS 数组对象 let value = ['aki'];
// 调用 value.push('jsbind');
value.CallMethod("push", "jsbind");
aki::Value::operator[]
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 映射为 JS 数组对象 let value = ['aki', 'jsbind'];
// 访问下标为0的值:'aki';
aki::Value str = value[0]; // str = "aki"
// 调用 JSON.stringify(...);
aki::Value::FromGlobal("JSON")["stringify"](...);
aki::Value::operator()
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"});
aki::Value::Set
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");
aki::Value::NewObject
static Value NewObject();
创建aki::Value
泛型对象。
返回值:
类型 | 说明 |
---|---|
aki::Value | 返回泛型对象。 |
示例:
aki::Value val = aki::Value::NewObject();
val.Set("name", "aki"); // {'name': 'aki'};
aki::Value::IsUndefined
bool IsUndefined() const
判断 JS 对象类型是否为undefined
。
返回值:
类型 | 说明 |
---|---|
bool | true or false。 |
aki::Value::IsNull
bool IsNull() const
判断 JS 对象类型是否为null
。
返回值:
类型 | 说明 |
---|---|
bool | true or false。 |
aki::Value::IsBool
bool IsBool() const
判断 JS 对象类型是否为boolean
。
返回值:
类型 | 说明 |
---|---|
bool | true or false。 |
aki::Value::IsNumber
bool IsNumber() const
判断 JS 对象类型是否为number
。
返回值:
类型 | 说明 |
---|---|
bool | true or false。 |
aki::Value::IsString
bool IsString() const
判断 JS 对象类型是否为string
。
返回值:
类型 | 说明 |
---|---|
bool | true or false。 |
aki::Value::IsArray
bool IsArray() const
判断 JS 对象类型是否为数组[]
。
返回值:
类型 | 说明 |
---|---|
bool | true or false。 |
aki::Value::IsFunction
bool IsFunction() const
判断 JS 对象类型是否为function
。
返回值:
类型 | 说明 |
---|---|
bool | true or false。 |
C/C++ 调用 @ohos.bundle.bundleManager (bundleManager模块)特性
示例:
-
期望在 C++ 调用如下@ohos.bundle.bundleManager (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++ 代码等同于 JS 代码: * 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::ArrayBuffer
constructor
- 当在非 JS 线程使用 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);
GetData
uint8_t* GetData()
获取 ArrayBuffer 的数据字节流内存地址。
返回值:
类型 | 说明 |
---|---|
uint8_t* | ArrayBuffer 的数据字节流内存地址。 |
GetLength
size_t GetLength()
获取 ArrayBuffer 的数据字节流内存长度。
返回值:
类型 | 说明 |
---|---|
size_t | ArrayBuffer 的数据字节流内存长度。 |
Commit
void Commit()
当在非 JS 线程使用 ArrayBuffer 时,如果数据字节流的内存生命周期在 ArrayBuffer 使用前结束,则需要暂存。
返回值:
类型 | 说明 |
---|---|
size_t | ArrayBuffer 的数据字节流内存长度。 |
示例:
// 非 JS 线程
aki::ArrayBuffer AsyncTaskReturnArrayBufferWithCommit() {
uint8_t temp[4] = {10, 20, 30, 40};
aki::ArrayBuffer arrayBuffer(temp, 4);
arrayBuffer.Commit();
return arrayBuffer;
}
AKI hybrid Node-API 混合开发
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 函数传入 js 对象绑定符号
return exports;
}
EXTERN_C_END
Benchmark
- IDE: DevEco Studio 3.1.1.130
- SDK:3.2.10.6
API接口压测,当前采用了OHOS上单元测试框架的数据驱动能力,详见benchmark
写在最后
如果你觉得这篇内容对你还蛮有帮助,我想邀请你帮我三个小忙:
- 点赞,转发,有你们的 『点赞和评论』,才是我创造的动力。
- 关注小编,同时可以期待后续文章ing🚀,不定期分享原创知识。
- 想要获取更多完整鸿蒙最新学习知识点,请移步前往小编:
https://gitee.com/MNxiaona/733GH/blob/master/jianshu