N-API在Android平臺(tái)應(yīng)用的使用指導(dǎo)
N-API接口可以實(shí)現(xiàn)ArkTS/TS/JS與C/C++(Native)之間的交互,ArkUI-X中支持的N-API接口情況和使用場(chǎng)景請(qǐng)見(jiàn)[FFI能力(N-API)]。本文檔以[ArkUI-X/Samples]中的Native樣例工程為例,介紹如何在Android平臺(tái)上使用N-API能力完成跨語(yǔ)言調(diào)用。
開(kāi)發(fā)流程
使用N-API完成跨語(yǔ)言調(diào)用的整體開(kāi)發(fā)流程分為以下五步,即
- 環(huán)境準(zhǔn)備:獲取Native工程。
- 提供Native能力:使用N-API接口提供Native能力,同時(shí),Native接口中還可調(diào)用ArkTS/TS/JS傳入的方法。
- 定義接口聲明:添加Native側(cè)暴露給ArkTS側(cè)接口的聲明。
- 調(diào)用Native能力:ArkTS/TS/JS側(cè)使用Native能力。
- 編譯與運(yùn)行應(yīng)用:編出應(yīng)用,并在android平臺(tái)上運(yùn)行,觀察效果。
- 開(kāi)發(fā)前請(qǐng)熟悉鴻蒙開(kāi)發(fā)指導(dǎo)文檔 :[gitee.com/li-shizhen-skin/harmony-os/blob/master/README.md]點(diǎn)擊或者復(fù)制轉(zhuǎn)到。
這里通過(guò)修改樣例工程,提供兩個(gè)例子來(lái)介紹N-API的典型使用場(chǎng)景:
- 提供一個(gè)名為
Add
的Native方法,ArkTS側(cè)調(diào)用該方法并傳入兩個(gè)number,Native方法將這兩個(gè)number相加并返回到ArkTS側(cè)。以此介紹:ArkTS側(cè)如何調(diào)用到Native側(cè)方法。 - 提供一個(gè)名為
NativeCallArkTS
的Native方法,ArkTS側(cè)調(diào)用該方法并傳入一個(gè)ArkTS function,Native方法中調(diào)用這個(gè)ArkTS function,并將其結(jié)果返回ArkTS側(cè)。以此介紹:Native側(cè)如何調(diào)用到ArkTS側(cè)方法。
1. 環(huán)境準(zhǔn)備
從[ArkUI-X/Samples]中獲取Native樣例工程,并使用DevEco Studio(V4.0 Beta2及以上版本)打開(kāi)該工程,打開(kāi)后將自動(dòng)進(jìn)行工程初始化。
2. 提供Native能力
利用N-API接口,進(jìn)行Native能力開(kāi)發(fā)。同時(shí),本樣例中的NativeCallArkTS
也完成了Native側(cè)調(diào)ArkTS側(cè)的演示。
// entrysrcmaincpphello.cpp,包含Native側(cè)邏輯。
// 引入N-API相關(guān)頭文件。
#include "napi/native_api.h"
// 開(kāi)發(fā)者提供的Native方法,入?yún)⒂星覂H有如下兩個(gè),開(kāi)發(fā)者不需進(jìn)行變更。
// napi_env 為當(dāng)前運(yùn)行的上下文。
// napi_callback_info 記錄了一些信息,包括從ArkTS側(cè)傳遞過(guò)來(lái)參數(shù)等。
static napi_value Add(napi_env env, napi_callback_info info)
{
// 期望從ArkTS側(cè)獲取的參數(shù)的數(shù)量,napi_value可理解為ArkTS value在Native方法中的表現(xiàn)形式。
size_t argc = 2;
napi_value args[2] = {nullptr};
// 從info中,拿到從ArkTS側(cè)傳遞過(guò)來(lái)的參數(shù),此處獲取了兩個(gè)ArkTS參數(shù),即arg[0]和arg[1]。
napi_get_cb_info(env, info, &argc, args , nullptr, nullptr);
// 獲取arg[0]的類型
napi_valuetype valuetype0 = napi_undefined;
napi_typeof(env, args[0], &valuetype0);
// 獲取arg[1]的類型
napi_valuetype valuetype1 = napi_undefined;
napi_typeof(env, args[1], &valuetype1);
// 校驗(yàn)入?yún)㈩愋停舨皇莕umber,則返回undefined
if ((valuetype0 != napi_number) || (valuetype1 != napi_number)) {
napi_value undefined = nullptr;
napi_get_undefined(env, &undefined);
return undefined;
}
// 將獲取的ArkTS參數(shù)轉(zhuǎn)換為Native信息,此處ArkTS側(cè)傳入了兩個(gè)number,這里將其轉(zhuǎn)換為Native側(cè)可以操作的double類型。
double value0;
napi_get_value_double(env, args[0], &value0);
double value1;
napi_get_value_double(env, args[1], &value1);
// Native側(cè)的業(yè)務(wù)邏輯,這里簡(jiǎn)單以兩數(shù)相加為例。
double nativeSum = value0 + value1;
// 此處將Native側(cè)業(yè)務(wù)邏輯處理結(jié)果轉(zhuǎn)換為ArkTS值,并返回給ArkTS。
napi_value sum = nullptr;
napi_create_double(env, nativeSum , &sum);
return sum;
}
static napi_value NativeCallArkTS(napi_env env, napi_callback_info info)
{
// 期望從ArkTS側(cè)獲取的參數(shù)的數(shù)量,napi_value可理解為ArkTS value在Native方法中的表現(xiàn)形式。
size_t argc = 1;
napi_value args[1] = {nullptr};
// 從info中,拿到從ArkTS側(cè)傳遞過(guò)來(lái)的參數(shù),此處獲取了一個(gè)ArkTS參數(shù),即arg[0]。
napi_get_cb_info(env, info, &argc, args , nullptr, nullptr);
// 獲取arg[0]的類型
napi_valuetype valuetype = napi_undefined;
napi_typeof(env, args[0], &valuetype);
// 校驗(yàn)入?yún)㈩愋?/span>
if (valuetype != napi_function) {
napi_value undefined = nullptr;
napi_get_undefined(env, &undefined);
return undefined;
}
// 創(chuàng)建一個(gè)ArkTS string作為ArkTS function的入?yún)ⅰ?/span>
napi_value argv = nullptr;
// 創(chuàng)建一個(gè)js string
napi_create_string_utf8(env, "hello", NAPI_AUTO_LENGTH, &argv);
napi_value result = nullptr;
// Native方法中調(diào)用ArkTS function,其返回值保存到result中并返到ArkTS側(cè)。
napi_call_function(env, nullptr, args[0], 1, &argv, &result);
return result;
}
EXTERN_C_START
// Init將在exports上掛上Add/NativeCallArkTS這些Native方法,此處的exports就是開(kāi)發(fā)者import之后獲取到的ArkTS對(duì)象。
static napi_value Init(napi_env env, napi_value exports)
{
// 函數(shù)描述結(jié)構(gòu)體,以Add為例,第三個(gè)參數(shù)"Add"為上述的Native方法,
// 第一個(gè)參數(shù)"add"為ArkTS側(cè)對(duì)應(yīng)方法的名稱。
napi_property_descriptor desc[] = {
{ "add", nullptr, Add, nullptr, nullptr, nullptr, napi_default, nullptr },
{ "nativeCallArkTS", nullptr, NativeCallArkTS, nullptr, nullptr, nullptr, napi_default, nullptr },
};
// 在exports這個(gè)ArkTS對(duì)象上,掛載Native方法。
napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
return exports;
}
EXTERN_C_END
// 準(zhǔn)備模塊加載相關(guān)信息,將上述Init函數(shù)與本模塊名等信息記錄下來(lái)。
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 },
};
// 打開(kāi)so時(shí),該函數(shù)將自動(dòng)被調(diào)用,使用上述demoModule模塊信息,進(jìn)行模塊注冊(cè)相關(guān)動(dòng)作。
extern "C" __attribute__((constructor)) void RegisterHelloModule(void)
{
napi_module_register(&demoModule);
}
3. 定義接口聲明
在d.ts
文件中添加暴露接口聲明
// entrysrcmaincpptypeslibentryindex.d.ts,包含Native側(cè)暴露給ArkTS側(cè)接口的聲明。
// Native側(cè)暴露給ArkTS側(cè)接口的聲明。
export const add: (a: number, b: number) = > number;
export const nativeCallArkTS: (a: object) = > string;
4. 調(diào)用Native能力
在ArkTS/TS/JS側(cè)使用Native能力。
entry.add
接口完成了ArkTS -> Native
的調(diào)用。entry.nativeCallArkTS
接口完成了ArkTS -> Native -> ArkTS
的調(diào)用。
// entrysrcmainetspagesIndex.ets,包含ArkTS側(cè)邏輯。
// 通過(guò)import的方式,引入Native能力。
import entry from 'libentry.so'
function TestFunction(str) {
let ret = str + ' world!'
return ret;
}
@Entry
@Component
struct Index {
@State message: string = 'Test native api: 2 + 3 = ?'
@State message2: string = 'Click me'
build() {
Row() {
Column() {
// 第一個(gè)按鈕,調(diào)用add方法,對(duì)應(yīng)到Native側(cè)的Add方法,進(jìn)行兩數(shù)相加。
Text(this.message)
.fontSize(50)
.fontWeight(FontWeight.Bold)
.onClick(() = > {
this.message = "Test native api: 2 + 3 = " + entry.add(2, 3);
console.log("Test NAPI 2 + 3 = " + entry.add(2, 3));
})
// 第二個(gè)按鈕,調(diào)用nativeCallArkTS方法,對(duì)應(yīng)到Native的NativeCallArkTS,在Native中執(zhí)行ArkTS function。
Text(this.message2)
.fontSize(50)
.fontWeight(FontWeight.Bold)
.onClick(() = > {
this.message2 = entry.nativeCallArkTS(TestFunction);
})
}
.width('100%')
}
.height('100%')
}
}
5. 編譯與運(yùn)行應(yīng)用
點(diǎn)擊DevEco Studio(V4.0 Beta2及以上版本)中的"Build > Build Hap(s)/APP(s) > Build APP(s)"進(jìn)行編譯,并利用Android Studio打開(kāi)Native工程的".arkui-xandroid"文件夾,點(diǎn)擊"Run app"按鈕后運(yùn)行應(yīng)用。應(yīng)用運(yùn)行后,點(diǎn)擊頁(yè)面上的兩個(gè)文本,文本做出相應(yīng)變換。
開(kāi)發(fā)建議
注冊(cè)建議
- nm_register_func對(duì)應(yīng)的函數(shù)(如上述Init函數(shù))需要加上static,防止與其他so里的符號(hào)沖突。
- 模塊注冊(cè)的入口,即使用__attribute__((constructor))修飾的函數(shù)的函數(shù)名(如上述RegisterHelloModule函數(shù))需要確保不與其他模塊重復(fù)。
so命名規(guī)則
so命名必須符合以下規(guī)則:
- 每個(gè)模塊對(duì)應(yīng)一個(gè)so。
- 如模塊名為
entry
,則so的名字為libentry.so
,napi_module
中nm_modname
字段應(yīng)為entry
,大小寫(xiě)與模塊名保持一致,應(yīng)用使用時(shí)寫(xiě)作:import entry from 'libentry.so'
。
JS對(duì)象線程限制
ArkCompiler會(huì)對(duì)JS對(duì)象線程進(jìn)行保護(hù),使用不當(dāng)會(huì)引起應(yīng)用crash,因此需要遵循如下原則:
- N-API接口只能在JS線程使用。
- Native接口入?yún)⒌膃nv與線程綁定,不能跨線程使用。Native側(cè)JS對(duì)象只能在創(chuàng)建時(shí)的線程使用,即與線程所持有的env綁定。
頭文件引入限制
在引入頭文件時(shí),需引入"napi/native_api.h",否則會(huì)出現(xiàn)N-API接口無(wú)法找到的編譯報(bào)錯(cuò)。
HarmonyOS與OpenHarmony鴻蒙文檔籽料:mau123789是v直接拿
N-API在iOS平臺(tái)應(yīng)用的使用指導(dǎo)
N-API接口可以實(shí)現(xiàn)ArkTS/TS/JS與C/C++(Native)之間的交互,ArkUI-X中支持的N-API接口情況和使用場(chǎng)景請(qǐng)見(jiàn)[FFI能力(N-API)]。N-API在iOS平臺(tái)上的使用方式中,除去"編譯與運(yùn)行應(yīng)用"環(huán)節(jié)與Android平臺(tái)略有差異外,其余部分均與Android平臺(tái)相同。本文檔將主要介紹N-API在iOS平臺(tái)上的"編譯與運(yùn)行應(yīng)用"環(huán)節(jié),其他環(huán)節(jié)可參考[N-API在Android平臺(tái)應(yīng)用的使用指導(dǎo)]。
編譯與運(yùn)行應(yīng)用
相較于Android平臺(tái),iOS平臺(tái)上編譯/運(yùn)行Native工程時(shí)需要進(jìn)行簽名操作,完整步驟如下:
- 點(diǎn)擊DevEco Studio(V4.0 Beta2及以上版本)中的"Build > Build Hap(s)/APP(s) > Build APP(s)"進(jìn)行編譯。
- 使用Xcode工具打開(kāi)".arkui-xios"文件,在Xcode中完成簽名操作。
- 點(diǎn)擊Xcode中的運(yùn)行按鈕以完成二次打包,運(yùn)行應(yīng)用。
-
移動(dòng)開(kāi)發(fā)
+關(guān)注
關(guān)注
0文章
52瀏覽量
10813 -
鴻蒙系統(tǒng)
+關(guān)注
關(guān)注
183文章
2642瀏覽量
68974 -
HarmonyOS
+關(guān)注
關(guān)注
80文章
2141瀏覽量
34905 -
OpenHarmony
+關(guān)注
關(guān)注
31文章
3891瀏覽量
20153 -
鴻蒙OS
+關(guān)注
關(guān)注
0文章
191瀏覽量
5229
發(fā)布評(píng)論請(qǐng)先 登錄
跨Android、iOS、鴻蒙多平臺(tái)框架ArkUI-X

