如何使用DevEco Studio建立Native C++應用

OpenHarmony開發者發表於2023-02-22

簡介

本篇主要介紹如何使用DevEco Studio for OpenAtom OpenHarmony (以下簡稱“OpenHarmony”)建立一個Native C++應用。應用採用“Native C++”模板,實現了透過Node-API呼叫C標準庫的功能。本示例透過呼叫C標準庫介面來演示呼叫過程,具體介面是C標準庫的計算兩個給定數和,並將結果返回到頁面展示。透過這個應用我們可以掌握OpenHarmony系統的ArkTS/JS與C/C++混合開發。ArkTS/JS與C/C++ 混合開發是OpenHarmony系統中的一套原生模組擴充套件開發框架,它基於Node.js N-API規範開發,為開發者提供了ArkTS/JS與C/C++模組之間相互呼叫的互動能力。這套機制對於OpenHarmony系統開發的價值有兩方面:
1、OpenHarmony系統可以將框架層豐富的模組功能透過js介面開放給上層應用使用。
2、應用開發者也可以選擇將一些對效能、底層系統呼叫有要求的核心功能用C/C++封裝實現,再透過js介面使用,提高應用本身的執行效率。

效果圖

實現效果如下圖所示:

圖片

透過ArkTS編寫介面,根據介面展示點選輸入框輸入兩個數,再點選計算按鈕呼叫介面,將資料傳入到C++端,C++端計算後再作為返回值到ArkTS端。

環境搭建

我們首先要完成應用開發環境的搭建,本示例執行RK3568開發板上。

1、 搭建應用開發環境
1.1、開始前請參考應用開發快速上手鍊接,完成DevEco Studio的安裝和開發環境配置:參考連結

1.2、開發環境配置完成後,建立工程(模板選擇“Native C++”),選擇JS或者eTS語言開發。

圖片

2、應用調測
工程建立完成後,選擇使用真機進行調測。
2.1、將搭載OpenHarmony標準系統的開發板與電腦連線。
2.2、點選File> Project Structure... > Project>SigningConfigs介面勾選“Automatically generate signature”,等待自動簽名完成即可,最後點選“OK”。如下圖所示:

圖片

在編輯視窗右上角的工具欄,點選"
圖片
"按鈕執行。

原始碼結構

程式碼結構分析,整個工程的程式碼結構如下:

圖片

檔案說明如下:

├── cpp:// C++程式碼區
│   ├── types:// 介面存放資料夾
│   │   └── libadd              
│   │       ├── index.d.ts       // 介面檔案
│   │       └── package.json // 介面註冊配置檔案
│   ├── CmakeList.text     // Cmake打包配置檔案
│   └── add.cpp                // C++原始碼
└── ets                               // ets程式碼區
    └── Application
    │   └── AbilityStage.ts  // Hap包執行時類
    ├── MainAbility
    │   └── MainAbility.ts   //對Ability生命週期管理
    └── pages
        └── index.ets            // 主頁面

C++端方法實現

C++端方法原始碼是工程的entry/src/main/cpp/add.cpp檔案。

1、 註冊模組
先定義一個模組,對應結構體為napi_module,模組定義好後,呼叫NAPI提供的模組註冊函式napi_module_register(napi_module* mod)註冊到系統中;參考如下示例,nm_modname可以根據實際情況修改。

static napi_module demoModule = {
    .nm_version =1,
    .nm_flags = 0,
    .nm_filename = nullptr,
    .nm_register_func = Init,
    .nm_modname = "libadd",
    .nm_priv = ((void*)0),
    .reserved = { 0 },
};

extern "C" __attribute__((constructor)) void RegisterHelloModule(void)
{
    napi_module_register(&demoModule);
}

2、 介面定義
介面定義是固定寫法,在napi_property_descriptor desc[]中,我們需要將編寫的“hyPotC”方法(從左至右第三個引數)與對應暴露的介面“hyPot”介面(從左至右第一個引數)進行關聯,其他參考示例預設填寫即可。如下所示,其中Add對應的是Native C++的介面,其應用端的介面對應為add,NAPI透過napi_define_properties介面將napi_property_descriptor結構體中的2個介面繫結在一起,並透過exports變數對外匯出,使應用層可以呼叫add方法。

