OpenHarmony之NAPI框架介绍

2023-11-25 15:30
文章标签 介绍 框架 napi openharmony

本文主要是介绍OpenHarmony之NAPI框架介绍,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

张志成

诚迈科技高级技术专家

NAPI是什么

NAPI的概念源自Nodejs,为了实现javascript脚本与C++库之间的相互调用,Nodejs对V8引擎的api做了一层封装,称为NAPI。可以在Nodejs官网(https://nodejs.org/dist/latest-v20.x/docs/api/n-api.html)上查看各种NAPI接口定义说明。

可以看到,NAPI接口本身是C++语言实现的,这些接口可以帮助C++代码创建JS变量,或访问JavaScript运行环境中的JS变量与方法。

OpenHarmony中的NAPI

OpenAtom OpenHarmony(以下简称“OpenHarmony”)应用层基于javascript语言开发,而系统框架层则基于C++语言。它们之间需要一个桥梁来实现两种语言代码之间的相互调用,这个桥梁就是NAPI。

这里可能有的小伙伴有疑问了:OpenHarmony的NAPI和NodeJs的NAPI是一回事吗?应该说,OpenHarmony系统沿用了NAPI的接口定义形式,但每个接口的内部实现都进行了重写。这是因为NAPI接口的本质是帮助C++程序去跟Javascript引擎交互,因此对于不同的引擎需要有不同的实现方式。当用户调用了NAPI接口 napi_create_int64(), 对于Nodejs而言,它会去访问V8引擎的api创建一个js的数字变量,而对于OpenHarmony,则是去访问ArkUI框架自己的js引擎(ArkNativeEngine)。在OpenHarmony源码中搜索 napi_create_int64() 方法,你会得到一份头文件定义:third_party\node\src\js_native_api.h以及两份不同的实现代码:third_party\node\src\js_native_api_v8.ccfoundation\arkui\napi\native_engine\native_api.cppnative_api.cpp是OpenHarmony版本的NAPI实现,想了解内部细节的可以从这里入手:

创建一个简单的NAPI工程

可以通过DevEco Studio的Native C++模板创建一个包含简单NAPI 实现的样例工程。

该工程自带一个hello.cpp,实现了一个能够被javascript代码调用的add()方法。

下面我们就基于这个简单的例子,探究一下NAPI框架的实现原理。

应用如何调用NAPI接口

应用代码导入对应的so库后,就可以调用该库实现的接口。

这里我们注意到,导入日志库时使用的名称是"@ohos.hilog",应用代码如果写成  import hilog from 'libhilog.z.so'  其实也是可以成功导入的。实际上,ArkUI在运行时会将@ohos.hilog转换为libhilog.z.so,然后到 /system/lib/module/ 目录下查找此库并加载。系统实现的NAPI库都放在/system/lib/module/目录下,类似的:@ohos.wifiManager对应的是 /system/lib/module/libwifimanager.z.so;@ohos.deviceInfo 对应的是 /system/lib//module/libdeviceinfo.z.so

除了系统自带的NAPI库,应用也可以用C++开发自己的NAPI库。上面例子中 import testNapi from 'libentry.so' 导入的就是应用自己实现的。应用开发的NAPI库会随着应用工程一起编译打包到hap文件中,最终部署到/data目录每个应用自己的文件夹下。

NAPI库的导入原理

我们知道,应用的javascript代码是由ArkUI的JS引擎解释执行的。当JS引擎解读 import hilog from '@ohos.hilog'; 这行代码时,会通过dlopen() 将对应的libhilog.z.so加载到应用进程中。这一切是怎么做到的呢?每个应用进程在初始化时,都会创建一个引擎实例 ArkNativeEngineImpl,我们来看一下它的构造函数foundation\arkui\napi\native_engine\impl\ark\ark_native_engine_impl.cpp

也就是说,每个应用进程的JS引擎中,都注册了一个"requireNapi"函数,当应用调用此方法时,JS引擎就会通过NAPI框架的moduleManager类去处理so库的加载。moduleManager内部最终是找到了/system/lib/module下对应的so文件,并通过dlopen()的方式加载到应用进程中。想了解细节的小伙伴可以读一下NativeModuleManager::LoadNativeModule()方法的内部实现。

这里可能会有个疑问:应用的javascript代码中并没有写什么"requireNapi"的代码,只有import xxx,怎么触发的导入处理函数?答案要到编译后的js代码中寻找。我们解开编译后的hap包,找到ets文件对应的js文件:

可以看到,index.ets被编译成index.js后,import关键字也被转为了"requireNapi",这样JS引擎在执行这行代码时,就会去调用注册的导入处理函数了。

C++库如何实现JS方法

前面解决了JS 导C++库的问题,下一步就是JS如何调用C++库里的方法了。先说结论:一个C++方法能否被应用调用,取决与C++代码有没有将这个方法注册到JS引擎。

我们来看看hello.cpp是如何注册add方法的:

我们可以从下往上看这段代码:首先是 RegisterEntryModule(void) 方法。这是C++向JS引擎进行NAPI模块与方法注册的起始代码。注意这个方法前面有个编译修饰符 "__attribute__((constructor))",它的作用是指导C++代码的编译,使得当so库被加载到应用进程中时,RegisterEntryModule(void) 方法就会被自动调用到。该方法通过NAPI接口napi_module_register() 向JS引擎注册了一个 napi_module。

然后是Init()方法。该方法实现了Add方法的注册。也就是告诉JS引擎,将JS符号"add" 与C++方法"Add" 进行关联映射。这样后续当JS引擎解释执行javascript代码 "testNapi.add(2, 3)"时,就会找到C++ Add()方法的函数地址并调用。如下图所示:

方法关联调用的问题也解决了,最后就是JS运行环境与C++运行环境的相互切换了。当C++的Add方法被JS引擎调用到后,引擎会将javascript下发的参数变量传递给C++。所有从JS运行环境传递过来的变量都是用napi_value类型来表示的。需要通过NAPI接口转为C++语言的变量类型。详见下图每行代码的注释:

napi_value不是一个具体的类型,它类似于void*,表示的是JS变量在JS引擎内部存储区内的地址。需要通过对应的NAPI方法实现,例如:napi_get_value_int32()  --- js变量转为c++整形napi_get_value_string_utf8() --- js变量转为c++字符串napi_get_value_bool() --- js变量转为c++布尔值

这些接口的具体用法和使用场景,可以参考NodeJs官方文档(https://nodejs.org/dist/latest-v20.x/docs/api/n-api.html)

C++程序链接NAPI库

OpenHarmony的NAPI接口实现都封装在libace_napi.z.so中,C++程序编译时需链接此库。对于DevEco Studio应用开发的cpp代码,在对应的CMakeLists.txt中链接。该库文件在SDK目录下可以找到。

对于设备侧开发,系统框架中的C++程序,则通过BUILD.gn文件定义依赖关系。

总结

NAPI是JavaScript与C++交互的桥梁。在OpenHarmony中,Javascript代码在运行时由ArkUI的JS引擎解释执行,C++代码则通过NAPI接口访问JS引擎中的Javascript上下文,从而实现与JS变量、方法之间的相互调用。

参考链接

以下是源码仓库地址

arkui_napi: Development framework for extending the JS Native Module | 原生模块扩展开发框架

third_party_node: Third-party open-source software node | 三方开源软件node

这篇关于OpenHarmony之NAPI框架介绍的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/424051

相关文章

性能测试介绍

性能测试是一种测试方法,旨在评估系统、应用程序或组件在现实场景中的性能表现和可靠性。它通常用于衡量系统在不同负载条件下的响应时间、吞吐量、资源利用率、稳定性和可扩展性等关键指标。 为什么要进行性能测试 通过性能测试,可以确定系统是否能够满足预期的性能要求,找出性能瓶颈和潜在的问题,并进行优化和调整。 发现性能瓶颈:性能测试可以帮助发现系统的性能瓶颈,即系统在高负载或高并发情况下可能出现的问题

水位雨量在线监测系统概述及应用介绍

在当今社会,随着科技的飞速发展,各种智能监测系统已成为保障公共安全、促进资源管理和环境保护的重要工具。其中,水位雨量在线监测系统作为自然灾害预警、水资源管理及水利工程运行的关键技术,其重要性不言而喻。 一、水位雨量在线监测系统的基本原理 水位雨量在线监测系统主要由数据采集单元、数据传输网络、数据处理中心及用户终端四大部分构成,形成了一个完整的闭环系统。 数据采集单元:这是系统的“眼睛”,

Hadoop数据压缩使用介绍

一、压缩原则 (1)运算密集型的Job,少用压缩 (2)IO密集型的Job,多用压缩 二、压缩算法比较 三、压缩位置选择 四、压缩参数配置 1)为了支持多种压缩/解压缩算法,Hadoop引入了编码/解码器 2)要在Hadoop中启用压缩,可以配置如下参数