鴻蒙開(kāi)發(fā)接口公共事件與通知:【@ohos.commonEvent (公共事件模塊)】

鴻蒙開(kāi)發(fā)接口公共事件與通知:【Notification模塊】

鴻蒙ArkUI-X跨語(yǔ)言調(diào)用說(shuō)明:【平臺(tái)橋接開(kāi)發(fā)指南(Android)Bridge API】

鴻蒙原生應(yīng)用/元服務(wù)開(kāi)發(fā)-通知添加行為意圖
鴻蒙實(shí)戰(zhàn)開(kāi)發(fā)-如何安全和高效的使用N-API開(kāi)發(fā)Native模塊
基于ArkTS語(yǔ)言的OpenHarmony APP應(yīng)用開(kāi)發(fā):公共事件的訂閱和發(fā)布
ArkUI-x跨平臺(tái)Bridge最佳實(shí)踐
HarmonyOS應(yīng)用開(kāi)發(fā)-公共事件處理
HarmonyOS-API7相對(duì)API6差異主要變更內(nèi)容
HarmonyOS/OpenHarmony應(yīng)用開(kāi)發(fā)-ArkTSAPI系統(tǒng)能力SystemCapability
OpenHarmony 應(yīng)用開(kāi)發(fā)SDK、API 與基礎(chǔ)工具
N-API的JS堆對(duì)象生命周期管理

鴻蒙開(kāi)發(fā)接口公共事件與通知:【FFI能力(Node-API)】

評(píng)論