介绍
针对JS与C/C++跨语言访问场景,NAPI使用比较繁琐。而AKI提供了极简语法糖使用方式,一行代码完成JS与C/C++的无障碍跨语言互调,使用方便。本示例将介绍使用AKI编写C++跨线程调用JS函数场景。通过调用C++全局函数,创建子线程来调用JS函数,实现对变量value的加10操作,为开发者使用AKI提供参考。
效果图预览
使用说明
- 点击页面“AKI跨线程调用JS函数”按钮,每次点击,显示数值加10。
实现思路
以下是使用AKI和NPAI的libuv实现跨线程调用JS函数的实现对比:
-
AKI和NAPI初始化。
AKI初始化使用JSBIND_ADDON注册Native插件,使用AKI的JSBIND_GLOBAL注册FFI特性,然后在JSBIND_GLOBAL作用域下使用AKI的JSBIND_FUNCTION绑定C++全局函数AkiThreadsCallJs。
... // 使用JSBIND_ADDON注册Native插件,可从JavaScript import导入插件。注册AKI插件名:即为编译*.so名称,规则与NAPI一致。 JSBIND_ADDON(aki_use_practice) // 使用JSBIND_GLOBAL注册FFI特性。用于圈定需要绑定的全局函数作用域。 JSBIND_GLOBAL() { // 在JSBIND_GLOBAL作用域下使用JSBIND_FUNCTION绑定C++全局函数后,可从JavaScript直接调用。 JSBIND_FUNCTION(AkiThreadsCallJs); } ...
NAPI的libuv初始化需要定义napi_property_descriptor结构体,准备模块加载相关信息,将Init函数与模块名等信息记录下来。
... static napi_value Init(napi_env env, napi_value exports) { // 第一个参数"add"为ArkTS侧对应方法的名称。 napi_property_descriptor desc[] = { {"UvWorkTest", nullptr, UvWorkTest, nullptr, nullptr, nullptr, napi_default, nullptr} }; napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc); return exports; } // 准备模块加载相关信息,将Init函数与本模块名等信息记录下来。 static napi_module demoModule = { .nm_version = 1, .nm_flags = 0, .nm_filename = nullptr, .nm_register_func = Init, .nm_modname = "entry", .nm_priv = ((void *)0), .reserved = {0}, }; extern "C" __attribute__((constructor)) void RegisterModule(void) { napi_module_register(&demoModule); }
-
AKI和NAPI在native侧的业务函数实现。
AKI在native侧业务函数实现是在AkiThreadsCallJs中创建子线程,子线程中使用aki::JSBind:: GetJSFunction获取指定JavaScript函数akiAccumulate的句柄后,使用Invoke触发调用。
// 定义C++函数AkiThreadsCallJs。从native主线程中创建子线程subThread调用JavaScript函数。 void AkiThreadsCallJs(int value) { // 创建子线程subThread std::thread subThread([=]() { // 使用aki::JSBind::GetJSFunction获取指定JavaScript函数句柄后,使用Invoke触发调用。这里获取JS侧定义的函数