0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

OpenHarmony 之 NAPI 框架介绍

王程 来源:jf_75796907 作者:jf_75796907 2024-02-01 17:34 次阅读

NAPI 是什么

NAPI 的概念源自 Nodejs,为了实现 javascript 脚本与 C++ 库之间的相互调用,Nodejs 对 V8 引擎的 api 做了一层封装,称为 NAPI。可以在 Nodejs 官网上查看各种 NAPI 接口定义说明。

wKgaomW7ZZyAYgmdAACKb1Siseo870.png

wKgZomW7Y7yAVd6uAACKb1Siseo945.png


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

OpenHarmony 中的 NAPI

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

wKgZomW7ZZyAeeaLAAATN4COqqE509.png

wKgZomW7Y8WAE7mMAAATN4COqqE582.png


这里可能有的小伙伴有疑问了: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_partynodesrcjs_native_api.h 以及两份不同的实现代码:third_partynodesrcjs_native_api_v8.ccfoundationarkuinapinative_enginenative_api.cppnative_api.cpp 是 OpenHarmony 版本的 NAPI 实现,想了解内部细节的可以从这里入手:

wKgaomW7ZZ2AGsGgAACfJoIejHA705.png

wKgZomW7Y9qARUrEAACfJoIejHA869.png

创建一个简单的 NAPI 工程

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

wKgZomW7ZZ2Acnw-AAA4QhHETD8395.png

wKgZomW7ZNmAbzayAAA4QhHETD8531.png

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

wKgaomW7Y_SAOX43AAExJw9GdEo668.png


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

应用如何调用 NAPI 接口

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

wKgaomW7ZAmAUrRmAAChcME0Pco291.png


这里我们注意到,导入日志库时使用的名称是 “@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 目录每个应用自己的文件夹下。

wKgZomW7ZBGAc8yeAAEoBFK5F28114.png

NAPI 库的导入原理

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

wKgaomW7ZB2AfltZAADrUj9f67g837.png


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

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

wKgZomW7ZCSAUGstAACFYhQ77v0762.png

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

wKgaomW7ZDCADRyLAACFMpZuTZQ193.png

C++ 库如何实现 JS 方法

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

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

wKgaomW7ZZ6AVP3FAAE30hMfv0s311.png

wKgZomW7ZFWAZWZ9AAE30hMfv0s093.png


我们可以从下往上看这段代码:首先是 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 () 方法的函数地址并调用。如下图所示:

wKgaomW7ZFuAcLAPAAM0DzxiyGk499.png

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

wKgZomW7ZHGAYxEJAAMwtf_Wu1w075.png

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 目录下可以找到。

wKgaomW7ZICAVgNrAACY9zLbKzE999.png


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

wKgaomW7ZaCAX5EuAAAJck3isig866.png

wKgZomW7ZIeAYCU9AAAJck3isig483.png

总结

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

审核编辑 黄宇


声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 接口
    +关注

    关注

    33

    文章

    8593

    浏览量

    151117
  • API
    API
    +关注

    关注

    2

    文章

    1499

    浏览量

    61991
  • OpenHarmony
    +关注

    关注

    25

    文章

    3721

    浏览量

    16299
