在 HarmonyOS 中如何使用 Native C++

环境

  • 设备: 支持HarmonyOS NEXT 的设备(真机/模拟器)

创建项目

新建一个项目,选择 [Native C++] 的模版

然后生成一个默认的工程

API 版本 : 5.0.1 (API 13)

分析项目

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import { hilog } from '@kit.PerformanceAnalysisKit';
import testNapi from 'libentry.so';

@Entry
@Component
struct Index {
@State message: string = 'Hello World';

build() {
Row() {
Column() {
Text(this.message)
.fontSize(50)
.fontWeight(FontWeight.Bold)
.onClick(() => {
hilog.info(0x0000, 'testTag', 'Test NAPI 2 + 3 = %{public}d', testNapi.add(2, 3));
})
}
.width('100%')
}
.height('100%')
}
}

分析这个默认工程,根据index.ets代码显示,是在Native下注册是add的计算方法,通过传入两个参数计算和,文中传入了 2 和 3,当点击界面上的Hello world 文本时调用计算方法,日志输出如下

1
12-19  55333-55333   A00000/com..../testTag  com.xw....lication  I     Test NAPI 2 + 3 = 5

点击16行,testNapi.add() 方法跳过去,在 index.d.ts 中定义了接口方法

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

这个 testNapi 又是通过 libentry.so 引入的

1
import testNapi from 'libentry.so';

CMakeLists 15行 我们可以链接库的地方

接着打开 cpp 目录下的 napi_init.cpp 文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
#include "napi/native_api.h"

static napi_value Add(napi_env env, napi_callback_info info)
{
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;

}

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

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 },
};

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

按照以上的使用流程,接下来实现一个类似的示例

修改项目

以下通过C API 获取设备信息 DeviceInfo

链接

CMakeList.txt

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# the minimum version of CMake.
cmake_minimum_required(VERSION 3.5.0)
project(HMBehavior)

set(NATIVERENDER_ROOT_PATH ${CMAKE_CURRENT_SOURCE_DIR})

if(DEFINED PACKAGE_FIND_FILE)
include(${PACKAGE_FIND_FILE})
endif()

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

add_library(entry SHARED napi_init.cpp)
target_link_libraries(entry PUBLIC libace_napi.z.so)
# 设备信息
target_link_libraries(entry PUBLIC libdeviceinfo_ndk.z.so)

实现

napi_init.cpp 里定义一个函数 GetDeviceInfo,实现具体设备信息获取的逻辑

导包

