当前位置: 首页 > news >正文

OpenHarmony 与 HarmonyOS 的 NAPI 开发实战对比:自上而下与自下而上的差异解析

一、 NAPI框架概述

NAPI(Native API)是鸿蒙生态中用于实现ArkTS/JS与C/C++代码互操作的核心框架。其概念源自Node.js,为了实现JavaScript脚本与C++库之间的相互调用,Node.js对V8引擎的API做了一层封装,称为NAPI。
OpenHarmony系统沿用了NAPI的接口定义形式,但每个接口的内部实现都进行了重写。这是因为NAPI接口的本质是帮助C++程序去跟JavaScript引擎交互,对于不同的引擎需要有不同的实现方式。当用户调用了NAPI接口(如 napi_create_int64()),在Node.js中它会访问V8引擎的API,而在OpenHarmony中,它访问的是ArkUI框架自己的JS引擎。
NAPI主要解决以下问题:

  1. 性能需求:对于CPU密集型、IO密集型或需要直接操作硬件的场景,C/C++实现通常比纯ArkTS/JS更高效。
  2. 代码复用:允许将现有的C/C++库(如音视频编解码、加密算法等)快速移植到鸿蒙平台。
  3. 系统级访问:提供对操作系统底层功能的访问能力,如GPIO控制、特定硬件驱动交互等。

二、 OpenHarmony与HarmonyOS NAPI开发的核心区别

虽然两者都使用NAPI框架,但其目标、开发流程和部署方式有本质区别。

特性OpenHarmony (系统级扩展)HarmonyOS (应用级模块)
目标扩展系统能力,为所有应用提供新的原生API。增强单个应用,封装应用私有的高性能逻辑。
开发环境需要完整的OpenHarmony源码和Linux编译环境。使用DevEco Studio,无需系统源码。
SDK依赖依赖并需要修改Full-SDK,将新接口打包进系统镜像。使用Public-SDK,模块随应用打包。
构建系统使用GNohos.build配置,参与系统编译。使用CMake配置,由DevEco Studio编译。
模块位置编译后.so文件位于/system/lib/module/目录,成为系统一部分。编译后.so文件打包在HAP内,位于应用私有目录。
ArkTS导入import myApi from '@ohos.myNewApi' (标准系统接口名)。import nativeModule from 'libentry.so' (直接指定so名)。
适用场景OEM厂商、系统开发者,为特定硬件或平台能力提供标准接口。应用开发者,优化应用内算法、复用现有C/C++库。

OpenHarmony的NAPI开发是一种“自下而上”的模式,开发者修改系统源码,增加一个新的子系统/组件,编译后生成包含新原生接口的系统固件和Full-SDK。应用开发者拿到这个新的SDK后,就能像使用系统官方API一样使用新增的接口。而HarmonyOS的NAPI开发是一种“自上而下”的模式,开发者在应用工程中直接创建一个原生模块,这个模块只为当前应用服务,与系统其他部分隔离。

三、 OpenHarmony NAPI开发:新增系统API

以下步骤演示如何在OpenHarmony源码中新增一个名为hellonapi的系统API模块,提供一个简单的add函数。

(一) 环境准备

  1. OpenHarmony源码。
  2. Linux编译环境(如Ubuntu 18.04/20.04)。
  3. 预装编译工具链。

(二) 新增子系统与组件

  1. 创建子系统目录:在源码根目录创建 mysubsys 文件夹。
  2. 配置子系统:在 mysubsys 下创建 ohos.build 文件,定义子系统和组件。
    // mysubsys/ohos.build
    {"subsystem": "mysubsys","parts": {"hello": {"module_list": ["//mysubsys/hello/hellonapi:hellonapi"]}}
    }
    
  3. 注册子系统:修改 build/subsystem_config.json,将新子系统加入构建系统。
    // build/subsystem_config.json (片段)
    "mysubsys": {"path": "mysubsys","name": "mysubsys"
    },
    

(三) 实现NAPI模块

  1. 创建目录结构
    mysubsys/
    └── hello/└── hellonapi/├── hellonapi.cpp└── BUILD.gn
    
  2. 编写C++代码 (hellonapi.cpp)
    #include "napi/native_api.h"
    #include "napi/native_node_api.h"
    // C++业务实现函数
    static napi_value Add(napi_env env, napi_callback_info info) {size_t argc = 2;napi_value args[2];napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);if (argc < 2) {napi_throw_error(env, nullptr, "Invalid argument count. Expected 2.");return nullptr;}napi_valuetype valuetype0;napi_typeof(env, args[0], &valuetype0);napi_valuetype valuetype1;napi_typeof(env, args[1], &valuetype1);if (valuetype0 != napi_number || valuetype1 != napi_number) {napi_throw_type_error(env, nullptr, "Wrong argument type. Numbers expected.");return nullptr;}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;
    }
    // 接口注册函数
    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;
    }
    // 模块定义
    static napi_module hellonapiModule = {.nm_version = 1,.nm_flags = 0,.nm_filename = nullptr,.nm_register_func = Init,.nm_modname = "hellonapi", // 模块名,对应ArkTS导入名的一部分.nm_priv = ((void*)0),.reserved = {0},
    };
    // 模块注册,加载so时自动调用
    extern "C" __attribute__((constructor)) void RegisterHellonapiModule(void) {napi_module_register(&hellonapiModule);
    }
    
  3. 编写构建脚本 (BUILD.gn)
    import("//build/ohos.gni")
    ohos_shared_library("hellonapi") {include_dirs = ["//foundation/ace/napi/interfaces/kits"]sources = ["hellonapi.cpp"]deps = ["//foundation/ace/napi:ace_napi",]relative_install_dir = "module" // 关键:指定安装到/system/lib/module/subsystem_name = "mysubsys"part_name = "hello"
    }
    

