Native侧跨HAR/HSP模块接口调用-程序包结构-应用框架 - 华为HarmonyOS开发者
ArkTS 与 Native 交互场景分类总结与关键实现
一、场景分类总结
场景类型 | 调用方向 | 适用场景 | 技术特点 |
---|---|---|---|
ArkTS → Native | HAP ArkTS → 同模块 Native | 高性能计算、硬件操作 | 使用 Node-API 直接调用 |
Native → Native | HAP Native → HAR/HSP Native | 跨模块复用底层能力 | 头文件导出 + SO 链接 |
Native → ArkTS | HAR/HSP Native → 同模块 ArkTS | Native 回调业务逻辑 | napi_load_module 动态加载 |
二、关键代码流程详解
场景1:ArkTS 调用同模块 Native
调用链 :HAP ArkTS → HAP Native
关键流程:
javascript
// ArkTS 侧 (index.ets)
import napi from 'libentry.so'
Button('调用Native方法').onClick(() => {
const result = napi.add(2, 3) // 调用Native方法
})
scss
// Native 侧 (napi_init.cpp)
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);
// 2. 类型转换
double value0, value1;
napi_get_value_double(env, args[0], &value0);
napi_get_value_double(env, args[1], &value1);
// 3. 执行计算
double sum = value0 + value1;
// 4. 返回结果
napi_value result;
napi_create_double(env, sum, &result);
return result;
}
场景2:跨模块 Native 调用
调用链 :HAP Native → HAR/HSP Native
关键流程:
arduino
// 被调用方 (HAR/HSP模块)
// napi_har.h
#pragma once
double harNativeAdd(double a, double b);
// napi_har.cpp
double harNativeAdd(double a, double b) {
return a + b;
}
scss
// 调用方 (HAP模块)
#include "napi_har.h" // 包含被调用方头文件
static napi_value invokeHarNative(napi_env env, napi_callback_info info) {
// 直接调用跨模块函数
double result = harNativeAdd(2, 3);
napi_value sum;
napi_create_double(env, result, &sum);
return sum;
}
场景3:Native 调用 ArkTS
调用链 :HAR/HSP Native → 同模块 ArkTS
关键流程:
typescript
// ArkTS 侧 (Util.ets)
export function add(a: number, b: number): number {
return a + b;
}
arduino
// Native 侧 (napi_har.cpp)
napi_value harArkTSAdd(double a, double b) {
// 1. 加载ArkTS模块
napi_value module;
napi_load_module_with_info(env,
"static_module/src/main/ets/utils/Util", // 模块路径
"com.example.app/entry", // 包名/模块名
&module);
// 2. 获取函数引用
napi_value addFunc;
napi_get_named_property(env, module, "add", &addFunc);
// 3. 准备参数
napi_value argv[2];
napi_create_double(env, a, &argv[0]);
napi_create_double(env, b, &argv[1]);
// 4. 调用函数
napi_value result;
napi_call_function(env, module, addFunc, 2, argv, &result);
return result;
}
三、CMake 配置精要
1. 被调用方 (HAR/HSP) 配置
scss
# CMakeLists.txt (HAR/HSP模块)
add_library(native_har SHARED
napi_har.cpp
napi_init.cpp)
# 设置头文件搜索路径
target_include_directories(native_har PRIVATE
${CMAKE_CURRENT_SOURCE_DIR})
json
// build-profile.json5 (关键导出配置)
{
"buildOption": {
"nativeLib": {
"headerPath": "./src/main/cpp" // 暴露头文件
}
}
}
2. 调用方 (HAP) 配置
bash
# CMakeLists.txt (HAP模块)
add_library(entry SHARED napi_init.cpp)
# 关键:链接被调用方库
target_link_libraries(entry PUBLIC
native_har) # 被调用方模块名::库名
# 包含被调用方头文件
target_include_directories(entry PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}
path/to/har_module/headers)
json
// oh-package.json5 (模块依赖声明)
{
"dependencies": {
"native_har": "file:../native_har_module"
}
}
四、特殊场景处理技巧
- 环境传递(Native 调用 ArkTS 前置条件)
java
// HAP Native 初始化时传递环境
EXTERN_C_START
static napi_value Init(napi_env env, napi_value exports) {
setHarEnv(env); // 将env传递给HAR模块
return exports;
}
EXTERN_C_END
- HSP/HAR 路径差异处理
arduino
// HSP模块使用自身模块名
napi_load_module_with_info(env,
"hsp_module/src/main/ets/MainPage", // 实际模块名
"com.example.app/hsp_entry", // 包名/模块名
&module);
- 解决模块加载失败
json
// build-profile.json5 添加运行时包声明
"buildOption": {
"arkOptions": {
"runtimeOnly": {
"packages": ["native_har"] // 声明依赖包
}
}
}
五、最佳实践建议
-
头文件管理:
- 使用
#pragma once
防止重复包含 - 为跨模块接口创建专用头文件目录
- 使用
-
符号导出控制:
- 使用
__attribute__((visibility("default")))
显式导出函数
arduino__attribute__((visibility("default"))) double harNativeAdd(double a, double b);
- 使用
-
错误处理增强:
ini
napi_status status = napi_load_module_with_info(...);
if (status != napi_ok) {
napi_throw_error(env, "MODULE_LOAD_FAIL", "Failed to load ArkTS module");
return nullptr;
}
-
性能优化:
- 缓存频繁调用的 ArkTS 函数引用
- 避免在循环中频繁加载模块
关键点总结:跨模块通信的核心在于头文件导出 、SO链接配置 和环境传递。对于Native调用ArkTS,需特别注意模块路径的正确性和运行环境的传递。