JavaScript如何调用C++模块中的函数
作者:Hens_Hello_Mr
场景一:JS侧调用C++侧函数,并传递参数
JS侧调用C++侧函数
import testNapi from 'libentry.so' const TAG = "beixiang"; @Entry @Component struct Index { build() { Row() { Column() { Text('调用testNapi.add') .fontSize(50) .fontWeight(FontWeight.Bold) .onClick(() => { const result = testNapi.add(3,4); console.log(`${TAG} 调用testNapi.add的结果为${result}`); }) } .width('100%') } .height('100%') } }
C++侧方法实现
static napi_value Add(napi_env env, napi_callback_info info) { // 获取 2 个参数,napi_value是对 JS 类型的封装 size_t argc = 2; napi_value argv[2] = {nullptr}; // 调用napi_get_cb_info方法,从 info 中读取传递进来的参数放入argv里 napi_get_cb_info(env, info, &argc, argv , nullptr, nullptr); // 获取参数并校验类型 napi_valuetype valuetype0; napi_typeof(env, argv[0], &valuetype0); napi_valuetype valuetype1; napi_typeof(env, argv[1], &valuetype1); // 调用napi_get_value_double把 napi_value 类型转换成 C++ 的 double 类型 double value0; napi_get_value_double(env, argv[0], &value0); double value1; napi_get_value_double(env, argv[1], &value1); // 调用napi_create_double方法把 C++类型转换成 napi_value 类型 napi_value sum; napi_create_double(env, value0 + value1, &sum); // 返回 napi_value 类型 return sum; }
napi_get_cb_info (napi_env env, napi_callback_info cbinfo, size_t *argc, napi_value *argv, napi_value *this_arg, void **data)
- env:调用 API 的环境
- cbinfo:传递给回调函数的回调信息
- argc:指定提供的 argv 数组的大小并接收参数的实际计数
- argv:将表示参数的 napi_value 复制到的缓冲区
- this_arg:接收调用的 JavaScript this 参数
- data:接收回调的数据指针
例如Add方法的代码,
napi_get_cb_info(env, info, &argc, argv , nullptr, nullptr);
,从 info 中读取传递进来的&argc个参数放入argv。napi_get_value_double(napi_env env, napi_value value, double *result)
把 napi_value 类型转换成 C++ 的 double 类型,供C++侧使用
napi_create_double(napi_env env, double value, napi_value *result)
把 C++ double类型转换成 napi_value 类型,供JS侧使用
napi_create_function(napi_env env, const char *utf8name, size_t length, napi_callback cb, void *data, napi_value *result)
不同于以上定义函数,并在Init()
方法内声明 napi_property_descriptor 结构体导出函数的方式,使用 napi_create_function允许将C++侧函数创建为可供JS侧调用的函数对象,然后使用napi_set_named_property将创建的函数对象导出,以便可以从JS侧访问该函数,如下代码:
// xxx.cpp EXTERN_C_START static napi_value Init(napi_env env, napi_value exports) { napi_value fn; // 根据C++侧函数Add创建函数fn napi_create_function(env, nullptr, 0, Add, nullptr, &fn); // 将创建的函数fn导出,函数名为newAdd napi_set_named_property(env, exports, "newAdd", fn); napi_property_descriptor desc[] = { { "add", nullptr, Add, nullptr, nullptr, nullptr, napi_default, nullptr }, }; napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc); return exports; } EXTERN_C_END
// index.d.ts export const newAdd: (a: number, b: number) => number;
场景二:JS侧不传参给回调函数,C++侧接收JS侧回调函数并执行
JS侧调用C++侧函数
import testNapi from 'libentry.so' const TAG = "beixiang"; @Entry @Component struct Index { build() { Row() { Column() { Text('调用无参回调函数') .fontSize(50) .fontWeight(FontWeight.Bold) .onClick(() => { // 先注册无参回调函数 testNapi.registerCallback(() => { const a = 2; const b = 3; return a + b; }) // 调用无参回调函数 const result = testNapi.handleCallbackWithoutParams(); console.log(`${TAG} 调用无参回调函数的结果为${result}`); }) } .width('100%') } .height('100%') } }
C++侧注册回调函数
// js函数回调 static napi_ref callback = nullptr; /** * 注册回调函数 * @param env * @param info * @return */ static napi_value RegisterCallback(napi_env env, napi_callback_info info) { size_t argc = 1; napi_value argv[1] = {nullptr}; napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr); napi_create_reference(env, argv[0], 1, &callback); return nullptr; }
C++侧执行注册回调函数
/** * 执行回调函数,不带参数 * @param env * @param info * @return */ static napi_value HandleCallbackWithoutParams(napi_env env, napi_callback_info info) { napi_value global; napi_get_global(env, &global); napi_value cb = nullptr; napi_get_reference_value(env, callback, &cb); napi_value result; napi_status status = napi_call_function(env, global, cb, 0 , nullptr, &result); if (status != napi_ok) return nullptr; return result; }
napi_create_reference(napi_env env, napi_value value, uint32_t initial_refcount, napi_ref *result)
此 API 为传入的对象创建一个具有指定引用计数的新引用,例如注册回调函数RegisterCallback中的napi_create_reference(env, argv[0], 1, &callback),将JS侧传入的对象argv[0](对JS来说,函数也是对象)保存在callback中,供C++侧方法调用;
napi_get_reference_value(napi_env env, napi_ref ref, napi_value *result)
将创建的引用ref保存到result中
napi_call_function(napi_env env, napi_value recv, napi_value func, size_t argc, const napi_value *argv, napi_value *result)
- env:调用 API 的环境
- recv:this 对象传递给被调用的函数,一般是当前环境的global对象,通过napi_get_global来获取。
- func:表示要调用的 JavaScript 函数
- argc:argv 数组中元素的计数。
- argv:表示作为参数传递给函数的 JavaScript 值的 napi_values 数组
- result:napi_value 表示返回的 JavaScript 对象
在env环境下,在global对象中调用函数func,该函数参数数组为argv,有argc个参数,函数执行结果保存在result。此API允许从C++侧调用 JavaScript 函数对象,例如本文的napi_call_function(env, global, cb, 0 , nullptr, &result);
场景三:JS侧传参给回调函数,C++侧接收JS侧回调函数并执行
JS侧调用C++侧函数
import testNapi from 'libentry.so' const TAG = "beixiang"; @Entry @Component struct Index { build() { Row() { Column() { Text('调用有参回调函数') .fontSize(50) .fontWeight(FontWeight.Bold) .onClick(() => { // 先注册无参回调函数 testNapi.registerCallback((a: number, b: number) => { return a + b; }) // 调用无参回调函数 const result = testNapi.handleCallbackWithParams(); console.log(`${TAG} 调用有参回调函数的结果为${result}`); }) } .width('100%') } .height('100%') } }
C++侧注册回调函数
/** * 注册回调函数 * @param env * @param info * @return */ static napi_value RegisterCallback(napi_env env, napi_callback_info info) { size_t argc = 1; napi_value args[1] = {nullptr}; napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); napi_create_reference(env, args[0], 1, &callback); return nullptr; }
C++侧执行注册回调函数
/** * 执行回调函数,带参数 * @param env * @param info * @return */ static napi_value HandleCallbackWithParams(napi_env env, napi_callback_info info) { napi_value argv[2] = {nullptr}; napi_valuetype valuetype0; napi_typeof(env, argv[0], &valuetype0); napi_valuetype valuetype1; napi_typeof(env, argv[1], &valuetype1); double value1 = 2; double value2 = 3; // 创建两个double,给callback调用 napi_create_double(env, value1, &argv[0]); napi_create_double(env, value2, &argv[1]); napi_value global; napi_get_global(env, &global); napi_value cb = nullptr; napi_get_reference_value(env, callback, &cb); napi_valuetype type; napi_typeof(env, cb, &type); napi_value result; // 调用回调函数 napi_status status = napi_call_function(env, global, cb, 2, argv, &result); if (status != napi_ok) return nullptr; return result; }
值得注意的是,本文JS侧传递给C++的回调函数是匿名函数,C++侧先将JS回调函数先在C++侧注册,即使用napi_create_reference将JS函数创建为ref,ref最终会作为napi_call_function的第三个参数,可以放心并没有在global对象里面直接去取函数引用。
另一种实现方式是JS侧传递给C++的回调函数是非匿名函数,使用napi_get_named_property在global对象中直接获取函数引用:
JS侧定义非匿名的回调函数:
function add(a: number, b:number) { return a + b; }
C++侧从global对象中取出add函数,在napi_call_function引入:
napi_value global, add, arg; napi_get_global(env, &global); // 在global对象中取出名为"add"的对象/函数名,保存在add中。 napi_get_named_property(env, global, "add", &add); ... // 调用add函数 napi_call_function(env, global, add, 2 , argv, &result);
总结
到此这篇关于JavaScript如何调用C++模块中函数的文章就介绍到这了,更多相关JS调用C++模块的函数内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!