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

2024-08-25 20:42:03 浏览数 (5)

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)

代码语言:shell复制
    cd entry/src/main/cpp
    git clone https://gitee.com/openharmony-sig/aki.git

CMakeLists.txt添加依赖(假定编译动态库名为:libhello.so):

代码语言:c复制
    add_subdirectory(aki)
    target_link_libraries(hello PUBLIC aki_jsbind)
  • ohpm har包依赖

指定路径下(如:项目根路径/entry),输入如下命令安装ohpm har包依赖

代码语言:shell复制
    cd entry
    ohpm install @ohos/aki

CMakeLists.txt添加依赖(假定编译动态库名为:libhello.so):

代码语言:c复制
    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

代码语言:c复制
#include <string>

std::string SayHello(std::string msg)
{
  return msg   " too.";
}

3 使用 AKI

使用JSBind工具宏声明需要被绑定的类、函数:

代码语言:c复制
#include <aki/jsbind.h>

// Step 1 注册 AKI 插件
JSBIND_ADDON(hello) // 注册 AKI 插件名: 即为编译*.so名称,规则与NAPI一致

// Step 2 注册 FFI 特性
JSBIND_GLOBAL()
{
  JSBIND_FUNCTION(SayHello);
}

4 编译构建使用

OpenHarmony工程代码调用:

代码语言:js复制
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
代码语言:c复制
#include <string>
#include <aki/jsbind.h>

JSBIND_ADDON(addon0)
  • JavaScript
代码语言:js复制
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
代码语言:c复制
#include <string>
#include <aki/jsbind.h>

JSBIND_ADDON(hello-world, HelloWorld)
  • JavaScript
代码语言:js复制
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
代码语言: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
代码语言:js复制
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
代码语言:c复制
int AsyncTaskReturnInt() {
    // Do something;
    return -1;
}

JSBIND_GLOBAL() {
    JSBIND_PFUNCTION(AsyncTaskReturnInt);
}

JSBIND_ADDON(async_tasks);
  • JavaScript
代码语言:js复制
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
代码语言: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
代码语言:js复制
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 类成员函数绑定

代码语言: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 类成员函数

代码语言:js复制
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
代码语言: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
代码语言:js复制
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) <sup>new in 1.0.7</sup>

AKI 使用JSBIND_PROPERTYJSBIND_FIELD 对 C 的类成员属性、类成员属性访问器进行绑定

  • JSBIND_PROPERTY需要在JSBIND_CLASS的作用域下;

参数:

参数名

类型

必填

说明

property

T

Y

类成员属性名。

示例:

代码语言:c复制
#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
代码语言:js复制
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
代码语言: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
代码语言:js复制
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
代码语言: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
代码语言:js复制
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

当前被绑定的函数下标索引

代码语言:js复制
// 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<T>(...); // 调用JavaScript函数,Invoke<T>指定返回值类型
  • JavaScript
代码语言:js复制
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 <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
代码语言:c复制
  #include <aki/jsbind.h>
  bool Foo(bool flag) {
    ...
    return true;
  }
  JSBIND_GLOBAL() {
      JSBIND_FUNCTION(Foo, "foo");
  }
  JSBIND_ADDON(hello)
  • JavaScript
代码语言:js复制
  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
代码语言:c复制
  #include <aki/jsbind.h>
  int Foo(int num) {
    ...
    return 666;
  }
  JSBIND_GLOBAL() {
      JSBIND_FUNCTION(Foo, "foo");
  }
  JSBIND_ADDON(hello)
  • JavaScript
代码语言:js复制
  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
代码语言: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
代码语言:js复制
  import libAddon from 'libhello.so'
  let str = libAddon.foo("AKI", "666");

Array

如下示例,开发者直接声明函数入参及返回值类型,使用AKI绑定后,框架自适应对 C/C 的 std::vector<T>, std::array<T, N> 及 JavaScript 的 [] 类型进行转化。

  • 数组类型仅支持同种类型的数组声明;

示例:

  • C
代码语言: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
代码语言:js复制
  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
代码语言: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
代码语言:js复制
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结构的数据类型,如:

