前言
當(dāng)開發(fā)者為OpenHarmony系統(tǒng)上開發(fā)JS與C++ 交互的接口時(shí),需要使用NAPI進(jìn)行接口封裝:首先需要用戶定義JS接口,然后創(chuàng)建NAPI模塊、實(shí)現(xiàn)NAPI初始化函數(shù)、封裝JS接口、處理JS調(diào)用,最后進(jìn)行構(gòu)建和部署。這需要開發(fā)人員熟悉NAPI,有一定的學(xué)習(xí)成本。而Napi框架生成工具可以根據(jù)用戶指定路徑下的ts(typescript)接口文件一鍵生成NAPI框架代碼、業(yè)務(wù)代碼框架,這為開發(fā)者提供了一種快速、高效的開發(fā)方式,可以大大提高開發(fā)效率。使用該工具時(shí),開發(fā)者不必關(guān)注Nodejs的語法、C++與JS之間的數(shù)據(jù)類型轉(zhuǎn)換等上層應(yīng)用邏輯,只需要關(guān)注底層業(yè)務(wù)邏輯;此外,Napi框架生成工具還可以自動(dòng)生成GN文件,這樣就可以方便地將生成的代碼集成到OpenHarmony系統(tǒng)中。這種方式可以避免手動(dòng)編寫GN文件的繁瑣過程,提高了代碼集成的效率。
1.使用說明
NAPI框架生成工具支持三種入口,分別是可執(zhí)行程序、VS Code插件、DevEco Studio上使用的IntelliJ插件,使用者可以根據(jù)自己的需要選擇合適的工具。本文主要介紹可執(zhí)行文件的使用方法。
1.可執(zhí)行文件下載路徑如下(由于網(wǎng)絡(luò)原因,可能會(huì)導(dǎo)致有的下載鏈接失效,因此提供了以下三個(gè)下載鏈接):
訪問密碼:kaihong
壓縮包解壓密碼:kaihong20231121
準(zhǔn)備
輸入文件說明
1.待轉(zhuǎn)換的示例.ts文件 @ohos.napitest.d.ts
declare namespace napitest {? ? function func1(v: string): string; } export default napitest;
2.業(yè)務(wù)代碼serviceCode示例
業(yè)務(wù)代碼頭文件Service.h
#ifndef IMPL_SERVICE_H #define IMPL_SERVICE_H? #include <string>? namespace napitest {? ? std::string func1(std::string& v); } #endif // IMPL_SERVICE_H
業(yè)務(wù)代碼cpp文件Service.cpp
#include "Service.h" #include "../generatorCode/napitest.h" #include "hilog/log.h" static constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, 0XD002E00, "NAPITESTNAPILayer"}; #define NAPITEST_LOGI(fmt, ...) OHOS::HiviewDFX::HiLog::Info(LABEL, \? ? "%{public}s:%{public}d " fmt, __func__, __LINE__, ##__VA_ARGS__) namespace napitest { std::string func1(std::string& v) {? ? NAPITEST_LOGI("NAPITEST_LOGI func1 v = %s\r\n", v.c_str());? // 打印輸入?yún)?shù)? ? return "testzzz"; } }
3.配置文件cfg.json示例
[? {? ? "includeName": "../serviceCode/Service.h",? ? "cppName": "../serviceCode/Service.cpp",? ? "interfaceName": "func1",? ? "serviceCode": "out = napitest::func1(v);"? } ]
可執(zhí)行文件使用方法
Linux
1.將待轉(zhuǎn)換的.d.ts文件(如@ohos.napitest.d.ts)、napi_generator-linux、 配置文件cfg.json、業(yè)務(wù)代碼文件夾serviceCode(其中serviceCode目錄下放置業(yè)務(wù)代碼的.h文件和.cpp文件)放在同級(jí)目錄下。此處新建generatorCode文件夾,用于存放生成框架代碼。整體目錄文件如下:
OpenHarmony@Ubuntu-64:~/service$ ls napi_generator-linux? @ohos.napitest.d.ts? generatorCode? cfg.json? serviceCode
2.在終端中進(jìn)入到之前可執(zhí)行程序napi_generator-linux所在的目錄,并運(yùn)行napi_generator-linux,命令如下:
OpenHarmony@Ubuntu-64:~/service$ ./napi_generator-linux -f @ohos.napitest.d.ts -o generatorCode -i false -n int -s cfg.json
其中,參數(shù)詳情如下:
-f, 待轉(zhuǎn)換的.d.ts文件,若同時(shí)轉(zhuǎn)換多個(gè)文件,文件之間用“,”隔開;
-d, 根據(jù)指定路徑轉(zhuǎn)換該文件夾中所有.d.ts文件;
-i, 可選參數(shù),默認(rèn)false,待轉(zhuǎn)換.d.ts文件中引用非basic.d.ts的ts文件時(shí)打開開關(guān);
-o, 可選參數(shù),默認(rèn)為當(dāng)前目錄,指定生成框架代碼輸出路徑;
-n, 可選參數(shù),默認(rèn)為uint32_t,指定生成框架代碼中number類型全部為指定類型;
-s, 可選參數(shù),默認(rèn)為不配置業(yè)務(wù)代碼,指定生成框架代碼的業(yè)務(wù)配置文件,用于粘合工具代碼和業(yè)務(wù)代碼的配置。
備注1:-f與-d兩個(gè)參數(shù)只選其中一個(gè)參數(shù)即可。
備注2:若.d.ts文件中聲明了basic.d.ts文件,將basic.d.ts文件放置在待轉(zhuǎn)換.d.ts文件同一級(jí)目錄;若除此之外還聲明其它.d.ts文件,將此類文件放置在待轉(zhuǎn)換.d.ts文件同級(jí)目錄。
其中,cfg.json內(nèi)容如下:
[? {? "includeName": "../serviceCode/Service.h",? "cppName": "../serviceCode/Service.cpp",? "interfaceName": "func1",? "serviceCode": "out = napitest::func1(v);",? "description": "includeName: 引入的業(yè)務(wù)代碼.h文件相對(duì)路徑, cppName: 引入的業(yè)務(wù)代碼.cpp文件相對(duì)路徑, interfaceName: ts文件中的使用接口名,業(yè)務(wù)代碼就在該接口中調(diào)用;格式為:類名::方法名(如: TestClass::funcTest1),若無類名,則格式為:方法名(如: funcTest), serviceCode: 在接口中調(diào)用業(yè)務(wù)代碼的調(diào)用語句。(該屬性只做注釋使用)"? } ]
cfg.json是一個(gè)數(shù)組,每一項(xiàng)配置對(duì)應(yīng)一個(gè)方法的調(diào)用,需要對(duì)多少方法進(jìn)行調(diào)用就配置多少項(xiàng);其中
“includeName”: 引入的業(yè)務(wù)代碼.h文件相對(duì)路徑, 如: “…/serviceCode/Service.h”,
“cppName”: 引入的業(yè)務(wù)代碼.cpp文件相對(duì)路徑, 如:“…/serviceCode/Service.cpp”,
“interfaceName”: ts文件中的使用接口名,業(yè)務(wù)代碼就在該接口中調(diào)用;格式為:類名::方法名(如: TestClass::funcTest1),若無類名,則格式為:方法名(如: func1),
“serviceCode”: 在接口中調(diào)用業(yè)務(wù)代碼的調(diào)用語句。此處調(diào)用的是實(shí)現(xiàn)該接口的業(yè)務(wù)代碼, 如:“out = napitest::func1(v);”
“description”: 僅作為cfg.json文件中描述其它字段含義的屬性,用戶配置時(shí),可以不用填寫這個(gè)字段
3.運(yùn)行成功后會(huì)在generatorCode目錄下生成框架代碼文件,如下所示:
OpenHarmony@Ubuntu-64:~/linshi/napi_generator_8/examples/ts/generatorCode$ ls binding.gyp? BUILD.gn? napi_gen.log? napitest.cpp? napitest.h? napitest_middle.h napitest_middle.cpp? test.sh? tool_utility.cpp? tool_utility.h
Windows
1.將待轉(zhuǎn)換的.d.ts文件(如@ohos.napitest.d.ts)、napi_generator-win.exe、 配置文件cfg.json、業(yè)務(wù)代碼文件夾serviceCode(其中serviceCode目錄下放置業(yè)務(wù)代碼的.h文件和.cpp文件)放在同級(jí)目錄下。此處新建generatorCode文件夾,用于存放生成框架代碼。整體目錄文件如下:
E:\demo\napi>dir /B @ohos.napitest.d.ts napi_generator-win.exe generatorCode cfg.json serviceCode
2.在終端中進(jìn)入到之前可執(zhí)行程序napi_generator-win.exe所在的目錄,并運(yùn)行napi_generator-win.exe,命令如下:
E:\demo\napi>napi_generator-win.exe -f @ohos.napitest.d.ts -o generatorCode -i false -n double -s cfg.json
1.
其中,參數(shù)詳情如下:
-f, 待轉(zhuǎn)換的.d.ts文件,若同時(shí)轉(zhuǎn)換多個(gè)文件,文件之間用“,”隔開;
-d, 根據(jù)指定路徑轉(zhuǎn)換該文件夾中所有.d.ts文件;
-i, 可選參數(shù),默認(rèn)false,待轉(zhuǎn)換.d.ts文件中引用非basic.d.ts的ts文件時(shí)打開開關(guān);
-o, 可選參數(shù),默認(rèn)為當(dāng)前目錄,指定生成框架代碼輸出路徑;
-n, 可選參數(shù),默認(rèn)為uint32_t,指定生成框架代碼中number類型全部為指定類型;
-s, 可選參數(shù),默認(rèn)為不配置業(yè)務(wù)代碼,指定生成框架代碼的業(yè)務(wù)配置文件,用于粘合工具代碼和業(yè)務(wù)代碼的配置。
備注1:-f與-d兩個(gè)參數(shù)只選其中一個(gè)參數(shù)即可。
備注2:若.d.ts文件中聲明了basic.d.ts文件,將basic.d.ts文件放置在待轉(zhuǎn)換.d.ts文件同一級(jí)目錄;若除此之外還聲明其它.d.ts文件,將此類文件放置在待轉(zhuǎn)換.d.ts文件同級(jí)目錄。
其中,cfg.json內(nèi)容如下:
[? {? "includeName": "../serviceCode/Service.h",? "cppName": "../serviceCode/Service.cpp",? "interfaceName": "func1",? "serviceCode": "out = napitest::func1(v);",? "description": "includeName: 引入的業(yè)務(wù)代碼.h文件相對(duì)路徑, cppName: 引入的業(yè)務(wù)代碼.cpp文件相對(duì)路徑, interfaceName: ts文件中的使用接口名,業(yè)務(wù)代碼就在該接口中調(diào)用;格式為:類名::方法名(如: TestClass::funcTest1),若無類名,則格式為:方法名(如: funcTest), serviceCode: 在接口中調(diào)用業(yè)務(wù)代碼的調(diào)用語句。(該屬性只做注釋使用)"? } ]
cfg.json是一個(gè)數(shù)組,每一項(xiàng)配置對(duì)應(yīng)一個(gè)方法的調(diào)用,需要對(duì)多少方法進(jìn)行調(diào)用就配置多少項(xiàng);其中
“includeName”: 引入的業(yè)務(wù)代碼.h文件相對(duì)路徑, 如: “…/serviceCode/Service.h”,
“cppName”: 引入的業(yè)務(wù)代碼.cpp文件相對(duì)路徑, 如:“…/serviceCode/Service.cpp”,
“interfaceName”: ts文件中的使用接口名,業(yè)務(wù)代碼就在該接口中調(diào)用;格式為:類名::方法名(如: TestClass::funcTest1),若無類名,則格式為:方法名(如: func1),
“serviceCode”: 在接口中調(diào)用業(yè)務(wù)代碼的調(diào)用語句。此處調(diào)用的是實(shí)現(xiàn)該接口的業(yè)務(wù)代碼, 如:“out = napitest::func1(v);”
“description”: 僅作為cfg.json文件中描述其它字段含義的屬性,用戶配置時(shí),可以不用填寫這個(gè)字段
3.運(yùn)行成功后會(huì)在generatorCode目錄下生成框架代碼文件,如下所示:
E:\demo\napi\generatorCode>dir /B binding.gyp BUILD.gn napitest.cpp napitest.h napitest_middle.h napitest_middle.cpp napi_gen.log test.sh tool_utility.cpp tool_utility.h
Mac
方法步驟參考windows、Linux的使用方法。
不配置cfg.json文件生成框架代碼
若使用配置文件配置業(yè)務(wù)代碼不能滿足用戶使用場(chǎng)景需求,可手動(dòng)配置業(yè)務(wù)代碼,參考以下鏈接:
輸出文件說明
Napi工具生成文件如下所示:
binding.gyp BUILD.gn napitest.cpp napitest.h napitest_middle.h napitest_middle.cpp napi_gen.log test.sh tool_utility.cpp tool_utility.h
其中binding.gyp為工具生成框架代碼后自測(cè)時(shí)的編譯配置文件;BUILD.gn為集成到OpenHarmony系統(tǒng)上的編譯配置文件;napitest.h和napitest.cpp是工具生成的業(yè)務(wù)代碼文件,業(yè)務(wù)開發(fā)者在這里對(duì)業(yè)務(wù)接口進(jìn)行調(diào)用或進(jìn)行業(yè)務(wù)代碼實(shí)現(xiàn);而napitest_middle.h,napitest_middle.cpp,tool_utility.h,tool_utility.cpp為膠水代碼,即NAPI框架代碼,用于創(chuàng)建NAPI模塊、實(shí)現(xiàn)NAPI初始化函數(shù)、參數(shù)轉(zhuǎn)換、封裝JS接口、處理JS調(diào)用等;napi_gen.log為工具生成的日志文件。
2.集成說明
本集成說明針對(duì)的是OpenHarmony 4.0release系統(tǒng),其他系統(tǒng)可能存在差別,開發(fā)者可自行調(diào)試修改。
用戶使用配置文件cfg.json生成框架代碼后,不必再手動(dòng)修改業(yè)務(wù)代碼,直接將生成代碼集成到OpenHarmony的方法參考以下鏈接:
若在生成框架代碼時(shí),用戶未選擇配置文件cfg.json生成框架代碼,那么在集成時(shí)用戶就需要在生成的框架代碼中自行添加業(yè)務(wù)代碼,例如當(dāng)前ts文件生成的napitest.cpp文件,修改相應(yīng)代碼后如下所示:
#include "napitest.h" #include "hilog/log.h" static constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, 0XD002E00, "NAPITESTNAPILayer"}; #define NAPITEST_LOGI(fmt, ...) OHOS::HiviewDFX::HiLog::Info(LABEL, \? ? "%{public}s:%{public}d " fmt, __func__, __LINE__, ##__VA_ARGS__) namespace napitest { bool func1(std::string& v, std::string& out) {? ? NAPITEST_LOGI("NAPITEST_LOGI func1 v = %s\r\n", v.c_str());? // 打印輸入?yún)?shù)? ? out = "testzzz";? ? return true; } }
手動(dòng)配置業(yè)務(wù)代碼之后集成到OpenHarmony的方法參考以下鏈接:
4.0版本手動(dòng)配置業(yè)務(wù)代碼集成方法
3.應(yīng)用測(cè)試
準(zhǔn)備
1.硬件:rk3568開發(fā)套件。
2.系統(tǒng)鏡像: 集成到OpenHarmony并編譯成功的鏡像,路徑如下:
OpenHarmony/out/rk3568/packages/phone/images
3.擴(kuò)展SDK接口并增加新接口調(diào)用
3.1 擴(kuò)展SDK接口
查看SDK目錄:
添加圖片注釋,不超過 140 字(可選)
將@ohos.napitest.d.ts文件拷貝到sdk目錄下的ets\api:
添加圖片注釋,不超過 140 字(可選)
編輯
3.2 編寫應(yīng)用測(cè)試新接口
其中修改index.ets文件內(nèi)容如下:
import hilog from '@ohos.hilog'; import napitest from '@ohos.napitest'; @Entry @Component struct Index { ? @State message: string = 'Hello World' ? build() { ? ? Row() { ? ? ? Column() { ? ? ? ? Text(this.message) ? ? ? ? ? .fontSize(50) ? ? ? ? ? .fontWeight(FontWeight.Bold) ? ? ? ? // 添加按鈕,以響應(yīng)用戶點(diǎn)擊 ? ? ? ? Button() { ? ? ? ? ? Text('TEST') ? ? ? ? ? ? .fontSize(30) ? ? ? ? ? ? .fontWeight(FontWeight.Bold) ? ? ? ? } ? ? ? ? .type(ButtonType.Capsule) ? ? ? ? .margin({ ? ? ? ? ? top: 20 ? ? ? ? }) ? ? ? ? .backgroundColor('#0D9FFB') ? ? ? ? .width('40%') ? ? ? ? .height('5%') ? ? ? ? // 跳轉(zhuǎn)按鈕響應(yīng) ? ? ? ? .onClick(() => { ? ? ? ? ? let out = napitest.func1("abcf"); ? ? ? ? ? hilog.info(0x0000, 'testTag', '%{public}s', 'AAAAAAAA napi testprint' + out); ? ? ? ? }) ? ? ? } ? ? ? .width('100%') ? ? } ? ? .height('100%') ? } }
使用說明
步驟一:安裝鏡像環(huán)境:將out/rk3568/packages/phone目錄下的images鏡像文件下載并燒錄到開發(fā)板上。
OpenHarmony@Ubuntu-64:~/OpenHarmony/out/rk3568/packages/phone/images$ ll? total 767452? drwxrwxrwx? 2 root root? ? ? 4096 Nov 21 05:32 ./? drwxrwxrwx 15 root root? ? ? 4096 Nov 21 05:32 ../? -rwxrwxrwx? 1 root root? 67108864 Nov 21 05:04 boot_linux.img*? -rw-r--r--? 1 root root? 52428800 Nov 21 05:32 chip_prod.img? -rwxrwxrwx? 1 root root? ? ? 8569 Nov 21 05:04 config.cfg*? -rw-r--r--? 1 root root? 12582912 Nov 21 05:32 eng_system.img? -rwxrwxrwx? 1 root root? ? 455104 Nov 21 05:04 MiniLoaderAll.bin*? -rwxrwxrwx? 1 root root? ? ? ? 756 Nov 21 05:04 parameter.txt*? -rw-rw-r--? 1 root root? ? 2507625 Nov 21 05:32 ramdisk.img? -rwxrwxrwx? 1 root root? ? 5639680 Nov 21 05:04 resource.img*? -rw-r--r--? 1 root root? 52428800 Nov 21 05:32 sys_prod.img? -rw-r--r--? 1 root root 1610608640 Nov 21 05:32 system.img? -rwxrwxrwx? 1 root root? ? 4194304 Nov 21 05:04 uboot.img*? -rw-rw-r--? 1 root root? 15806303 Nov 21 05:32 updater.img? -rw-r--r--? 1 root root 1468006400 Nov 21 05:32 userdata.img? -rw-r--r--? 1 root root? 268431360 Nov 21 05:32 vendor.img
步驟二:安裝hap包。
Build Haps通過后,通過Run按鈕將hap包安裝到板子上。
執(zhí)行完成后,設(shè)備中會(huì)出現(xiàn)安裝的APP。
步驟三:打印日志并驗(yàn)證結(jié)果。
hap包安裝成功后,進(jìn)入hdc shell
首先執(zhí)行以下命令關(guān)閉hilog隱私權(quán)限
hilog -p off
輸入命輸入命令實(shí)時(shí)打印日志并輸出至windows中。
.\hdc.exe hilog > log.txt
然后單擊設(shè)備中安裝的APP,進(jìn)入APP后單擊測(cè)試按鈕,執(zhí)行完成后會(huì)在hdc安裝目錄下出現(xiàn)log.txt文件。
查看結(jié)果
log.txt中包含“AAAAAAAA napi testprint testzzz”日志表示接口調(diào)用成功。如下所示:
// 打印js層傳遞給C++的入?yún)bcf I C02e00/NAPITESTNAPILayer: [Service.cpp:10] NAPITEST_LOGI func1 v = abcf // 打印接口返回到j(luò)s的返回值testzzz 01-01 08:10:55.571? 2291? 2291 I A00000/testTag: AAAAAAAA napi testprint testzzz
使用問題
問題:用可執(zhí)行程序生成C++代碼失敗,log如下所示:
E:\napi_generator_aboutTest\zzx_gjj_napi230808\napiTest>napi_generator-win.exe -f @ohos.napitest.d.ts at checkGenerate [C:\snapshot\napi_generator\src\gen\cmd_gen.js(135:21)] @ohos.napitest.d.ts (15,41): Cannot find module './basic'. Did you mean to set the 'moduleResolution' option to 'node', or to add aliases to the 'paths' option?? fail @ohos.napitest.d.ts (15,41): Cannot find module './basic'. Did you mean to set the 'moduleResolution' option to 'node', or to add aliases to the 'paths' option?
問題定位:@ohos.napitest.d.ts依賴了文件basic.d.ts,但在@ohos.napitest.d.ts同級(jí)目錄下未找到該依賴文件。
Cannot find module './basic'.
解決方案:將依賴文件basic.d.ts放在@ohos.napitest.d.ts同級(jí)目錄下,若@ohos.napitest.d.ts中還引用了其他依賴文件,需要一一將其加入到其依賴的路徑下。
更多常見問題解決方法指導(dǎo)如下:
相關(guān)倉
關(guān)于Napi工具,若想了解更多,請(qǐng)參考以下鏈接:
總結(jié)
Napi框架生成工具是一個(gè)開源項(xiàng)目,我們歡迎有興趣的開發(fā)者試用該工具,并提出寶貴的改進(jìn)意見,我們將繼續(xù)不斷優(yōu)化和完善該工具軟件。