1
2
3
4
5
#include "napi/native_api.h"
#include "deviceinfo.h"
#include <cstdlib>
#include <cstring>
#include <string>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
/**
* 获取设备信息
* @param env
* @param
* @return
*/
static napi_value GetDeviceInfo(napi_env env, napi_callback_info) {

std::string deviceType = "设备类型: " + std::string(OH_GetDeviceType()) + "\n";
std::string manufacture = "设备制造商: " + std::string(OH_GetManufacture()) + "\n";
std::string brand = "设备设备品牌: " + std::string(OH_GetBrand()) + "\n";
std::string marketName = "外部产品系列: " + std::string(OH_GetMarketName()) + "\n";
std::string productSeries = "产品系列: " + std::string(OH_GetProductSeries()) + "\n";
std::string productModel = "认证型号: " + std::string(OH_GetProductModel()) + "\n";
std::string softwareModel = "内部软件子型号: " + std::string(OH_GetSoftwareModel()) + "\n";
std::string hardwareModel = "硬件版本号: " + std::string(OH_GetHardwareModel()) + "\n";
std::string bootloaderVersion = "Bootloader版本号: " + std::string(OH_GetBootloaderVersion()) + "\n";
std::string abiList = "应用二进制接口(Abi): " + std::string(OH_GetAbiList()) + "\n";
std::string securityPatchTag = "安全补丁级别: " + std::string(OH_GetSecurityPatchTag()) + "\n";
std::string displayVersion = "产品版本: " + std::string(OH_GetDisplayVersion()) + "\n";
std::string IncrementalVersion = "差异版本: " + std::string(OH_GetIncrementalVersion()) + "\n";
std::string OSReleaseType = "系统的发布类型: " + std::string(OH_GetOsReleaseType()) + "\n";
std::string OSFullName = "完整的系统版本名: " + std::string(OH_GetOSFullName()) + "\n";
std::string sdkApiVersion = "系统软件API版本: " + std::to_string(OH_GetSdkApiVersion()) + "\n";
std::string firstApiVersion = "首个版本系统软件API版本: " + std::to_string(OH_GetFirstApiVersion()) + "\n";
std::string versionId = "版本ID: " + std::string(OH_GetVersionId()) + "\n";
std::string buildType = "系统的构建类型: " + std::string(OH_GetBuildType()) + "\n";
std::string buildUser = "系统的构建用户: " + std::string(OH_GetBuildUser()) + "\n";
std::string buildHost = "系统的构建主机: " + std::string(OH_GetBuildHost()) + "\n";
std::string buildTime = "完整系统的构建时间: " + std::string(OH_GetBuildTime()) + "\n";
std::string buildRootHash = "系统的构建版本Hash: " + std::string(OH_GetBuildRootHash()) + "\n";
std::string distributionOSName = "ISV发行系统版本名称: " + std::string(OH_GetDistributionOSName()) + "\n";
std::string distributionOSVersion = "ISV发行版系统版本号: " + std::string(OH_GetDistributionOSVersion()) + "\n";
std::string distributionOSApiVersion ="ISV发行版系统api版本: " + std::to_string(OH_GetDistributionOSApiVersion()) + "\n";
std::string distributionOSReleaseType ="ISV发行版系统类型: " + std::string(OH_GetDistributionOSReleaseType()) + "\n";

// 获取每个属性的长度
size_t length1 = strlen(deviceType.c_str());
size_t length2 = strlen(manufacture.c_str());
size_t length3 = strlen(brand.c_str());
size_t length4 = strlen(marketName.c_str());
size_t length5 = strlen(productSeries.c_str());
size_t length6 = strlen(productModel.c_str());
size_t length7 = strlen(softwareModel.c_str());
size_t length8 = strlen(hardwareModel.c_str());
size_t length9 = strlen(bootloaderVersion.c_str());
size_t length10 = strlen(abiList.c_str());
size_t length11 = strlen(securityPatchTag.c_str());
size_t length12 = strlen(displayVersion.c_str());
size_t length13 = strlen(IncrementalVersion.c_str());
size_t length14 = strlen(OSReleaseType.c_str());
size_t length15 = strlen(OSFullName.c_str());
size_t length16 = strlen(sdkApiVersion.c_str());
size_t length17 = strlen(firstApiVersion.c_str());
size_t length18 = strlen(versionId.c_str());
size_t length19 = strlen(buildType.c_str());
size_t length20 = strlen(buildUser.c_str());
size_t length21 = strlen(buildHost.c_str());
size_t length22 = strlen(buildTime.c_str());
size_t length23 = strlen(buildRootHash.c_str());
size_t length24 = strlen(distributionOSName.c_str());
size_t length25 = strlen(distributionOSVersion.c_str());
size_t length26 = strlen(distributionOSApiVersion.c_str());
size_t length27 = strlen(distributionOSReleaseType.c_str());

// 计算拼接后的长度
size_t resultLength = length1 + length2 + length3 + length4 + length5 + length6 + length7 + length8 + length9 +
length10 + length11 + length12 + length13 + length14 + length15 + length16 + length17 +
length18 + length19 + length20 + length21 + length22 + length23 + length24 + length25 +
length26 + length27;

// 分配内存以存储拼接后的字符串
char *resultStr = (char *)malloc(resultLength + 1);
// 拼接字符串
strcpy(resultStr, deviceType.c_str());
strcat(resultStr, manufacture.c_str());
strcat(resultStr, brand.c_str());
strcat(resultStr, marketName.c_str());
strcat(resultStr, productSeries.c_str());
strcat(resultStr, productModel.c_str());
strcat(resultStr, softwareModel.c_str());
strcat(resultStr, hardwareModel.c_str());
strcat(resultStr, bootloaderVersion.c_str());
strcat(resultStr, abiList.c_str());
strcat(resultStr, securityPatchTag.c_str());
strcat(resultStr, displayVersion.c_str());
strcat(resultStr, IncrementalVersion.c_str());
strcat(resultStr, OSReleaseType.c_str());
strcat(resultStr, OSFullName.c_str());
strcat(resultStr, sdkApiVersion.c_str());
strcat(resultStr, firstApiVersion.c_str());
strcat(resultStr, versionId.c_str());
strcat(resultStr, buildType.c_str());
strcat(resultStr, buildUser.c_str());
strcat(resultStr, buildHost.c_str());
strcat(resultStr, buildTime.c_str());
strcat(resultStr, buildRootHash.c_str());
strcat(resultStr, distributionOSName.c_str());
strcat(resultStr, distributionOSVersion.c_str());
strcat(resultStr, distributionOSApiVersion.c_str());
strcat(resultStr, distributionOSReleaseType.c_str());

napi_value result;
napi_create_string_utf8(env, resultStr, resultLength, &result);
return result;
}

配置

1
2
3
4
5
6
7
8
9
10
EXTERN_C_START
static napi_value Init(napi_env env, napi_value exports) {

napi_property_descriptor desc[] = {
// 设备信息
{"getDeviceInfo", nullptr, GetDeviceInfo, nullptr, nullptr, nullptr, napi_default, nullptr}
};
napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
return exports;
}

定义模块

1
2
3
4
5
6
7
8
9
10
EXTERN_C_END
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},
};

注册模块

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

定义调用函数

index.d.ts

1
export const getDeviceInfo: () => string;

引入

1
import { getDeviceInfo } from 'libentry.so';

调用

1
2
val deviceinfo = getDeviceInfo();
console.error(deviceinfo);

运行项目

输出

1
12-19 11:08:10.384   21645-21645   A03D00/com.../JSAPP  com.xw....lication   E     设备类型: phone, 厂家:HUAWEI, 品牌:HUAWEI, 外部产品系列:HUAWEI Mate 60, 产品系列:BRA, 认证型号:BRA-AL00, 内部软件子型号:BRA-AL00, 硬件版本号:HL1FLSM, 硬件Profiledefault, Bootloader版本号:bootloader, 应用二进制接口(Abi)列表:arm64-v8a, 安全补丁级别:2024/11/01, 产品版本:BRA-AL00 5.0.0.110(SP6C00E107R4P22), 差异版本号:default, 系统的发布类型:Beta3, 系统版本:OpenHarmony-5.0.1.107(Beta3), Major版本号:5, Senior版本号:0, Feature版本号:1, Build版本号:107, 系统软件API版本:13, 首个版本系统软件API版本:1, 版本ID:phone/HUAWEI/HUAWEI/BRA/OpenHarmony-5.0.1.107(Beta3)/BRA-AL00/BRA-AL00/13/default/default, 构建类型:default, 构建用户:default, 构建主机:default, 构建时间:default, 构建版本Hashdefault, 发行版系统名称:, 发行版系统版本号:5.0.0, 发行版系统api版本:50001, 发行版系统api版本名称:5.0.1, 发行版系统类型:Beta3, 开发者匿名设备标识符(ODID): 2699128d-5975-8985-8af4-bb30ce52....

效果图

alt text