Appearance
ArkTS 与 C++ 交互(NAPI)
理解 NAPI(Node-API)在鸿蒙中的应用,如何通过 C++ 扩展 ArkTS 能力,以及 .so 库的集成方式。
1. NAPI 概述
NAPI(Node-API,原名 NAN) 是华为在 ArkTS 中提供的 C++ 桥接机制,允许 ArkTS 代码调用 C++ 编写的原生库(.so),实现底层能力扩展。
核心用途
- 高性能计算:加密、图像处理、音视频编解码
- 硬件驱动:传感器、蓝牙、串口通信
- 复用已有 C++ 库:开源库直接调用
- 系统级能力:绕过 ArkTS 限制的能力
架构
ArkTS 应用层
↓ (NAPI 桥接)
C++ 原生层 (.so)
↓
系统底层 (内核/硬件)2. C++ 端:导出接口
2.1 基本导出
cpp
// native/my_module.cpp
#include <napi/native_api.h>
// 要被 ArkTS 调用的 C++ 函数
int add(int a, int b) {
return a + b;
}
// NAPI 导出函数
static napi_value Add(napi_env env, napi_callback_info info) {
// 1. 获取参数
size_t argc = 2;
napi_value args[2];
napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
int64_t a, b;
napi_get_value_int64(env, args[0], &a);
napi_get_value_int64(env, args[1], &b);
// 2. 调用 C++ 函数
int result = add(a, b);
// 3. 返回结果
napi_value result_value;
napi_create_int64(env, result, &result_value);
return result_value;
}
// 模块导出
static napi_value Init(napi_env env, napi_value exports) {
napi_property_descriptor props[] = {
{"add", nullptr, Add, nullptr, nullptr, nullptr, napi_default, nullptr}
};
napi_define_properties(env, exports, 1, props);
return exports;
}
NAPI_MODULE(my_module, Init)3. ArkTS 端:调用 C++ 接口
3.1 加载 .so 库
typescript
// 方式1:直接加载(推荐)
import { add } from 'libmy_module.so'
// 方式2:动态加载
const lib = require('libmy_module.so')
const add = lib.add3.2 使用 C++ 函数
typescript
import { add, multiply, sqrt } from 'libmy_module.so'
// 直接使用
let sum = add(10, 20) // 30
let product = multiply(5, 6) // 30
let root = sqrt(144) // 124. napi_ref 机制
4.1 什么是 napi_ref?
napi_ref 是 C++ 侧对 ArkTS 对象的强引用,防止对象被 GC(垃圾回收)回收。
cpp
// C++ 侧保存对 ArkTS 对象的引用
napi_ref callbackRef;
static void SaveCallback(napi_env env, napi_value callback) {
napi_create_reference(env, callback, 1, &callbackRef); // 1 = 强引用
}
static void InvokeCallback(napi_env env) {
napi_value callback;
napi_get_reference_value(env, callbackRef, &callback);
napi_call_function(env, nullptr, callback, 0, nullptr, nullptr);
// 使用完后释放
napi_delete_reference(env, callbackRef);
}4.2 napi_ref 的使用场景
| 场景 | 是否需要 napi_ref |
|---|---|
| 保存回调函数供后续调用 | ✅ 需要,防止 GC |
| 临时参数传递 | ❌ 不需要 |
| 异步操作结果回调 | ✅ 需要 |
| 事件监听回调 | ✅ 需要 |
5. NAPI 数据类型映射
| ArkTS 类型 | NAPI C++ 类型 | 获取函数 |
|---|---|---|
| number | napi_number | napi_get\_value\_int64 |
| string | napi_string | napi\_get\_value\_string |
| boolean | napi_boolean | napi\_get\_value\_boolean |
| object | napi_object | napi\_get\_property_names |
| function | napi_function | napi\_get\_cb\_info |
| null/undefined | napi_null/napi_undefined | napi\_get\_null/undefined |
| bigint | napi_bigint | napi\_get\_value\_big\_int64 |
6. 实战示例:加密模块
6.1 C++ 端实现
cpp
#include <napi/native_api.h>
#include <openssl/sha.h>
static napi_value Sha256(napi_env env, napi_callback_info info) {
size_t argc = 1;
napi_value args[1];
napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
size_t dataLen;
char* data;
napi_get_value_string_utf8(env, args[0], nullptr, 0, &dataLen);
data = new char[dataLen + 1];
napi_get_value_string_utf8(env, args[0], data, dataLen + 1, &dataLen);
unsigned char hash[SHA256_DIGEST_LENGTH];
SHA256((unsigned char*)data, dataLen, hash);
delete[] data;
// 返回 hex 字符串
char hex[SHA256_DIGEST_LENGTH * 2 + 1];
for (int i = 0; i < SHA256_DIGEST_LENGTH; i++) {
sprintf(&hex[i * 2], "%02x", hash[i]);
}
napi_value result;
napi_create_string_utf8(env, hex, NAPI_AUTO_LENGTH, &result);
return result;
}
static napi_value Init(napi_env env, napi_value exports) {
napi_property_descriptor props[] = {
{"sha256", nullptr, Sha256, nullptr, nullptr, nullptr, napi_default, nullptr}
};
napi_define_properties(env, exports, 1, props);
return exports;
}
NAPI_MODULE(crypto_module, Init)6.2 ArkTS 端使用
typescript
import { sha256 } from 'libcrypto_module.so'
// 加密敏感数据
const password = 'mySecretPassword'
const hash = sha256(password)
console.log('加密后:', hash) // e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b8557. 构建与集成
7.1 build-profile.json5 配置
json5
{
"module": {
"ndk": {
"cppFlags": "-std=c++17",
"libPaths": ["src/main/cpp/libs"]
},
"externalNativeOptions": {
"path": "src/main/cpp/CMakeLists.txt",
"arguments": "",
"cppFlags": "",
"abiFilters": ["arm64-v8a", "x86_64"]
}
}
}7.2 CMakeLists.txt
cmake
cmake_minimum_required(VERSION 3.13)
project(MyNativeModule)
add_library(my_module SHARED
src/main/cpp/native/my_module.cpp
)
find_library(
napi_lib
native
)
target_link_libraries(my_module PUBLIC ${napi_lib})8. 面试高频考点
Q1: NAPI 的作用是什么?
回答:NAPI(Node-API)是 ArkTS 与 C++ 之间的桥接机制,允许 ArkTS 调用 C++ 编写的原生库,实现高性能计算、硬件驱动和已有 C++ 库复用。
Q2: napi_ref 的作用?
回答:napi_ref 是 C++ 侧对 ArkTS 对象的强引用,防止对象被 GC 回收。主要用于保存回调函数供异步操作后续调用。
Q3: NAPI 相比 JNI 有什么区别?
回答:NAPI 是鸿蒙平台专用的 API,更轻量、更高效;JNI 是 Android 平台的概念。两者原理类似,都是 Java/C++ 桥接。
🐱 小猫提示:NAPI 是高级开发的加分项。面试中不需要写 C++ 代码,但要理解"桥接机制"和"napi_ref 防 GC"这两个核心概念。