代码语言:js复制
{
  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
代码语言: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
代码语言:js复制
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 获取

代码语言:c复制
static napi_env aki::JSBind::GetScopedEnv();

线程安全函数,用于获取当前线程的 napi_env 对象。当在非 JS 线程调用时,返回 nullptr。

参数:

参数名

类型

必填

说明

key

string

Y

需要读取的属性名。

示例:

代码语言:c复制
// 在 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

任务调度器别名。

示例:

代码语言:js复制
import libAddon from "libaki.so"

libAddon.JSBind.initTaskRunner("name");
PostTask
代码语言:c复制
static void PostTask(const std::string& runnerName, Closure task);

静态函数,往指定任务调度器,投递任务。

参数:

参数名

类型

必填

说明

runnerName

string

Y

指定任务调度器,需先使用JSBind.initTaskRunner初始化任务调度器。

task

Closure

Y

任务表达式: std::function<void ()>。

示例:

代码语言:c复制
void foo ()
{
    aki::TaskRunner::PostTask("main", [] () {
      // 在 JS 线程执行
      // do something
    });
}

aki::Value <sup> v1.2.0 </sup>

JavaScript 是弱类型语言,可用泛型any表示任意类型。C/C 使用aki::Value映射 JavaScript 的any类型

aki::Value::FromGlobal
代码语言:c复制
static Value FromGlobal(const char* key = nullptr)

用于获取 JS 侧globalThis下的属性。

参数:

参数名

类型

必填

说明

key

string

Y

需要读取的属性名。

返回值:

类型

说明

aki::Value

对应属性的 JS 对象句柄。

示例:

代码语言:c复制
  // 获取globalThis.JSON
  aki::Value json = aki::Value::FromGlobal("JSON");
  json["stringify"](obj);
aki::Value::As
代码语言:c复制
template<typename T>
T As() const;

模板函数,用于将 JS 对象转化为 C/C 指定数据类型

参数:

参数名

类型

必填

说明

T

any

Y

需要被转化的 C/C 数据类型。

返回值:

类型

说明

T

对应类型的值。

示例:

代码语言:c复制
  value.As<bool>(); // 将 JS 对象 value 转化为 bool
  value.As<int>(); // 将 JS 对象 value 转化为 int
  value.As<std::string>(); // 将 JS 对象 value 转化为 string
aki::Value::GetHandle
代码语言:c复制
napi_value GetHandle() const

用于获取 JS 对象的 napi_value 句柄。

返回值:

类型

说明

napi_value

JS 对象的 napi_value 句柄。

aki::Value::CallMethod
代码语言:c复制
template<typename... Args>
Value CallMethod(const char* name, Args&&... args)

调用 JS 对象的成员函数。

参数:

参数名

类型

必填

说明

name

string

Y

函数名。

args

any

N

成员函数接收的参数。

返回值:

类型

说明

aki::Value

返回泛型对象。

示例:

代码语言:c复制
  // value 映射为 JS 数组对象 let value = ['aki'];
  // 调用 value.push('jsbind');
  value.CallMethod("push", "jsbind");
aki::Value::operator[]
代码语言:c复制
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

返回泛型对象。

示例:

代码语言:c复制
  // 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()
代码语言:c复制
template<typename... Args>
Value operator()(Args&&... args) const;

aki::Value对象的函数调用运算符

参数:

参数名

类型

必填

说明

args

any

N

函数所接收入参。

返回值:

类型

说明

aki::Value

返回泛型对象。

示例:

代码语言:c复制
  // 调用 JSON.parse({'aki': 'jsinbd'});
  aki::Value::FromGlobal("JSON")["parse"]({"aki": "jsinbd"});
aki::Value::Set
代码语言:c复制
template<typename V>
void Set(const char* key, const V& value);

用于给aki::Value泛型对象属性设值。

参数:

参数名

类型

必填

说明

key

string

Y

属性名。

value

any

Y

属性值。

示例:

代码语言:c复制
  // value 为 JS 对象;
    value.Set("name", "aki");
aki::Value::NewObject
代码语言:c复制
static Value NewObject();

创建aki::Value泛型对象。

返回值:

类型

说明

aki::Value

返回泛型对象。

示例:

代码语言:c复制
  aki::Value val = aki::Value::NewObject();
  val.Set("name", "aki"); // {'name': 'aki'};
aki::Value::IsUndefined
代码语言:c复制
bool IsUndefined() const

判断 JS 对象类型是否为undefined

返回值:

类型

说明

bool

true or false。

aki::Value::IsNull
代码语言:c复制
bool IsNull() const

判断 JS 对象类型是否为null

返回值:

类型

说明

bool

true or false。

aki::Value::IsBool
代码语言:c复制
bool IsBool() const

判断 JS 对象类型是否为boolean

返回值:

类型

说明

bool

true or false。

aki::Value::IsNumber
代码语言:c复制
bool IsNumber() const

判断 JS 对象类型是否为number

返回值:

类型

说明

bool

true or false。

aki::Value::IsString
代码语言:c复制
bool IsString() const

判断 JS 对象类型是否为string

返回值:

类型

说明

bool

true or false。

aki::Value::IsArray
代码语言:c复制
bool IsArray() const

判断 JS 对象类型是否为数组[]

返回值:

类型

说明

bool

true or false。

aki::Value::IsFunction
代码语言:c复制
bool IsFunction() const

判断 JS 对象类型是否为function

返回值:

类型

说明

bool

true or false。

C/C 调用 @ohos.bundle.bundleManager (bundleManager模块)特性

示例:

  • 期望在 C 调用如下@ohos.bundle.bundleManager (bundleManager模块) 特性:
代码语言:js复制
  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<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()函数使用。
代码语言:c复制
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。

示例:

代码语言:c复制
uint8_t temp[4] = {10, 20, 30, 40};
aki::ArrayBuffer arrayBuffer(temp, 4);
GetData
代码语言:c复制
uint8_t* GetData()

获取 ArrayBuffer 的数据字节流内存地址。

返回值:

类型

说明

uint8_t*

ArrayBuffer 的数据字节流内存地址。

GetLength
代码语言:c复制
size_t GetLength()

获取 ArrayBuffer 的数据字节流内存长度。

返回值:

类型

说明

size_t

ArrayBuffer 的数据字节流内存长度。

Commit
代码语言:c复制
void Commit()

当在非 JS 线程使用 ArrayBuffer 时,如果数据字节流的内存生命周期在 ArrayBuffer 使用前结束,则需要暂存。

返回值:

类型

说明

size_t

ArrayBuffer 的数据字节流内存长度。

示例:

代码语言:c复制
// 非 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

代码语言: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::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

0 人点赞