北向应用集成三方库——Napi接口封装工具aki

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嵌套使用;

已测试兼容环境

  • 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未被指定时,JavaScriptC++函数名相同。
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++类对象/结构体JavaScriptC++类名相同。

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_PROPERTYJSBIND_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_ENUMJSBIND_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
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,470评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,393评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,577评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,176评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,189评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,155评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,041评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,903评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,319评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,539评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,703评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,417评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,013评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,664评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,818评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,711评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,601评论 2 353

推荐阅读更多精彩内容