OpenHarmony鸿蒙开发( Beta5.0)无感配网详解

1、简介 无感配网是指在设备联网过程中无需输入热点相关账号信息,即可快速实现设备配网,是一种兼顾高效性、可靠性和安全性的配网方式。 2、配网原理 2.1 通信原理 手机和智能设备之间的信息传递,利用特有的NAN协议实现。利用手机和智能设备之间的WiFi 感知订阅、发布能力,实现了数字管家应用和设备之间的发现。在完成设备间的认证和响应后,即可发送相关配网数据。同时还支持与常规Sof

图神经网络模型介绍(1)

我们将图神经网络分为基于谱域的模型和基于空域的模型,并按照发展顺序详解每个类别中的重要模型。 1.1基于谱域的图神经网络         谱域上的图卷积在图学习迈向深度学习的发展历程中起到了关键的作用。本节主要介绍三个具有代表性的谱域图神经网络:谱图卷积网络、切比雪夫网络和图卷积网络。 (1)谱图卷积网络 卷积定理:函数卷积的傅里叶变换是函数傅里叶变换的乘积,即F{f*g}

cross-plateform 跨平台应用程序-03-如果只选择一个框架,应该选择哪一个?

跨平台系列 cross-plateform 跨平台应用程序-01-概览 cross-plateform 跨平台应用程序-02-有哪些主流技术栈? cross-plateform 跨平台应用程序-03-如果只选择一个框架,应该选择哪一个? cross-plateform 跨平台应用程序-04-React Native 介绍 cross-plateform 跨平台应用程序-05-Flutte

