鸿蒙ArkTS 与 Native 交互场景分类总结与关键实现

8 阅读3分钟

Native侧跨HAR/HSP模块接口调用-程序包结构-应用框架 - 华为HarmonyOS开发者

ArkTS 与 Native 交互场景分类总结与关键实现

一、场景分类总结

场景类型调用方向适用场景技术特点
ArkTS → NativeHAP ArkTS → 同模块 Native高性能计算、硬件操作使用 Node-API 直接调用
Native → NativeHAP Native → HAR/HSP Native跨模块复用底层能力头文件导出 + SO 链接
Native → ArkTSHAR/HSP Native → 同模块 ArkTSNative 回调业务逻辑napi_load_module 动态加载

二、关键代码流程详解

场景1:ArkTS 调用同模块 Native

调用链​:HAP ArkTS → HAP Native

关键流程​:

// ArkTS 侧 (index.ets)
import napi from 'libentry.so'

Button('调用Native方法').onClick(() => {
  const result = napi.add(2, 3) // 调用Native方法
})
// 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

关键流程​:

// 被调用方 (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;
}
// 调用方 (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

关键流程​:

// ArkTS 侧 (Util.ets)
export function add(a: number, b: number): number {
  return a + b;
}
// 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) 配置

# 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})
// build-profile.json5 (关键导出配置)
{
  "buildOption": {
    "nativeLib": {
      "headerPath": "./src/main/cpp" // 暴露头文件
    }
  }
}

2. 调用方 (HAP) 配置

# 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)
// oh-package.json5 (模块依赖声明)
{
  "dependencies": {
    "native_har": "file:../native_har_module"
  }
}

四、特殊场景处理技巧

  1. 环境传递​(Native 调用 ArkTS 前置条件)
// HAP Native 初始化时传递环境
EXTERN_C_START
static napi_value Init(napi_env env, napi_value exports) {
  setHarEnv(env); // 将env传递给HAR模块
  return exports;
}
EXTERN_C_END
  1. HSP/HAR 路径差异处理
// HSP模块使用自身模块名
napi_load_module_with_info(env,
    "hsp_module/src/main/ets/MainPage",  // 实际模块名
    "com.example.app/hsp_entry",         // 包名/模块名
    &module);
  1. 解决模块加载失败
// build-profile.json5 添加运行时包声明
"buildOption": {
  "arkOptions": {
    "runtimeOnly": {
      "packages": ["native_har"] // 声明依赖包
    }
  }
}

五、最佳实践建议

  1. 头文件管理​:

    • 使用 #pragma once防止重复包含
    • 为跨模块接口创建专用头文件目录
  2. 符号导出控制​:

    • 使用 __attribute__((visibility("default")))显式导出函数
    __attribute__((visibility("default"))) 
    double harNativeAdd(double a, double b);
    
  3. 错误处理增强​:

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;
}
  1. 性能优化​:

    • 缓存频繁调用的 ArkTS 函数引用
    • 避免在循环中频繁加载模块

关键点总结:跨模块通信的核心在于头文件导出SO链接配置环境传递。对于Native调用ArkTS,需特别注意模块路径的正确性和运行环境的传递。