(四) 编译与集成

  1. 编译系统:执行 ./build.sh --product-name <你的产品名> (如 rk3568)。
  2. 生成Full-SDK:编译成功后,新的 libhellonapi.z.so 会被打包到系统镜像中,并生成对应的接口声明文件(.d.ts)到 out/<product>/packages/phone/samples/full-sdk 目录。
  3. ArkTS应用调用:应用开发者将这个新的Full-SDK集成到DevEco Studio中,就可以像使用系统API一样调用它:
    import hellonapi from '@ohos.hellonapi'; // 注意:模块名通常是 @ohos. + nm_modname
    @Entry
    @Component
    struct Index {@State result: number = 0;build() {Row() {Column() {Text(`Result: ${this.result}`)Button('Add 5 + 3').onClick(() => {this.result = hellonapi.add(5, 3);})}}}
    }
    

四、 HarmonyOS NAPI开发:创建应用原生模块

以下步骤演示如何在HarmonyOS应用工程中创建一个原生模块。

(一) 环境准备

  1. DevEco Studio。
  2. HarmonyOS SDK(Public-SDK即可)。

(二) 创建Native工程

  1. 在DevEco Studio中,选择 File > New > Create Project
  2. 选择模板 Native C++,点击Next。
  3. 配置工程名、包名等,点击Finish。
  4. DevEco Studio会自动生成一个包含 napi-init.cppCMakeLists.txt 和示例ArkTS代码的工程。

(三) 实现NAPI模块

  1. 编写C++代码:在 entry/src/main/cpp 目录下,修改或创建 .cpp 文件(例如 hello.cpp)。
    // entry/src/main/cpp/hello.cpp
    #include "napi/native_api.h"
    // 与OpenHarmony示例中的Add函数完全相同
    static napi_value Add(napi_env env, napi_callback_info info) {// ... (代码同上) ...
    }
    // 此函数由napi-init.cpp中的Init函数调用
    napi_value CreateAddFunction(napi_env env) {napi_property_descriptor desc[] = {{"add", nullptr, Add, nullptr, nullptr, nullptr, napi_default, nullptr}};napi_value result;napi_create_object(env, &result);napi_define_properties(env, result, sizeof(desc) / sizeof(desc[0]), desc);return result;
    }
    
  2. 注册接口:打开 entry/src/main/cpp/napi-init.cpp,修改 Init 函数来导出你的接口。
    // entry/src/main/cpp/napi-init.cpp
    #include "napi/native_api.h"
    // 声明你的函数创建器
    extern napi_value CreateAddFunction(napi_env env);
    static napi_value Init(napi_env env, napi_value exports) {// 将你的函数对象挂载到exports上napi_set_named_property(env, exports, "addModule", CreateAddFunction(env));return exports;
    }
    // ... (其余自动生成的代码保持不变) ...
    
  3. 配置构建脚本 (CMakeLists.txt)
    # entry/src/main/cpp/CMakeLists.txt
    cmake_minimum_required(VERSION 3.4.1)
    project(Entry)
    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 hello.cpp napi-init.cpp) # 添加你的cpp文件
    find_package(hilog REQUIRED CONFIG)
    find_package(ace_napi REQUIRED CONFIG)
    target_link_libraries(entry PUBLIC ace_napi::ace_napi hilog::libhilog)
    