C++——stack、queue的实现及deque的介绍

目录 1.stack与queue的实现 1.1stack的实现  1.2 queue的实现 2.重温vector、list、stack、queue的介绍 2.1 STL标准库中stack和queue的底层结构  3.deque的简单介绍 3.1为什么选择deque作为stack和queue的底层默认容器  3.2 STL中对stack与queue的模拟实现 ①stack模拟实现

Spring框架5 - 容器的扩展功能 (ApplicationContext)

private static ApplicationContext applicationContext;static {applicationContext = new ClassPathXmlApplicationContext("bean.xml");} BeanFactory的功能扩展类ApplicationContext进行深度的分析。ApplicationConext与 BeanF

数据治理框架-ISO数据治理标准

引言 "数据治理"并不是一个新的概念,国内外有很多组织专注于数据治理理论和实践的研究。目前国际上,主要的数据治理框架有ISO数据治理标准、GDI数据治理框架、DAMA数据治理管理框架等。 ISO数据治理标准 改标准阐述了数据治理的标准、基本原则和数据治理模型,是一套完整的数据治理方法论。 ISO/IEC 38505标准的数据治理方法论的核心内容如下: 数据治理的目标:促进组织高效、合理地

嵌入式Openharmony系统构建与启动详解

大家好,今天主要给大家分享一下,如何构建Openharmony子系统以及系统的启动过程分解。 第一:OpenHarmony系统构建      首先熟悉一下,构建系统是一种自动化处理工具的集合,通过将源代码文件进行一系列处理,最终生成和用户可以使用的目标文件。这里的目标文件包括静态链接库文件、动态链接库文件、可执行文件、脚本文件、配置文件等。      我们在编写hellowor