javascript技巧

关注公众号 jb51net

关闭
首页 > 网络编程 > JavaScript > javascript技巧 > JS调用C++模块的函数

JavaScript如何调用C++模块中的函数

作者:Hens_Hello_Mr

这篇文章主要给大家介绍了关于JavaScript如何调用C++模块中函数的相关资料,文中通过代码介绍的非常详细,对大家的学习或者工作具有一定的参考借鉴价值,需要的朋友可以参考下

场景一: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;
}

不同于以上定义函数,并在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;
}

场景三: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++模块的函数内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

阅读全文