(四) ArkTS应用调用

  1. 编译项目:DevEco Studio会自动编译C++代码生成 libentry.so 并打包到HAP中。
  2. 在ArkTS中调用
    // entry/src/main/ets/pages/Index.ets
    import nativeModule from 'libentry.so'; // 直接导入so文件名
    @Entry
    @Component
    struct Index {@State result: number = 0;build() {Row() {Column() {Text(`Result: ${this.result}`)Button('Add 10 + 20').onClick(() => {// 通过在Init中挂载的对象名访问this.result = nativeModule.addModule.add(10, 20);})}}}
    }
    

五、 NAPI异步开发:Callback与Promise

对于耗时操作,必须使用异步模型避免阻塞UI线程。NAPI提供了基于napi_create_async_work的异步支持。

异步工作原理

  1. 立即返回:原生函数被调用时,立即创建一个异步工作项并返回一个Promise对象或接收一个Callback函数,然后立即结束。
  2. 后台执行napi_create_async_work创建的工作项被放入线程池,在后台Worker线程中执行execute回调。注意:execute回调中不能调用任何NAPI接口
  3. 结果返回execute执行完毕后,在JS主线程(EventLoop)中触发complete回调。complete回调可以将结果转换为JS值,并通过Promise的resolve/reject或调用Callback函数返回给ArkTS。

Promise模式示例

// 结构体用于在execute和complete之间传递数据
struct AddAsyncData {napi_async_work work;double x;double y;double result;napi_ref callback_ref; // 如果是Callback模式,需要保存回调函数的引用
};
// execute回调:在worker线程执行
static void ExecuteAdd(napi_env env, void* data) {AddAsyncData* asyncData = (AddAsyncData*)data;asyncData->result = asyncData->x + asyncData->y;
}
// complete回调:在JS线程执行
static void CompleteAdd(napi_env env, napi_status status, void* data) {AddAsyncData* asyncData = (AddAsyncData*)data;napi_value result;napi_create_double(env, asyncData->result, &result);// 获取Promise的resolve函数napi_value promise;napi_get_named_property(env, asyncData->work, "promise", &promise);napi_value resolve;napi_get_named_property(env, promise, "resolve", &resolve);// 调用resolve,将结果返回napi_call_function(env, undefined, resolve, 1, &result, nullptr);// 清理资源napi_delete_async_work(env, asyncData->work);delete asyncData;
}
// 导出的异步函数
static napi_value AddAsync(napi_env env, napi_callback_info info) {size_t argc = 2;napi_value args[2];napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);// 获取参数AddAsyncData* asyncData = new AddAsyncData();napi_get_value_double(env, args[0], &asyncData->x);napi_get_value_double(env, args[1], &asyncData->y);// 创建Promisenapi_value promise;napi_create_promise(env, &asyncData->callback_ref, &promise, &resolve); // 此处简化,实际需管理deferred// 创建异步工作项napi_value resource_name;napi_create_string_utf8(env, "AddAsync", NAPI_AUTO_LENGTH, &resource_name);napi_create_async_work(env, nullptr, resource_name, ExecuteAdd, CompleteAdd, asyncData, &asyncData->work);// 将工作项放入队列napi_queue_async_work(env, asyncData->work);return promise; // 返回Promise对象
}

Callback模式的实现类似,只是在AddAsync中获取并保存Callback函数的引用,在CompleteAdd中调用该Callback即可。

六、 总结

NAPI是鸿蒙生态连接ArkTS应用层与C/C++系统/原生层的强大桥梁。通过本教程,我们清晰地认识到:

  1. OpenHarmony的NAPI开发是系统级工程,旨在为整个生态扩展标准化的原生能力,流程复杂但影响深远,适合平台和硬件开发者。
  2. HarmonyOS的NAPI开发是应用级工程,旨在优化单个应用的性能或复用现有代码库,流程简单直接,适合广大应用开发者。
http://www.dtcms.com/a/502889.html

相关文章:

  • openHarmony之DSoftBus分布式软总线智能链路切换算法
  • TensorFlow2 Python深度学习 - 循环神经网络(GRU)示例
  • TVM | Relay
  • 使用 Conda 安装 QGIS 也是很好的安装方式
  • 网站套餐到期什么意思抖音seo优化系统招商
  • 怎么看网站pr值衡水市住房和城乡建设局网站
  • 散点拟合圆:Matlab两种方法实现散点拟合圆
  • Kubernetes流量管理:从Ingress到GatewayAPI演进
  • 专做品牌网站西安做网站电话
  • “函数恒大于0”说明函数是可取各不同数值的变数(变量)——“函数是一种对应法则等”是非常明显的错误
  • Linux系统--信号(4--信号捕捉、信号递达)--重点--重点!!!
  • Blender后期合成特效资产预设插件 MP_Comp V2.0.2
  • 达梦8数据库常见故障分析与解决方案
  • 迁移服务器
  • 解决docker构建centos7时yum命令报错、镜像源失效问题
  • 密钥轮换:HashiCorp Vault自动续期,密钥生命周期?
  • 即时通讯系统核心模块实现
  • 【HarmonyOS】组件嵌套优化
  • 福州企业做网站催眠物语wordpress
  • 图文并茂:全面了解UART相关知识(TTL+RS232+RS484)
  • VMware Euler系统Ctrl+C/V共享剪贴板完全指南:从配置到彻底清理
  • IOT项目——STM32
  • 【物联网架构】
  • 【编程】IDEA自定义系统注解格式|自定义自定义注解格式
  • 定位网站关键词dw网页制作模板源代码
  • 【Linux网络】封装Socket
  • Solidity智能合约开发入门攻略
  • AI决策系统:从数据到行动的智能跃迁——底层逻辑与实践全景解析
  • 好看的单页面网站石岩网站设计
  • 未来的 AI 操作系统(二)——世界即界面:自然语言成为新的人机交互协议