JavaScript如何調(diào)用C++模塊中的函數(shù)
場(chǎng)景一:JS側(cè)調(diào)用C++側(cè)函數(shù),并傳遞參數(shù)
JS側(cè)調(diào)用C++側(cè)函數(shù)
import testNapi from 'libentry.so' const TAG = "beixiang"; @Entry @Component struct Index { build() { Row() { Column() { Text('調(diào)用testNapi.add') .fontSize(50) .fontWeight(FontWeight.Bold) .onClick(() => { const result = testNapi.add(3,4); console.log(`${TAG} 調(diào)用testNapi.add的結(jié)果為${result}`); }) } .width('100%') } .height('100%') } }
C++側(cè)方法實(shí)現(xiàn)
static napi_value Add(napi_env env, napi_callback_info info) { // 獲取 2 個(gè)參數(shù),napi_value是對(duì) JS 類型的封裝 size_t argc = 2; napi_value argv[2] = {nullptr}; // 調(diào)用napi_get_cb_info方法,從 info 中讀取傳遞進(jìn)來(lái)的參數(shù)放入argv里 napi_get_cb_info(env, info, &argc, argv , nullptr, nullptr); // 獲取參數(shù)并校驗(yàn)類型 napi_valuetype valuetype0; napi_typeof(env, argv[0], &valuetype0); napi_valuetype valuetype1; napi_typeof(env, argv[1], &valuetype1); // 調(diào)用napi_get_value_double把 napi_value 類型轉(zhuǎn)換成 C++ 的 double 類型 double value0; napi_get_value_double(env, argv[0], &value0); double value1; napi_get_value_double(env, argv[1], &value1); // 調(diào)用napi_create_double方法把 C++類型轉(zhuǎn)換成 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:調(diào)用 API 的環(huán)境
- cbinfo:傳遞給回調(diào)函數(shù)的回調(diào)信息
- argc:指定提供的 argv 數(shù)組的大小并接收參數(shù)的實(shí)際計(jì)數(shù)
- argv:將表示參數(shù)的 napi_value 復(fù)制到的緩沖區(qū)
- this_arg:接收調(diào)用的 JavaScript this 參數(shù)
- data:接收回調(diào)的數(shù)據(jù)指針
例如Add方法的代碼,
napi_get_cb_info(env, info, &argc, argv , nullptr, nullptr);
,從 info 中讀取傳遞進(jìn)來(lái)的&argc個(gè)參數(shù)放入argv。napi_get_value_double(napi_env env, napi_value value, double *result)
把 napi_value 類型轉(zhuǎn)換成 C++ 的 double 類型,供C++側(cè)使用
napi_create_double(napi_env env, double value, napi_value *result)
把 C++ double類型轉(zhuǎn)換成 napi_value 類型,供JS側(cè)使用
napi_create_function(napi_env env, const char *utf8name, size_t length, napi_callback cb, void *data, napi_value *result)
不同于以上定義函數(shù),并在Init()
方法內(nèi)聲明 napi_property_descriptor 結(jié)構(gòu)體導(dǎo)出函數(shù)的方式,使用 napi_create_function允許將C++側(cè)函數(shù)創(chuàng)建為可供JS側(cè)調(diào)用的函數(shù)對(duì)象,然后使用napi_set_named_property將創(chuàng)建的函數(shù)對(duì)象導(dǎo)出,以便可以從JS側(cè)訪問(wèn)該函數(shù),如下代碼:
// xxx.cpp EXTERN_C_START static napi_value Init(napi_env env, napi_value exports) { napi_value fn; // 根據(jù)C++側(cè)函數(shù)Add創(chuàng)建函數(shù)fn napi_create_function(env, nullptr, 0, Add, nullptr, &fn); // 將創(chuàng)建的函數(shù)fn導(dǎo)出,函數(shù)名為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;
場(chǎng)景二:JS側(cè)不傳參給回調(diào)函數(shù),C++側(cè)接收J(rèn)S側(cè)回調(diào)函數(shù)并執(zhí)行
JS側(cè)調(diào)用C++側(cè)函數(shù)
import testNapi from 'libentry.so' const TAG = "beixiang"; @Entry @Component struct Index { build() { Row() { Column() { Text('調(diào)用無(wú)參回調(diào)函數(shù)') .fontSize(50) .fontWeight(FontWeight.Bold) .onClick(() => { // 先注冊(cè)無(wú)參回調(diào)函數(shù) testNapi.registerCallback(() => { const a = 2; const b = 3; return a + b; }) // 調(diào)用無(wú)參回調(diào)函數(shù) const result = testNapi.handleCallbackWithoutParams(); console.log(`${TAG} 調(diào)用無(wú)參回調(diào)函數(shù)的結(jié)果為${result}`); }) } .width('100%') } .height('100%') } }
C++側(cè)注冊(cè)回調(diào)函數(shù)
// js函數(shù)回調(diào) static napi_ref callback = nullptr; /** * 注冊(cè)回調(diào)函數(shù) * @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++側(cè)執(zhí)行注冊(cè)回調(diào)函數(shù)
/** * 執(zhí)行回調(diào)函數(shù),不帶參數(shù) * @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 為傳入的對(duì)象創(chuàng)建一個(gè)具有指定引用計(jì)數(shù)的新引用,例如注冊(cè)回調(diào)函數(shù)RegisterCallback中的napi_create_reference(env, argv[0], 1, &callback),將JS側(cè)傳入的對(duì)象argv[0](對(duì)JS來(lái)說(shuō),函數(shù)也是對(duì)象)保存在callback中,供C++側(cè)方法調(diào)用;
napi_get_reference_value(napi_env env, napi_ref ref, napi_value *result)
將創(chuàng)建的引用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:調(diào)用 API 的環(huán)境
- recv:this 對(duì)象傳遞給被調(diào)用的函數(shù),一般是當(dāng)前環(huán)境的global對(duì)象,通過(guò)napi_get_global來(lái)獲取。
- func:表示要調(diào)用的 JavaScript 函數(shù)
- argc:argv 數(shù)組中元素的計(jì)數(shù)。
- argv:表示作為參數(shù)傳遞給函數(shù)的 JavaScript 值的 napi_values 數(shù)組
- result:napi_value 表示返回的 JavaScript 對(duì)象
在env環(huán)境下,在global對(duì)象中調(diào)用函數(shù)func,該函數(shù)參數(shù)數(shù)組為argv,有argc個(gè)參數(shù),函數(shù)執(zhí)行結(jié)果保存在result。此API允許從C++側(cè)調(diào)用 JavaScript 函數(shù)對(duì)象,例如本文的napi_call_function(env, global, cb, 0 , nullptr, &result);
場(chǎng)景三:JS側(cè)傳參給回調(diào)函數(shù),C++側(cè)接收J(rèn)S側(cè)回調(diào)函數(shù)并執(zhí)行
JS側(cè)調(diào)用C++側(cè)函數(shù)
import testNapi from 'libentry.so' const TAG = "beixiang"; @Entry @Component struct Index { build() { Row() { Column() { Text('調(diào)用有參回調(diào)函數(shù)') .fontSize(50) .fontWeight(FontWeight.Bold) .onClick(() => { // 先注冊(cè)無(wú)參回調(diào)函數(shù) testNapi.registerCallback((a: number, b: number) => { return a + b; }) // 調(diào)用無(wú)參回調(diào)函數(shù) const result = testNapi.handleCallbackWithParams(); console.log(`${TAG} 調(diào)用有參回調(diào)函數(shù)的結(jié)果為${result}`); }) } .width('100%') } .height('100%') } }
C++側(cè)注冊(cè)回調(diào)函數(shù)
/** * 注冊(cè)回調(diào)函數(shù) * @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++側(cè)執(zhí)行注冊(cè)回調(diào)函數(shù)
/** * 執(zhí)行回調(diào)函數(shù),帶參數(shù) * @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; // 創(chuàng)建兩個(gè)double,給callback調(diào)用 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; // 調(diào)用回調(diào)函數(shù) napi_status status = napi_call_function(env, global, cb, 2, argv, &result); if (status != napi_ok) return nullptr; return result; }
值得注意的是,本文JS側(cè)傳遞給C++的回調(diào)函數(shù)是匿名函數(shù),C++側(cè)先將JS回調(diào)函數(shù)先在C++側(cè)注冊(cè),即使用napi_create_reference將JS函數(shù)創(chuàng)建為ref,ref最終會(huì)作為napi_call_function的第三個(gè)參數(shù),可以放心并沒(méi)有在global對(duì)象里面直接去取函數(shù)引用。
另一種實(shí)現(xiàn)方式是JS側(cè)傳遞給C++的回調(diào)函數(shù)是非匿名函數(shù),使用napi_get_named_property在global對(duì)象中直接獲取函數(shù)引用:
JS側(cè)定義非匿名的回調(diào)函數(shù):
function add(a: number, b:number) { return a + b; }
C++側(cè)從global對(duì)象中取出add函數(shù),在napi_call_function引入:
napi_value global, add, arg; napi_get_global(env, &global); // 在global對(duì)象中取出名為"add"的對(duì)象/函數(shù)名,保存在add中。 napi_get_named_property(env, global, "add", &add); ... // 調(diào)用add函數(shù) napi_call_function(env, global, add, 2 , argv, &result);
總結(jié)
到此這篇關(guān)于JavaScript如何調(diào)用C++模塊中函數(shù)的文章就介紹到這了,更多相關(guān)JS調(diào)用C++模塊的函數(shù)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
js判斷手機(jī)是否安裝并打開(kāi)app,未安裝則安裝app【兼容Android、ios,親測(cè)可用】
這篇文章主要介紹了js判斷手機(jī)是否安裝并打開(kāi)app,未安裝則安裝app,通過(guò)調(diào)用瀏覽器判斷app,兼容Android、ios等系統(tǒng),,需要的朋友可以參考下2023-05-05JS制作簡(jiǎn)單的三級(jí)聯(lián)動(dòng)
本文給大家分享的是使用javascript實(shí)現(xiàn)的一個(gè)簡(jiǎn)單的三級(jí)聯(lián)動(dòng)菜單,非常簡(jiǎn)單實(shí)用,有需要的小伙伴過(guò)來(lái)參考下吧。2015-03-03通過(guò)實(shí)例解析js可枚舉屬性與不可枚舉屬性
這篇文章主要介紹了通過(guò)實(shí)例解析js可枚舉屬性與不可枚舉屬性,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-12-12使用requestAnimationFrame實(shí)現(xiàn)js動(dòng)畫(huà)性能好
requestAnimationFrame優(yōu)于setTimeout/setInterval的地方在于它是由瀏覽器專門(mén)為動(dòng)畫(huà)提供的API,在運(yùn)行時(shí)瀏覽器會(huì)自動(dòng)優(yōu)化方法的調(diào)用,并且如果頁(yè)面不是激活狀態(tài)下的話,動(dòng)畫(huà)會(huì)自動(dòng)暫停,有效節(jié)省了CPU開(kāi)銷,這篇文章給大家詳細(xì)介紹使用requestAnimationFrame實(shí)現(xiàn)js動(dòng)畫(huà)2015-08-08動(dòng)態(tài)添加js事件實(shí)現(xiàn)代碼
動(dòng)態(tài)添加js事件,主要是不用具體指定位置的事件,這種動(dòng)態(tài)添加事件的方法比較方便,并可以擴(kuò)展等。2009-03-03