收藏 人收藏

    评论

    相关推荐

    2K0300先锋派Openharmony开发介绍

    *附件:2K0300先锋派Openharmony开发介绍-241114.pdf
    发表于 11-17 21:36

    第三届OpenHarmony技术大会星光璀璨、致谢OpenHarmony社区贡献者

    取得丰硕成果的TSG团队、OpenHarmony技术俱乐部团队及个人,本次大会特别举办了星光团队和星光个人授牌仪式。共授牌4个星光TSG,分别是安全及机密计算TSG、跨平台应用开发框架TSG、编程语言
    的头像 发表于 10-21 14:10 216次阅读

    基于ArkTS语言的OpenHarmony APP应用开发:HelloOpenharmony

    1、程序简介该程序是基于OpenHarmony标准系统编写的UI应用类:HelloOpenHarmony。本案例是基于API9接口开发。本案例已在OpenHarmony凌蒙派-RK3568开发
    的头像 发表于 09-15 08:09 383次阅读
    基于ArkTS语言的<b class='flag-5'>OpenHarmony</b> APP应用开发:Hello<b class='flag-5'>Openharmony</b>

    鸿蒙OpenHarmony南向/北向快速开发教程-迅为RK3568开发板

    优化开发流程-配置远程访问环境 P8_优化开发流程-编译源码和烧写镜像 P9_OpenHarmony源码目录介绍 P10_整体移植方案介绍 P11_编译目标分析 P12_编译框架基本概
    发表于 07-23 10:44

    OpenHarmony开机优化

    OpenHarmony已经支持了Bootchart工具,我们可以直接使用Bootchart工具,Bootchart工具介绍如下: 概述 Bootchart是一个用于系统启动过程性能分析的开源软件工具
    发表于 07-01 16:39

    OpenHarmony 成功亮相国际学术会议 ASPLOS 2024

    举行的ASPLOS 2024上成功举办。本次学术教程会以“OpenHarmony操作系统的关键特性与能力”为主题,聚焦“基于OpenHarmony的前沿学术探索机遇与挑战“,详细介绍
    的头像 发表于 05-16 09:28 425次阅读
    <b class='flag-5'>OpenHarmony</b> 成功亮相国际学术会议 ASPLOS 2024

    开发者手机 AI - 目标识别 demo

    Lite的API接口实现主要功能; Mindspore Lite为Openharmony AI推理框架,为上层应用提供统一的AI推理接口,可以完成在手机等端侧设备中的模型推理过程; Neural
    发表于 04-11 16:14

    【六】Purple Pi OH开发板带你7天入门OpenHarmony

    今天我们来从OpenHarmony简介、环境搭建、创建第一个OpenHarmony项目等方面开始OpenHarmony应用开发的第一步。一.OpenHarmony简介
    的头像 发表于 03-14 08:31 546次阅读
    【六】Purple Pi OH开发板带你7天入门<b class='flag-5'>OpenHarmony</b>!

    介绍一种OpenAtom OpenHarmony轻量系统适配方案

    本文在不改变原有系统基础框架的基础上, 介绍了一种OpenAtom OpenHarmony(以下简称“OpenHarmony”)轻量系统适配方案。
    的头像 发表于 03-05 09:24 1161次阅读
    <b class='flag-5'>介绍</b>一种OpenAtom <b class='flag-5'>OpenHarmony</b>轻量系统适配方案

    【鸿蒙】NAPI 框架生成工具实现流程

    NAPI 框架生成工具 可以根据用户指定路径下的 ts(typescript)接口文件一键生成 NAPI 框架代码、业务代码框架、GN 文件
    的头像 发表于 02-28 17:00 692次阅读
    【鸿蒙】<b class='flag-5'>NAPI</b> <b class='flag-5'>框架</b>生成工具实现流程

    OpenHarmony4.0源码解析媒体框架

    媒体框架简介 媒体框架 multimedia_player_framework 主要提供音视频的录制与播放功能。 框架简介 从框架图中可以看出,媒体
    的头像 发表于 02-26 22:05 932次阅读
    <b class='flag-5'>OpenHarmony</b>4.0源码解析<b class='flag-5'>之</b>媒体<b class='flag-5'>框架</b>

    【鸿蒙】OpenHarmony 4.0蓝牙代码结构简析

    /master/api当前所有应用层接口统一归并到interface仓;api 10中蓝牙接口按照profile拆分了多个d.ts文件 框架层https://gitee.com/openharmony/communication_bluetooth该仓之前包含
    的头像 发表于 02-26 16:08 1558次阅读
    【鸿蒙】<b class='flag-5'>OpenHarmony</b> 4.0蓝牙代码结构简析

    鸿蒙OpenHarmony NAPI技术-基础学习

    NAPI(Native API)是OpenHarmony系统中的一套原生模块扩展开发框架,它基于Node.js N-API规范开发,为开发者提供了JavaScript与C/C++模块之间相互调用的交互能力。可以在NodeJs官网
    的头像 发表于 01-19 16:57 979次阅读
    鸿蒙<b class='flag-5'>OpenHarmony</b> <b class='flag-5'>NAPI</b>技术-基础学习

    OpenHarmony图形HDI基础适配及点屏

    本文档主要介绍图形基础适配及点屏。 环境说明: OHOS版本: 适用3.2-Beta3及以上 内核版本: linux-5.10 硬件环境: Dayu200-rk3568及其它硬件 一、图形驱动测试
    发表于 01-18 14:49

    资讯速递 | 厦门大学OpenHarmony技术俱乐部正式揭牌成立

    个智能终端设备操作系统的框架和平台,促进万物互联产业的繁荣发展。在OpenHarmony项目群技术指导委员会领导下,OpenHar
    的头像 发表于 01-02 16:51 511次阅读
    资讯速递 | 厦门大学<b class='flag-5'>OpenHarmony</b>技术俱乐部正式揭牌成立