EXTERN_C_START
static napi_value Init(napi_env env, napi_value exports)
{
    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

3、 介面實現

#include "napi/native_api.h"
static napi_value Add(napi_env env, napi_callback_info info)
{
    size_t requireArgc = 2;
    size_t argc = 2;
    napi_value args[2] = {nullptr};
    napi_get_cb_info(env, info, &argc, args , nullptr, nullptr);
    napi_valuetype valuetype0;
    napi_typeof(env, args[0], &valuetype0);
    napi_valuetype valuetype1;
    napi_typeof(env, args[1], &valuetype1);
    double value0;
    napi_get_value_double(env, args[0], &value0);
    double value1;
    napi_get_value_double(env, args[1], &value1);
    napi_value sum;
    napi_create_double(env, value0 + value1, &sum);
    return sum;
}

4、 介面對外配置
4.1、修改index.d.ts用於對外提供方法、說明(名字可以更改,點選方法可以直接連結到index.d.ts)。

export const add: (a: number, b: number) => number;

4.2、在package.json檔案中將index.d.ts與cpp檔案關聯起來。

{
  "name": "libadd.so",
  "types": "./index.d.ts"
}

4.3、CMakeLists.txt配置CMake打包引數,CMakeLists.txt是CMake打包的配置檔案,裡面的大部分內容無需修改,project、add_library方法中的內容可以根據實際情況修改。

# the minimum version of CMake.
cmake_minimum_required(VERSION 3.4.1)
project(MyApplication)

set(NATIVERENDER_ROOT_PATH ${CMAKE_CURRENT_SOURCE_DIR})

include_directories(${NATIVERENDER_ROOT_PATH}
                    ${NATIVERENDER_ROOT_PATH}/include)

add_library(add SHARED add.cpp)
target_link_libraries(add PUBLIC libace_napi.z.so)

ArkTS端實現

介面整體規劃效果如下圖所示:

圖片

介面實現部分程式碼,具體請檢視原始碼(見參考連結原始碼路徑)。

@Entry
@Component
struct Index {
  ...
  build() {
    Row() {
      Column() {
      }
      .width('100%')
    }
    .height('100%')
  }
}

ArkTS呼叫C++方法流程

在ArkTS呼叫C++流程的過程中,需要使用到Node_API、Cmake等工具來做中間轉換,整個流程如下:

圖片

(1) add.cpp原始碼用來編寫C++程式碼,並透過index.d.ts檔案對外提供介面。
(2) C++程式碼透過Cmake打包工具打包成動態連結庫SO檔案。
(3) arkTs端index.ets原始碼透過引入SO包的方式去呼叫SO檔案中的介面,最終透過hivgor一起打包成可執行的xxx.hap包。

1、匯入SO包
在index.ets檔案中引入編譯好的SO包。

import libAdd from 'libadd.so'

2、新增點選事件
Button元件新增點選事件,呼叫libadd.so中的方法。

Button(this.buttonSubmit)
    .fontSize(40)
    .fontWeight(FontWeight.Bold)
    .margin({top:5})
    .height(100)
    .width(200)
    .onClick(() => {
        this.result = libAdd.add(this.num1,this.num2)
 })

3、hivgor打包
hivgor打包將SO檔案與eTS程式碼一起打包成hap包。

4、安裝hap包
點選"

圖片
"按鈕安裝hap包執行。

總結

透過本篇介紹,我們瞭解了C++程式碼如何與ArkTS實現關聯,ArkTS如何呼叫SO包中的介面等,同時也掌握了C++程式碼的具體編寫與打包流程。

參考連結

DevEco Studio安裝和開發環境配置https://gitee.com/openharmony...

原始碼路徑https://gitee.com/openharmony...

NAPI課程學習路徑https://gitee.com/openharmony...

圖片

相關文章