介紹
本篇Codelab主要介紹如何使用DevEco Studio創(chuàng)建一個(gè)Native C++應(yīng)用。應(yīng)用采用Native C++模板,實(shí)現(xiàn)使用NAPI調(diào)用C標(biāo)準(zhǔn)庫(kù)的功能。使用C標(biāo)準(zhǔn)庫(kù)hypot接口計(jì)算兩個(gè)給定數(shù)平方和的平方根。在輸入框中輸入兩個(gè)數(shù)字,點(diǎn)擊計(jì)算結(jié)果按鈕顯示計(jì)算后的數(shù)值。
相關(guān)概念
- [Native API]:NAPI提供的接口名與三方Node.js一致,目前支持部分接口。
- [Native API中支持的標(biāo)準(zhǔn)庫(kù)]:目前支持標(biāo)準(zhǔn)C庫(kù)、C++庫(kù)、OpenSL ES、zlib。
環(huán)境搭建
軟件要求
- [DevEco Studio]版本:DevEco Studio 3.1 Release。
- OpenHarmony SDK版本:API version 9。
- 鴻蒙文檔參考:[
gitee.com/li-shizhen-skin/harmony-os/blob/master/README.md
]
硬件要求
- 開發(fā)板類型:[潤(rùn)和RK3568開發(fā)板]。
- OpenHarmony系統(tǒng):3.2 Release。
鴻蒙NEXT學(xué)習(xí)文檔紫料可mau123789添加v直接領(lǐng)
環(huán)境搭建
完成本篇Codelab我們首先要完成開發(fā)環(huán)境的搭建,本示例以RK3568開發(fā)板為例,參照以下步驟進(jìn)行:
- [獲取OpenHarmony系統(tǒng)版本]:標(biāo)準(zhǔn)系統(tǒng)解決方案(二進(jìn)制)。以3.2 Release版本為例:
- 搭建燒錄環(huán)境。
- [完成DevEco Device Tool的安裝]
- [完成RK3568開發(fā)板的燒錄](méi)
- 搭建開發(fā)環(huán)境。
- 開始前請(qǐng)參考[工具準(zhǔn)備],完成DevEco Studio的安裝和開發(fā)環(huán)境配置。
- 開發(fā)環(huán)境配置完成后,請(qǐng)參考[使用工程向?qū)創(chuàng)建工程(模板選擇“Empty Ability”)。
- 工程創(chuàng)建完成后,選擇使用[真機(jī)進(jìn)行調(diào)測(cè)]。
代碼結(jié)構(gòu)解讀
本篇Codelab只對(duì)核心代碼進(jìn)行講解,對(duì)于完整代碼,我們會(huì)在gitee中提供。
使用Native C++模板創(chuàng)建項(xiàng)目會(huì)自動(dòng)生成cpp文件夾、types文件夾、CMakeList.txt文件,開發(fā)者可以根據(jù)實(shí)際情況自行添加修改其他文件及文件夾。
├──entry/src/main
│ ├──common
│ │ └──CommonContants.ets // 常量定義文件
│ ├──cpp // C++代碼區(qū)
│ │ ├──CMakeLists.txt // CMake編譯配置文件
│ │ ├──hello.cpp // C++源代碼
│ │ └──types // 接口存放文件夾
│ │ └──libhello
│ │ ├──index.d.ts // 接口文件
│ │ └──oh-package.json5 // 接口注冊(cè)配置文件
│ └──ets // 代碼區(qū)
│ ├──entryability
│ │ └──EntryAbility.ts // 程序入口類
│ └──pages
│ └──Index.ets // 主界面
└──entry/src/main/resources // 資源文件目錄
架構(gòu)組成
應(yīng)用架構(gòu)
應(yīng)用架構(gòu)可以分為三部分:C++、ArkTS、工具鏈。
- C++:包含各種文件的引用、C++或者C代碼、Native項(xiàng)目必需的配置文件等。
- ArkTS:包含界面UI、自身方法、調(diào)用引用包的方法等。
- 工具鏈:包含CMake編譯工具在內(nèi)的系列工具。
使用ArkTS調(diào)用C++方法的過(guò)程中,需要使用到NAPI、CMake等工具來(lái)做中間轉(zhuǎn)換,整個(gè)架構(gòu)及其關(guān)聯(lián)關(guān)系參考示意圖。
示意圖中,hello.cpp文件實(shí)現(xiàn)C++方法,并通過(guò)NAPI將C++方法與ArkTS方法關(guān)聯(lián)。
C++代碼通過(guò)CMake編譯工具編譯成動(dòng)態(tài)鏈接庫(kù)so文件,使用index.d.ts文件對(duì)外提供接口。ArkTS引入so文件后調(diào)用其中的接口。
編譯架構(gòu)
ArkTS與C++方法的調(diào)用、編譯流程參考示意圖。圖中C++代碼通過(guò)CMake編譯生成so文件后可以直接被ArkTS側(cè)引入,最終通過(guò)hvigor編譯成可執(zhí)行的hap包。
Native項(xiàng)目開發(fā)流程
Native側(cè)操作詳解
配置模塊描述信息,設(shè)置Init方法為napi_module的入口方法。 attribute ((constructor))修飾的方法由系統(tǒng)自動(dòng)調(diào)用,使用NAPI接口napi_module_register()傳入模塊描述信息進(jìn)行模塊注冊(cè)。Native C++模板創(chuàng)建項(xiàng)目會(huì)自動(dòng)生成此結(jié)代碼,開發(fā)者可根據(jù)實(shí)際情況修改其中內(nèi)容。
// hello.cpp static napi_module demoModule = { nm_version = 1, nm_flags = 0, nm_filename = nullptr, nm_register_func = Init, // napi_module入口方法 nm_modname = "hello", // napi_module模塊名 nm_priv = ((void *)0), reserved = { 0 } }; extern "C" __attribute__((constructor)) void RegisterModule(void) { napi_module_register(&demoModule); }
Init方法為Native C++模板生成的結(jié)構(gòu),開發(fā)者可根據(jù)實(shí)際情況修改其中內(nèi)容。在napi_property_descriptor desc[]中,我們需要將編寫的MyHypot方法與對(duì)外提供的接口myHypot接口進(jìn)行關(guān)聯(lián),其他參數(shù)使用示例默認(rèn)值填寫。使用NAPI接口napi_define_properties構(gòu)建包含方法對(duì)應(yīng)列表的返回值。
// hello.cpp static napi_value Init(napi_env env, napi_value exports) { if ((nullptr == env) || (nullptr == exports)) { OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "Init", "env or exports is null"); return exports; } napi_property_descriptor desc[] = { { "myHypot", nullptr, MyHypot, nullptr, nullptr, nullptr, napi_default, nullptr } }; if (napi_ok != napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc)) { OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "Init", "napi_define_properties failed"); return nullptr; } return exports; }
本例中使用C標(biāo)準(zhǔn)庫(kù)的hypot方法進(jìn)行計(jì)算。引入C標(biāo)準(zhǔn)庫(kù)頭文件math.h,使用double類型解析傳入的參數(shù)后,調(diào)用C標(biāo)準(zhǔn)庫(kù)方法hypot計(jì)算兩數(shù)平方的和后計(jì)算平方根。使用NAPI接口napi_create_double將結(jié)果轉(zhuǎn)化為napi_value類型的變量并返回。
// hello.cpp #include < hilog/log.h > #include "napi/native_api.h" #include "math.h" static napi_value MyHypot(napi_env env, napi_callback_info info) { if ((nullptr == env) || (nullptr == info)) { OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "MyHypot", "env or exports is null"); return nullptr; } // 參數(shù)數(shù)量 size_t argc = PARAMETER_COUNT; // 定義參數(shù)數(shù)組 napi_value args[PARAMETER_COUNT] = { nullptr }; // 獲取傳入的參數(shù)并放入?yún)?shù)數(shù)組中 if (napi_ok != napi_get_cb_info(env, info, &argc, args, nullptr, nullptr)) { OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "MyHypot", "api_get_cb_info failed"); return nullptr; } // 將傳入的參數(shù)轉(zhuǎn)化為double類型 double valueX = 0.0; double valueY = 0.0; if (napi_ok != napi_get_value_double(env, args[0], &valueX) || napi_ok != napi_get_value_double(env, args[1], &valueY)) { OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "MyHypot", "napi_get_value_double failed"); return nullptr; } // 調(diào)用C標(biāo)準(zhǔn)庫(kù)的hypot接口進(jìn)行計(jì)算 double result = hypot(valueX, valueY); // 創(chuàng)建返回結(jié)果并返回 napi_value napiResult; if (napi_ok != napi_create_double(env, result, &napiResult)) { OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "MyHypot", "napi_create_double failed"); return nullptr; } return napiResult; }
添加接口文件以及接口配置文件。接口文件index.d.ts用于對(duì)外提供方法說(shuō)明。接口配置文件oh-package.json5文件中將index.d.ts與CMake編譯的so文件關(guān)聯(lián)起來(lái)。模塊級(jí)目錄下oh-package.json5文件添加so文件依賴。
// index.d.ts export const myHypot: (a: number, b: number) = > number;
// oh-package.json5 { "name": "libhello.so", "types": "./index.d.ts" } // entry/oh-package.json5 { "devDependencies": { "@types/libhello.so": "file:./src/main/cpp/types/libhello" } }
在CMakeLists.txt文件中配置CMake編譯參數(shù)。配置需要添加的hello.cpp文件,編譯后的so文件名為libhello.so。CMakeLists.txt是CMake編譯的配置文件,里面的大部分內(nèi)容無(wú)需修改,project、add_library方法中的內(nèi)容可以根據(jù)實(shí)際情況修改。
# CMakeLists.txt # 聲明使用 CMAKE 的最小版本號(hào) cmake_minimum_required(VERSION 3.4.1) # 配置項(xiàng)目信息 project(NativeTemplateDemo) # set命令,格式為set(key value),表示設(shè)置key的值為value set(NATIVERENDER_ROOT_PATH ${CMAKE_CURRENT_SOURCE_DIR}) # 設(shè)置頭文件的搜索目錄 include_directories( ${NATIVERENDER_ROOT_PATH} ${NATIVERENDER_ROOT_PATH}/include ) # 添加日志庫(kù) find_library( # Sets the name of the path variable. hilog-lib # Specifies the name of the NDK library that # you want CMake to locate. hilog_ndk.z ) # 添加名為hello的庫(kù),庫(kù)文件名為libhello.so add_library(hello SHARED hello.cpp) # 添加構(gòu)建需要鏈接的庫(kù) target_link_libraries(hello PUBLIC ${hilog-lib} libace_napi.z.so libc++.a)
說(shuō)明:
- CMAKE_CURRENT_SOURCE_DIR:CMakeList.txt文件所在的目錄。
- add_library:添加本地的cpp文件,多cpp文件使用空格或換行間隔。
- target_link_libraries:添加需要鏈接的庫(kù),本篇Codelab使用C標(biāo)準(zhǔn)庫(kù)hypot方法,此處鏈接libc++.a庫(kù)文件。
ArkTS調(diào)用C++方法
Index.ets文件使用import語(yǔ)句導(dǎo)入CMake編譯出的so文件。Button組件添加點(diǎn)擊事件,點(diǎn)擊按鈕觸發(fā)點(diǎn)擊事件時(shí),調(diào)用libhello.so對(duì)外提供的myHypot方法,執(zhí)行計(jì)算并返回計(jì)算結(jié)果。依據(jù)結(jié)果值進(jìn)行格式化,顯示科學(xué)計(jì)數(shù)法或保留指定位小數(shù)。
// Index.ets
import libHello from 'libhello.so';
@Entry
@Component
struct Index {
...
build() {
...
Button($r('app.string.submit_button'))
.onClick(() = > {
let resultTemp = libHello.myHypot(this.numX, this.numY);
if (resultTemp > CommonContants.MAX_RESULT) {
this.result = resultTemp.toExponential(CommonContants.EXPONENTIAL_COUNT);
} else {
this.result = resultTemp.toFixed(CommonContants.FIXED_COUNT);
}
})
}
}
界面設(shè)計(jì)
界面由標(biāo)題、文本說(shuō)明、計(jì)算結(jié)果展示、輸入框、按鈕組成。Index.ets文件完成界面實(shí)現(xiàn),使用Column及Row容器組件進(jìn)行布局。
// Index.ets
@Entry
@Component
struct NativeTemplate {
...
build() {
Column() {
...
Column() {
...
Row() {
...
TextInput({ controller: this.textInputControllerX })
.type(InputType.Number)
}
.height($r('app.float.tips_num_height'))
.width(CommonContants.FULL_PARENT)
Row() {
...
TextInput({ controller: this.textInputControllerY })
.type(InputType.Number)
.onChange(value = > {
this.numY = parseFloat(value);
})
}
.height($r('app.float.tips_num_height'))
.width(CommonContants.FULL_PARENT)
}
Row() {
Button($r('app.string.submit_button'))
.height(CommonContants.FULL_PARENT)
.width($r('app.float.button_width'))
}
.height($r('app.float.button_height'))
.width(CommonContants.FULL_PARENT)
}
.width(CommonContants.FULL_PARENT)
.height(CommonContants.FULL_PARENT)
}
}
審核編輯 黃宇
-
C++
+關(guān)注
關(guān)注
22文章
2116瀏覽量
74627 -
OpenHarmony
+關(guān)注
關(guān)注
26文章
3805瀏覽量
17945 -
鴻蒙OS
+關(guān)注
關(guān)注
0文章
190瀏覽量
4841
發(fā)布評(píng)論請(qǐng)先 登錄
基于OpenHarmony開發(fā)板上測(cè)試Native C++應(yīng)用開發(fā)
【軟通動(dòng)力鴻湖萬(wàn)聯(lián)揚(yáng)帆系列“競(jìng)”開發(fā)板試用體驗(yàn)】Native C++應(yīng)用Demo示例(eTS)

