淺談OpenHarmony的NDK開(kāi)發(fā)
背景
Native API(NDK)入門
名詞概念
Native API構(gòu)成介紹
Native API目錄結(jié)構(gòu)
目錄 | 功能說(shuō)明 |
build | 應(yīng)用中編譯動(dòng)態(tài)庫(kù)的toolchain cmake腳本;這個(gè)目錄下ohos.toolchain.cmake文件定義了給OHOS交叉編譯選項(xiàng) |
build-tools | 放置編譯構(gòu)建的工具,如cmake |
docs | Native API接口參考文檔,通過(guò)doxgen從頭文件中提取出來(lái) |
llvm | 支持OHOS ABI的llvm交叉編譯器 |
sysroot | 放置編譯鏈接的依賴文件目錄,包含頭文件,動(dòng)態(tài)庫(kù)等 |
寫(xiě)在最后Native API接口(4.0 Release)
Native API相關(guān)資料
- Native API參考,介紹各個(gè)API參考手冊(cè)。
- Native API中支持的標(biāo)準(zhǔn)庫(kù),介紹Native API支持的開(kāi)源標(biāo)準(zhǔn)庫(kù)。
- Native API開(kāi)發(fā)指南,結(jié)合具體的例子,場(chǎng)景介紹各類接口的使用。
- 如何在Cmake工程中使用NDK,介紹如何使用使用NDK開(kāi)發(fā)一個(gè)CMake工程。
- Node-API在應(yīng)用工程中的使用指導(dǎo), 如何使用Node-API接口。
簡(jiǎn)單應(yīng)用
如何開(kāi)發(fā)應(yīng)用?
- DevEco IDE創(chuàng)建工程選擇“Native C++”模板:
編譯運(yùn)行后,點(diǎn)擊helloworld打印輸出有:Test NAPI 2 + 3 = 5。
- ArkUI部分:
import hilog from '@ohos.hilog'; //導(dǎo)入hilog
import testNapi from 'libentry.so'; //導(dǎo)入nativeC++模塊
@Entry
@Component
struct Index {
@State message: string = 'Hello World';
build() {
Row() {
Column() {
Text(this.message)
.fontSize(50)
.fontWeight(FontWeight.Bold)
.onClick(() => {
//調(diào)用nativeC++代碼
hilog.info(0x0000, 'testTag', 'Test NAPI 2 + 3 = %{public}d', testNapi.add(2, 3));
})
}
.width('100%')
}
.height('100%')
}
}
- nativeC++部分由 CMake 和 C++代碼兩部分組成:
- CMake:
# the minimum version of CMake.
cmake_minimum_required(VERSION 3.4.1)
project(MyNDKApplication)
# 編譯路徑
set(NATIVERENDER_ROOT_PATH ${CMAKE_CURRENT_SOURCE_DIR})
# 編譯頭文件路徑
include_directories(${NATIVERENDER_ROOT_PATH}
${NATIVERENDER_ROOT_PATH}/include)
# 編譯對(duì)象entry是對(duì)應(yīng)用層可見(jiàn)的so,即import testNapi from 'libentry.so'
add_library(entry SHARED hello.cpp)
# 這是link命令,libace_napi 這個(gè)就是node-api需要用的so庫(kù);
target_link_libraries(entry PUBLIC libace_napi.z.so)
- C++:
#include "napi/native_api.h"
// 對(duì)外node-api方法,對(duì)應(yīng)testNapi.add(2, 3)
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;
}
// 模塊初始化方法,對(duì)應(yīng)的方法在這加入對(duì)外描述隊(duì)列
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
// 模塊聲明,import時(shí)候調(diào)用
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 },
};
// 模塊入口注冊(cè)
extern "C" __attribute__((constructor)) void RegisterEntryModule(void)
{
napi_module_register(&demoModule);
}
如何使用系統(tǒng)NDK?
上面例子運(yùn)行起來(lái)后,c++部分是沒(méi)有打印信息的,若想看到對(duì)應(yīng)的打印信息,則需要調(diào)用hilog進(jìn)行輸出,修改如下:
- cmake修改:
# the minimum version of CMake.
cmake_minimum_required(VERSION 3.4.1)
project(MyNDKApplication)
set(NATIVERENDER_ROOT_PATH ${CMAKE_CURRENT_SOURCE_DIR})
include_directories(${NATIVERENDER_ROOT_PATH}
${NATIVERENDER_ROOT_PATH}/include)
# 增加hiloglib庫(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
)
add_library(entry SHARED hello.cpp)
# 增加hiloglib庫(kù)連接
target_link_libraries(entry PUBLIC ${hilog-lib} libace_napi.z.so)
- c++文件修改:
// 增加hilog頭文件
#include <hilog/log.h>
#include "napi/native_api.h"
static napi_value Add(napi_env env, napi_callback_info info)
{
// 增加打印輸出
const unsigned int LOG_PRINT_DOMAIN = 0xFF00;
OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "Init", "Init begins");
size_t requireArgc = 2;
size_t argc = 2;
napi_value args[2] = {nullptr};
...
- 輸出:
08-07 05:40:25.079 15167-15167 A0ff00/Init com.example.myndkapplication I Init begins
08-07 05:40:25.079 15167-15167 A00000/testTag com.example.myndkapplication I Test NAPI 2 + 3 = 5
具體原理是什么?
PC端OHOS SDK里包括了native對(duì)應(yīng)的庫(kù)文件和頭文件。
OHOS源碼可以編譯出帶NDK的FullSDK,也可以從CI網(wǎng)址下載。
# Generate NDK library from NDK description file.
#
# Variables:
# ndk_description_file:
# min_compact_version: string specifies the minimal compactible version of NDK.
# set to major_version in default.
#
template("ohos_ndk_library") {
forward_variables_from(invoker, [ "testonly" ])
assert(defined(invoker.ndk_description_file),
"ndk description file is necessary ")
...
// 在GN里用ohos_ndk_library生成ndk庫(kù)和頭文件,如
ohos_ndk_library("libhilog_ndk") {
output_name = "hilog_ndk"
ndk_description_file = "./libhilog.ndk.json"
min_compact_version = "1"
system_capability = "SystemCapability.HiviewDFX.HiLog"
}
ohos_ndk_headers("hilog_header") {
dest_dir = "$ndk_headers_out_dir/hilog"
sources = [ "./include/hilog/log.h" ]
}
// ndk_description_file 對(duì)應(yīng)的 libhilog.ndk.json 文件里聲明了導(dǎo)出的接口函數(shù)
[
{
"name": "OH_LOG_Print"
},
{
"name": "OH_LOG_IsLoggable"
}
]
// ohos 編譯fullsdk的命令:./build.sh --product-name ohos-sdk
ohos的ci網(wǎng)址如下:https://ci.openharmony.cn/workbench/cicd/dailybuild/dailylist。
使用建議
建議使用Native API的場(chǎng)景
主要有如下一些
- 應(yīng)用性能敏感代碼,比如游戲,物理模擬等計(jì)算密集型場(chǎng)景。
- 需要復(fù)用已有的C或C++庫(kù)。
- 需要針對(duì)CPU特性進(jìn)行專項(xiàng)定制的庫(kù),如neon加速。
不建議使用Native API的場(chǎng)景
- 寫(xiě)一個(gè)純native的的OHOS應(yīng)用。
- 希望在盡可能多的OHOS設(shè)備上保持兼容的應(yīng)用。
維測(cè)能力
- OHOS官方提供lldb remote方式代碼調(diào)試,詳細(xì)參看lldb參考手冊(cè)。
- musl庫(kù)的log維測(cè)能力,請(qǐng)參看libc庫(kù)維測(cè)章節(jié)。
總結(jié)
- NDK方式是應(yīng)用層直接調(diào)用底層庫(kù)或者三方庫(kù)目前看最常規(guī)的方式;
- 4.0(API10)有ndk 46個(gè),3.2(API9)有ndk 28個(gè),實(shí)質(zhì)代碼里有更多的ndk,RK的原因沒(méi)有編出更多,比如sensor部分就沒(méi)有編譯出來(lái)。
- 劃重點(diǎn),NDK里有兩種api:node-api,用于arkts和c++調(diào)用和傳遞數(shù)據(jù);c/c++ api,可以把動(dòng)態(tài)庫(kù)打包成應(yīng)用側(cè)c++直接調(diào)用的接口。
- 社區(qū)文檔:https://gitee.com/openharmony/docs/tree/master/zh-cn/application-dev/reference。