AKI 項目介紹
AKI (Alpha Kernel Interacting)
是一款邊界性編程體驗友好的ArkTs FFI開發(fā)框架,針對OpenHarmony Native開發(fā)提供JS與C/C++跨語言訪問場景解決方案。支持極簡語法糖使用方式,一行代碼完成JS與C/C++的無障礙跨語言互調(diào),所鍵即所得。
優(yōu)勢
- 極簡使用,解耦FFI代碼與業(yè)務(wù)代碼,友好的邊界性編程體驗;
- 提供完整的數(shù)據(jù)類型轉(zhuǎn)換、函數(shù)綁定、對象綁定、線程安全等特性;
- 支持JS & C/C++互調(diào);
- 支持與Node-API嵌套使用;
已測試兼容環(huán)境
- 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添加依賴(假定編譯動態(tài)庫名為: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添加依賴(假定編譯動態(tài)庫名為:libhello.so):
set(AKI_ROOT_PATH ${CMAKE_CURRENT_SOURCE_DIR}/../../../oh_modules/@ohos/aki) # 設(shè)置AKI根路徑 set(CMAKE_MODULE_PATH ${AKI_ROOT_PATH}) find_package(Aki REQUIRED) ... target_link_libraries(hello PUBLIC Aki::libjsbind) # 鏈接二進(jìn)制依賴 & 頭文件
2 用戶自定義業(yè)務(wù)
用戶業(yè)務(wù) C++ 代碼 hello.cpp:
全程無感node-API
#include <string>
std::string SayHello(std::string msg)
{
return msg + " too.";
}
3 使用 AKI
使用JSBind
工具宏聲明需要被綁定的類、函數(shù):
#include <aki/jsbind.h>
// Step 1 注冊 AKI 插件
JSBIND_ADDON(hello) // 注冊 AKI 插件名: 即為編譯*.so名稱,規(guī)則與NAPI一致
// Step 2 注冊 FFI 特性
JSBIND_GLOBAL()
{
JSBIND_FUNCTION(SayHello);
}
4 編譯構(gòu)建使用
OpenHarmony工程代碼調(diào)用:
import aki from 'libhello.so' // 工程編譯出來的*.so
aki.SayHello("hello world");
JSBind 語法糖
插件注冊
JSBIND_ADDON(addonName)
使用JSBIND_ADDON
注冊O(shè)penHarmony Native 插件,可從 JavaScript import
導(dǎo)入插件。
參數(shù):
參數(shù)名 | 類型 | 必填 | 說明 |
---|---|---|---|
addonName | - | Y | 注冊的OpenHarmony native 插件名,可從 JavaScript import lib${addonName}.so 導(dǎo)入插件,插件名必須符合函數(shù)命名規(guī)則。 |
示例:
- C++
#include <string>
#include <aki/jsbind.h>
JSBIND_ADDON(addon0)
- JavaScript
import addon from 'libaddon0.so' // 插件名為:addon0
JSBIND_ADDON_X(addonName constructorAlias)
用法與JSBIND_ADDON
相似,用于支持插件名有特殊符號的場景,如包含'-';
參數(shù):
參數(shù)名 | 類型 | 必填 | 說明 |
---|---|---|---|
addonName | - | Y | 注冊的OpenHarmony native 插件名,可從 JavaScript import lib${addonName}.so 導(dǎo)入插件,插件名可包含特殊符號,如:'-'。 |
constructorAlias | - | Y | 插件預(yù)構(gòu)造函數(shù)名,只需填寫符合函數(shù)命名規(guī)則名稱即可,無其他特殊含義 |
示例:
- C++
#include <string>
#include <aki/jsbind.h>
JSBIND_ADDON(hello-world, HelloWorld)
- JavaScript
import addon from 'libhello-world.so' // 插件名為:hello-world
綁定全局函數(shù)
JSBIND_GLOBAL
用于圈定需要綁定的全局函數(shù) scope。
JSBIND_FUNCTION(func, alias)
在JSBIND_GLOBAL
作用域下使用JSBIND_FUNCTION
綁定 C++ 全局函數(shù)后,可從 JavaScript 直接調(diào)用。
- 調(diào)度線程為 JS 線程;
參數(shù):
參數(shù)名 | 類型 | 必填 | 說明 |
---|---|---|---|
func | 函數(shù)指針 | Y | 被綁定的C++ 函數(shù)指針,當(dāng)alias未被指定時,JavaScript 與C++ 函數(shù)名相同。 |
alias | string | N | 函數(shù)別名 |
示例:
- 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++ 全局函數(shù)后,從 JavaScript 使用同Promise方式相同的異步調(diào)用。
- 調(diào)度線程為工作線程,由 ArkCompiler Runtime 決定;
參數(shù):
參數(shù)名 | 類型 | 必填 | 說明 |
---|---|---|---|
func | 函數(shù)指針 | Y | 被綁定的C++ 函數(shù)指針。 |
alias | string | N | 函數(shù)別名 |
示例:
- 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)
});
綁定類/結(jié)構(gòu)體
AKI
提供 JSBIND_CLASS
對 C++ 類/結(jié)構(gòu)體
進(jìn)行綁定,在JSBIND_CLASS
作用域下可綁定:類構(gòu)造函數(shù)、類成員函數(shù)、類成員屬性的類特性。
JSBIND_CLASS(class)
參數(shù):
參數(shù)名 | 類型 | 必填 | 說明 |
---|---|---|---|
class | class/struct | Y | 被綁定的C++類對象/結(jié)構(gòu)體 ,JavaScript 與C++ 類名相同。 |
JSBIND_CONSTRUCTOR<T>()
在JSBIND_CLASS
作用域下使用綁定 C++ 類/結(jié)構(gòu)體構(gòu)造函數(shù),其中為了支持多態(tài),可通過類型模板指定構(gòu)造函數(shù)參數(shù)類型。
-
JSBIND_CONSTRUCTOR
需要在JSBIND_CLASS
的作用域下;
參數(shù):
參數(shù)名 | 類型 | 必填 | 說明 |
---|---|---|---|
T | any | N | 構(gòu)造函數(shù)參數(shù)類型,可變類型參數(shù)。 |
示例:
- 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);
綁定類成員函數(shù)
JSBIND_METHOD(method)
AKI
使用 JSBIND_METHOD
對C++ 的3種類成員函數(shù)進(jìn)行綁定:類靜態(tài)函數(shù)、類成員函數(shù)、const 類成員函數(shù)。
-
JSBIND_METHOD
需要在JSBIND_CLASS
的作用域下; - 調(diào)度線程為 JS 線程;
參數(shù):
參數(shù)名 | 類型 | 必填 | 說明 |
---|---|---|---|
method | R (C::*)(P...) | Y | 同時支持類靜態(tài)函數(shù)、類成員函數(shù)、const 類成員函數(shù)。 |
示例:
使用 AKI
對C++類成員函數(shù)綁定
#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è)調(diào)用綁定的C++類成員函數(shù)
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) // 靜態(tài)方法
JSBIND_PMETHOD(method)
JSBIND_PMETHOD
用于綁定 C++ 類成員函數(shù),從 JavaScript 使用同Promise方式相同的異步調(diào)用。
- 調(diào)度線程為工作線程,由 ArkCompiler Runtime 決定;
參數(shù):
參數(shù)名 | 類型 | 必填 | 說明 |
---|---|---|---|
method | 類成員函數(shù)指針 | Y | 被綁定的C++ 類成員函數(shù)指針。 |
示例:
- 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++ 的類成員屬性、類成員屬性訪問器進(jìn)行綁定
-
JSBIND_PROPERTY
需要在JSBIND_CLASS
的作用域下;
參數(shù):
參數(shù)名 | 類型 | 必填 | 說明 |
---|---|---|---|
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++ 的類成員屬性進(jìn)行監(jiān)聽
JSBIND_FIELD
需要在JSBIND_CLASS
的作用域下;調(diào)度線程為 JS 線程;
參數(shù):
參數(shù)名 | 類型 | 必填 | 說明 |
---|---|---|---|
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++側(cè)默認(rèn)枚舉類型為POD中的int32_t;
- JavaScript側(cè)對應(yīng)的枚舉類型屬性為
readonly
;
JSBIND_ENUM(enum)
參數(shù):
參數(shù)名 | 類型 | 必填 | 說明 |
---|---|---|---|
enum | enum | Y | 被綁定的C++ 枚舉類型。 |
JSBIND_ENUM_VALUE(value)
參數(shù):
參數(shù)名 | 類型 | 必填 | 說明 |
---|---|---|---|
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);
}
線程安全函數(shù)
使用AKI
的線程安全特性,綁定 JavaScript 的業(yè)務(wù)函數(shù)后,可由native
直接調(diào)用。
-
線程安全:使用
AKI
線程安全綁定的 JavaScript 函數(shù)是線程安全的,可在非JS線程直接調(diào)用。最終會由框架調(diào)度JS線程執(zhí)行業(yè)務(wù); - 阻塞式調(diào)用:C++ 觸發(fā)調(diào)用 JavaScript 函數(shù)的調(diào)用是阻塞式的,對于在JS線程執(zhí)行業(yè)務(wù)這點沒有疑義。但當(dāng)C++觸發(fā) JavaScript 業(yè)務(wù)調(diào)用的線程是非JS線程時,就存在跨線程任務(wù)調(diào)度。此時由框架進(jìn)行了阻塞式調(diào)用,即 C++ 會等待 JavaScript 函數(shù)執(zhí)行結(jié)束后返回;
JSBind.bindFunction(name: string, func: function)
在 JavaScript 使用 JSBind.bindFunction
綁定 JavaScript 全局函數(shù)后,可從 C++ 直接調(diào)用。
參數(shù):
參數(shù)名 | 類型 | 必填 | 說明 |
---|---|---|---|
name | string | Y | 指定綁定的JavaScript 函數(shù)名,用于Native索引。 |
func | function | Y | 被綁定的JavaScript 函數(shù) |
返回值:
類型 | 說明 |
---|---|
number | 當(dāng)前被綁定的函數(shù)下標(biāo)索引 |
// name: 指定函數(shù)名,func: JavaScript 全局函數(shù)
libAddon.JSBind.bindFunction(name: string, func: Function);
C++ 使用aki::JSBind::GetJSFunction獲取指定 JavaScript 函數(shù)句柄后,使用Invoke觸發(fā)調(diào)用
auto jsFunc = aki::JSBind::GetJSFunction("xxx"); // 獲取指定函數(shù)句柄
auto result = jsFunc->Invoke<T>(...); // 調(diào)用JavaScript函數(shù),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 函數(shù)句柄
auto jsFunc = aki::JSBind::GetJSFunction("sayHelloFromJS");
// Invoke 指定 JS 方法的返回值類型
auto result = jsFunc->Invoke<std::string>("hello from C++"); // 可在非JS線程執(zhí)行
// result == "hello from JS"
}
類型轉(zhuǎn)換
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*
是以引用方式傳遞參數(shù),如遇到異步操作,請使用傳值方式:std::string
Boolean
如下示例,開發(fā)者直接聲明函數(shù)入?yún)⒓胺祷刂殿愋停褂?code>AKI綁定后,框架自適應(yīng)對 C/C++ 的 bool
及 JavaScript 的 Boolean
類型進(jìn)行轉(zhuǎn)化。
示例:
-
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
如下示例,開發(fā)者直接聲明函數(shù)入?yún)⒓胺祷刂殿愋停褂?code>AKI綁定后,框架自適應(yīng)對 C/C++ 的 uint8_t
, int8_t
, uint16_t
, int16_t
, short
, int32
, uint32
, int64
, float
, double
, enum
及 JavaScript 的 Number
類型進(jìn)行轉(zhuǎn)化。
-
float:
浮點型轉(zhuǎn)換時存在精度丟失,對于高精度場景,請使用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
如下示例,開發(fā)者直接聲明函數(shù)入?yún)⒓胺祷刂殿愋停褂?code>AKI綁定后,框架自適應(yīng)對 C/C++ 的 const char*
, std::string
及 JavaScript 的 String
類型進(jìn)行轉(zhuǎn)化。
-
const char*
是以引用方式傳遞參數(shù),如遇到異步操作,請使用傳值方式: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
如下示例,開發(fā)者直接聲明函數(shù)入?yún)⒓胺祷刂殿愋停褂?code>AKI綁定后,框架自適應(yīng)對 C/C++ 的 std::vector<T>
, std::array<T, N>
及 JavaScript 的 []
類型進(jìn)行轉(zhuǎn)化。
- 數(shù)組類型僅支持同種類型的數(shù)組聲明;
示例:
-
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
二進(jìn)制數(shù)據(jù)緩沖區(qū)ArrayBuffer
, TypedArray
是 JavaScript AKI 提供了內(nèi)建結(jié)構(gòu)體:aki::ArrayBuffer
用來支持該特性:
GetData()*
獲取 ArrayBuffer 數(shù)組緩沖區(qū)地址,aki::ArrayBuffer 本身不申請數(shù)據(jù)內(nèi)存,data 都來源于JavaScript引擎分配的內(nèi)存,也無需做內(nèi)存生命周期管理,禁止對該內(nèi)存進(jìn)行危險的釋放。GetLength()
獲取 ArrayBuffer 數(shù)組緩沖區(qū)長度,以單字節(jié)為計量單位。GetTyped()
獲取 ArrayBuffer 數(shù)組緩沖區(qū)的類型化類型。GetCount()
獲取 ArrayBuffer 數(shù)組緩沖區(qū)的類型化數(shù)據(jù)元素個數(shù)。
示例:
- 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結(jié)構(gòu)的數(shù)據(jù)類型,如:
{
name: 'hanmeimei',
age: '17',
date: '1999-02-02'
}
AKI
支持使用C/C++的std::map<std::string, T>
映射JavaScript的JsonObject
。
與
std::map<std::string, T>
對應(yīng)的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的一種基本數(shù)據(jù)類型,當(dāng)JS傳入Function作為參數(shù)時,Native可在適當(dāng)?shù)臅r機(jī)調(diào)用觸發(fā)回調(diào)。AKI
支持如下3中C++數(shù)據(jù)類型作為參數(shù)處理回調(diào):
- aki::Callback<R (P...)>:指定回調(diào)類型為
R (*)(P...)
的高性能回調(diào)。非線程安全,禁止在非JS線程使用,否則會發(fā)生異常; - aki::SafetyCallback<R (P...)>:指定回調(diào)類型為
R (*)(P...)
的線程安全回調(diào)。因為需要創(chuàng)建線程安全資源,所以性能不如aki::Callback; - std::function<R (P...)>:用法與aki::SafetyCallback一致;
對象引用&指針
C++ 對象作為參數(shù)和返回類型,在 C++ & JavaScript 代碼中可以使用如下形式進(jìn)行傳遞:
- 值傳遞;
- 引用(T&)與指針(T*)傳遞;
API參考
napi_env 獲取
static napi_env aki::JSBind::GetScopedEnv();
線程安全函數(shù),用于獲取當(dāng)前線程的 napi_env 對象。當(dāng)在非 JS 線程調(diào)用時,返回 nullptr。
參數(shù):
參數(shù)名 | 類型 | 必填 | 說明 |
---|---|---|---|
key | string | Y | 需要讀取的屬性名。 |
示例:
// 在 JS 線程執(zhí)行
napi_value obj;
napi_env env = aki::JSBind::GetScopedEnv();
napi_create_object(env, &obj);
TaskRunner 任務(wù)調(diào)度器
TaskRunner
提供JS線程的任務(wù)調(diào)度器,開發(fā)人員可以很方便地往JS線程PostTask
JSBind.initTaskRunner(name: string)
JS
側(cè)的靜態(tài)函數(shù),用于初始化對應(yīng)JS線程的任務(wù)調(diào)度器。
參數(shù):
參數(shù)名 | 類型 | 必填 | 說明 |
---|---|---|---|
runnerName | string | Y | 任務(wù)調(diào)度器別名。 |
示例:
import libAddon from "libaki.so"
libAddon.JSBind.initTaskRunner("name");
PostTask
static void PostTask(const std::string& runnerName, Closure task);
靜態(tài)函數(shù),往指定任務(wù)調(diào)度器,投遞任務(wù)。
參數(shù):
參數(shù)名 | 類型 | 必填 | 說明 |
---|---|---|---|
runnerName | string | Y | 指定任務(wù)調(diào)度器,需先使用JSBind.initTaskRunner 初始化任務(wù)調(diào)度器。 |
task | Closure | Y | 任務(wù)表達(dá)式: std::function<void ()>。 |
示例:
void foo ()
{
aki::TaskRunner::PostTask("main", [] () {
// 在 JS 線程執(zhí)行
// 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 側(cè)globalThis
下的屬性。
參數(shù):
參數(shù)名 | 類型 | 必填 | 說明 |
---|---|---|---|
key | string | Y | 需要讀取的屬性名。 |
返回值:
類型 | 說明 |
---|---|
aki::Value | 對應(yīng)屬性的 JS 對象句柄。 |
示例:
// 獲取globalThis.JSON
aki::Value json = aki::Value::FromGlobal("JSON");
json["stringify"](obj);
aki::Value::As
template<typename T>
T As() const;
模板函數(shù),用于將 JS 對象轉(zhuǎn)化為 C/C++ 指定數(shù)據(jù)類型
參數(shù):
參數(shù)名 | 類型 | 必填 | 說明 |
---|---|---|---|
T | any | Y | 需要被轉(zhuǎn)化的 C/C++ 數(shù)據(jù)類型。 |
返回值:
類型 | 說明 |
---|---|
T | 對應(yīng)類型的值。 |
示例:
value.As<bool>(); // 將 JS 對象 value 轉(zhuǎn)化為 bool
value.As<int>(); // 將 JS 對象 value 轉(zhuǎn)化為 int
value.As<std::string>(); // 將 JS 對象 value 轉(zhuǎn)化為 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)
調(diào)用 JS 對象的成員函數(shù)。
參數(shù):
參數(shù)名 | 類型 | 必填 | 說明 |
---|---|---|---|
name | string | Y | 函數(shù)名。 |
args | any | N | 成員函數(shù)接收的參數(shù)。 |
返回值:
類型 | 說明 |
---|---|
aki::Value | 返回泛型對象。 |
示例:
// value 映射為 JS 數(shù)組對象 let value = ['aki'];
// 調(diào)用 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
對象的下標(biāo)運(yùn)算符
參數(shù):
參數(shù)名 | 類型 | 必填 | 說明 |
---|---|---|---|
key | string | Y | 屬性名下標(biāo)。 |
index | size_t | Y | 數(shù)組下標(biāo)。 |
返回值:
類型 | 說明 |
---|---|
aki::Value | 返回泛型對象。 |
示例:
// value 映射為 JS 數(shù)組對象 let value = ['aki', 'jsbind'];
// 訪問下標(biāo)為0的值:'aki';
aki::Value str = value[0]; // str = "aki"
// 調(diào)用 JSON.stringify(...);
aki::Value::FromGlobal("JSON")["stringify"](...);
aki::Value::operator()
template<typename... Args>
Value operator()(Args&&... args) const;
aki::Value
對象的函數(shù)調(diào)用運(yùn)算符
參數(shù):
參數(shù)名 | 類型 | 必填 | 說明 |
---|---|---|---|
args | any | N | 函數(shù)所接收入?yún)ⅰ?/td> |
返回值:
類型 | 說明 |
---|---|
aki::Value | 返回泛型對象。 |
示例:
// 調(diào)用 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
泛型對象屬性設(shè)值。
參數(shù):
參數(shù)名 | 類型 | 必填 | 說明 |
---|---|---|---|
key | string | Y | 屬性名。 |
value | any | Y | 屬性值。 |
示例:
// value 為 JS 對象;
value.Set("name", "aki");
aki::Value::NewObject
static Value NewObject();
創(chuàng)建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 對象類型是否為數(shù)組[]
。
返回值:
類型 | 說明 |
---|---|
bool | true or false。 |
aki::Value::IsFunction
bool IsFunction() const
判斷 JS 對象類型是否為function
。
返回值:
類型 | 說明 |
---|---|
bool | true or false。 |
C/C++ 調(diào)用 @ohos.bundle.bundleManager (bundleManager模塊)特性
示例:
-
期望在 C++ 調(diào)用如下@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++
代碼實現(xiàn)上述功能/* 要求在ArkTS側(cè)執(zhí)行如下代碼: * 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
- 當(dāng)在非 JS 線程使用 aki::ArrayBuffer,需要關(guān)注數(shù)據(jù)字節(jié)流生命周期,并考慮是否需要結(jié)合
Commit()
函數(shù)使用。
ArrayBuffer(uint8_t* ptr, size_t len, Typed typed = BUFF)
參數(shù):
參數(shù)名 | 類型 | 必填 | 說明 |
---|---|---|---|
ptr | uint8_t* | Y | 構(gòu)造 ArrayBuffer 的數(shù)據(jù)字節(jié)流內(nèi)存地址。 |
len | size_t | Y | 構(gòu)造 ArrayBuffer 的數(shù)據(jù)字節(jié)流內(nèi)存長度。 |
typed | aki::ArrayBuffer::Typed | N | 構(gòu)造的 ArrayBuffer | TypedArray 類型,默認(rèn)為 ArrayBuffer。 |
示例:
uint8_t temp[4] = {10, 20, 30, 40};
aki::ArrayBuffer arrayBuffer(temp, 4);
GetData
uint8_t* GetData()
獲取 ArrayBuffer 的數(shù)據(jù)字節(jié)流內(nèi)存地址。
返回值:
類型 | 說明 |
---|---|
uint8_t* | ArrayBuffer 的數(shù)據(jù)字節(jié)流內(nèi)存地址。 |
GetLength
size_t GetLength()
獲取 ArrayBuffer 的數(shù)據(jù)字節(jié)流內(nèi)存長度。
返回值:
類型 | 說明 |
---|---|
size_t | ArrayBuffer 的數(shù)據(jù)字節(jié)流內(nèi)存長度。 |
Commit
void Commit()
當(dāng)在非 JS 線程使用 ArrayBuffer 時,如果數(shù)據(jù)字節(jié)流的內(nèi)存生命周期在 ArrayBuffer 使用前結(jié)束,則需要暫存。
返回值:
類型 | 說明 |
---|---|
size_t | ArrayBuffer 的數(shù)據(jù)字節(jié)流內(nèi)存長度。 |
示例:
// 非 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 混合開發(fā)
AKI
支持與 Node-API 混合開發(fā)。接口 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 函數(shù)傳入 js 對象綁定符號
return exports;
}
EXTERN_C_END
Benchmark
- IDE: DevEco Studio 3.1.1.130
- SDK:3.2.10.6
API接口壓測,當(dāng)前采用了OHOS上單元測試框架的數(shù)據(jù)驅(qū)動能力,詳見benchmark
寫在最后
如果你覺得這篇內(nèi)容對你還蠻有幫助,我想邀請你幫我三個小忙:
- 點贊,轉(zhuǎn)發(fā),有你們的 『點贊和評論』,才是我創(chuàng)造的動力。
- 關(guān)注小編,同時可以期待后續(xù)文章ing??,不定期分享原創(chuàng)知識。
- 想要獲取更多完整鴻蒙最新學(xué)習(xí)知識點,請移步前往小編:
https://gitee.com/MNxiaona/733GH/blob/master/jianshu