鴻蒙next開發(fā)-OpenHarmony的NDK開發(fā)

請(qǐng)問(wèn)鴻蒙如何進(jìn)行native開發(fā)?
請(qǐng)問(wèn)鴻蒙系統(tǒng)是否支持native側(cè)opengles渲染引擎開發(fā)?
【軟通動(dòng)力鴻湖萬(wàn)聯(lián)揚(yáng)帆系列“競(jìng)”開發(fā)板試用體驗(yàn)】試用測(cè)評(píng)報(bào)告五 –開源鴻蒙C/C++軟件開發(fā)
如何使用DevEco Studio創(chuàng)建Native C++應(yīng)用
ARM與C/OS-Ⅱ嵌入式系統(tǒng)設(shè)計(jì)與實(shí)例開發(fā)
使用React Native構(gòu)建OS X桌面應(yīng)用

【軟通動(dòng)力鴻湖萬(wàn)聯(lián)揚(yáng)帆系列“競(jìng)”開發(fā)板試用體驗(yàn)】試用測(cè)評(píng)報(bào)告五 –開源鴻蒙C/C++軟件開發(fā)

如何使用DevEco Studio創(chuàng)建Native C++應(yīng)用
用OpenVINO? C++ API編寫YOLOv8-Seg實(shí)例分割模型推理程序

鴻蒙開發(fā)用什么語(yǔ)言?

評(píng)論