赞
踩
通过本文您将熟悉:
NAPI(Native API)组件是一套对外接口基于Node.js N-API规范开发的原生模块扩展开发框架。
OpenHarmony中组件有一种是C和C++语言的三方组件,通常以源码或OpenHarmony hpm包的方式引入,在应用开发中以NAPI的方式使用,或直接编译在OpenHarmony操作系统镜像
NAPI组件架构图
OpenHarmony 标准系统应用开发基于ArkUI框架,开发语言使用JS/eTS。部分业务场景依赖使用现有的C/C++ 库,或为了获取更高的性能。OpenHarmony提供NAPI机制,用于规范封装IO、CPU密集型、OS底层等能力并对外暴露JS接口,通过NAPI实现JS和C/C++代码的互相访问.
OpenHarmony 中的 N-API 定义了由 JS/ETS 语言编写的代码和 native 代码(使用 C/C++ 编写)交互的方式,由 Node.js N-API 框架扩展而来。
- N-API:Native Application Programming Interface(本地应用程序接接口)
- 什么是Node.js N-API 框架
Node.js N-API为开发者提供了一套C/C++ API用于开发Node.js的Native扩展模块。从Node.js 8.0.0开始,N-API以实验性特性作为Node.js本身的一部分被引入,并且从Node.js 10.0.0开始正式全面支持N-API。
直接在OpenHarmony源码根目录创建子系统文件夹,取名mysubsys。并在目录下添加子系统的构建配置文件ohos.build
完整内容如下:
{ "subsystem": "mysubsys", "parts": { "hello": { "module_list": [ "//mysubsys/hello/hellonapi:hellonapi" ], "inner_kits": [ ], "system_kits": [ ], "test_list": [ ] } } }
需要明白以下知识点:
"subsystem": "mysubsys",
"parts": {
"hello": {
}
}
"module_list": [
"//mysubsys/hello/hellonapi:hellonapi"
接着将子系统配置到源码下build\subsystem_config.json文件,在该文件中插入如下内容。
"mysubsys": {
"project": "hmf/mysubsys",
"path": "mysubsys",
"name": "mysubsys",
"dir": ""
}
本示例按子系统system > 组件part > 组件module 创建了3级目录
mysubsys -- 子系统目录
├── hello -- 组件目录
│ └── hellonapi
│ ├── BUILD.gn -- 组件module目录
│ └── hellonapi.cpp
└── ohos.build
最后在组件目录下中创建代码文件hellonapi.cpp
完整内容如下:
#include <string.h> #include "napi/native_node_api.h" #include "napi/native_api.h" // 接口业务实现C/C++代码 // std::string 需要引入string头文件,#include <string> // 该napi_module对外具体的提供的API接口是 getHelloString static napi_value getHelloString(napi_env env, napi_callback_info info) { napi_value result; std::string words = "Hello OpenHarmony NAPI"; NAPI_CALL(env, napi_create_string_utf8(env, words.c_str(), words.length(), &result)); return result; } // 注册对外接口的处理函数napi_addon_register_func // 2.指定NAPI模块注册对外接口的处理函数,具体扩展的接口在该函数中声明 // 模块对外接口注册函数为registerFunc static napi_value registerFunc(napi_env env, napi_value exports) { static napi_property_descriptor desc[] = { // 声明该napi_module对外具体的提供的API为getHelloString DECLARE_NAPI_FUNCTION("getHelloString", getHelloString), }; NAPI_CALL(env, napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc)); return exports; } // 注册NAPI模块 // 1.先定义NAPI模块,指定当前NAPI模块对应的模块名 // 以及模块注册对外接口的处理函数,具体扩展的接口在该函数中声明 // nm_modname: NAPI模块名称,对应eTS代码为import nm_modname from '@ohos.ohos_shared_library_name' // 示例对应hap应用中eTS代码需要包含import hellonapi from '@ohos.hellonapi' // 以下的出现的hellonapi都为注册的NAPI模块名 static napi_module hellonapiModule = { .nm_version = 1, .nm_flags = 0, .nm_filename = nullptr, // registerFunc是NAPI模块对外接口注册函数 .nm_register_func = registerFunc, .nm_modname = "hellonapi", .nm_priv = ((void*)0), .reserved = { 0 }, }; // 3.NAPI模块定义好后,调用NAPI提供的模块注册函数napi_module_register(napi_module* mod)函数注册到系统中。 // register module,设备启动时自动调用此constructor函数,把定义的模块注册到OpenHarmony中。 // 以下出现的hellonapi都是注册的NAPI模块名 extern "C" __attribute__((constructor)) void hellonapiModuleRegister() { // napi_module_register是ohos的NAPI组件提供的模块注册函数 napi_module_register(&hellonapiModule); }
代码解析如下:
// 接口业务实现C/C++代码
// std::string 需要引入string头文件,#include <string>
// 该napi_module对外具体的提供的API接口是 getHelloString
static napi_value getHelloString(napi_env env, napi_callback_info info) {
napi_value result;
std::string words = "Hello OpenHarmony NAPI";
NAPI_CALL(env, napi_create_string_utf8(env, words.c_str(), words.length(), &result));
return result;
}
NAPI提供了提供了一系列接口函数,声明包含如下2个头文件中,先添加这2个头文件到hellonapi.cpp
#include "napi/native_api.h"
#include "napi/native_node_api.h"
定义的hellonapi模块,其对应结构体为napi_module。
// 注册对外接口的处理函数napi_addon_register_func // 2.指定NAPI模块注册对外接口的处理函数,具体扩展的接口在该函数中声明 // 模块对外接口注册函数为registerFunc static napi_value registerFunc(napi_env env, napi_value exports) { static napi_property_descriptor desc[] = { // 声明该napi_module对外具体的提供的API为getHelloString // 在napi_property_descriptor desc[]中需要将编写C语言的“getHelloString”方法与对暴露的Js语言的接口“getHelloString”进行关联。 /* NAPI提供DECLARE_NAPI_FUNCTION(name, func)函数用于声明api, 传入名称和其他实现函数。在registerFunc函数中添加DECLARE_NAPI_FUNCTION */ DECLARE_NAPI_FUNCTION("getHelloString", getHelloString), }; NAPI_CALL(env, napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc)); return exports; } // 注册NAPI模块 // 1.先定义NAPI模块,指定当前NAPI模块对应的模块名 // 以及模块注册对外接口的处理函数,具体扩展的接口在该函数中声明 // nm_modname: NAPI模块名称,对应eTS代码为import nm_modname from '@ohos.ohos_shared_library_name' // 示例对应hap应用中eTS代码需要包含import hellonapi from '@ohos.hellonapi' // 以下的出现的hellonapi都为注册的NAPI模块名 static napi_module hellonapiModule = { .nm_version = 1, .nm_flags = 0, .nm_filename = nullptr, // registerFunc是该自定义的NAPI模块对外接口注册函数 .nm_register_func = registerFunc, .nm_modname = "hellonapi", .nm_priv = ((void*)0), .reserved = { 0 }, }; // 3.NAPI模块定义好后,调用ohos的NAPI组件提供的模块注册函数napi_module_register(napi_module* mod)函数注册到系统中。 // register module,设备启动时自动调用constructor函数,把定义的模块注册到OpenHarmony中。 // 以下出现的hellonapi都是注册的NAPI模块名 extern "C" __attribute__((constructor)) void hellonapiModuleRegister() { // napi_module_register(napi_module* mod)是ohos的NAPI组件提供的模块注册函数 napi_module_register(&hellonapiModule); }
napi_module_register(napi_module* mod)是ohos的NAPI组件提供的模块注册函数。
在模块hellonapi目录下新建BUILD.gn文件,内容如下:
gn文件支持注释,以
#
开头
import("//build/ohos.gni") #ohos_shared_library()中的hellonapi决定了生成动态库的名称,增量编译阶段生成动态库libhellonapi.z.so ohos_shared_library("hellonapi") { include_dirs = [ #NAPI头文件目录 "//foundation/arkui/napi/interfaces/kits", "//foundation/arkui/napi/interfaces/inner_api", #根据增量编译阶段报错添加的头文件目录 "//third_party/node/src" ] #根据增量编译时clang编译器报警,添加的cflag cflags_cc = [ #编译时报错提示"-Werror",则加上"-Wno-error" "-Wno-error", #编译时报错提示"-Wunused-function",则加上"-Wno-unused-function" "-Wno-unused-function", ] #编译需要的源文件 sources = [ "hellonapi.cpp" ] #指定编译依赖libace_napi.z.so动态库 deps = [ "//foundation/arkui/napi:ace_napi" ] #指定库生成的路径 #libhellonapi.z.so会安装在rk3568开发板的system/lib/module目录下 relative_install_dir = "module" #子系统名称是mysubsys subsystem_name = "mysubsys" #组件名称是hello part_name = "hello" }
将组件添加到需要的产品配置文件,源码目录下的productdefine/common/products/ohos-arm64.json。
"parts":{
...
"mysubsys:hello":{},
...
}
"parts":{
"部件所属子系统名:部件名":{}
}
新增子系统定义。
注意json文件也不支持注释!!!
"mysubsys": {
"project": "hmf/mysubsys",
"path": "mysubsys",
"name": "mysubsys"
}
"path": "mysubsys",
表示子系统路径"name": "mysubsys"
表示子系统名称将mysubsys子系统添加至rk3568开发板,在vendor目录下新增产品的定义。
{
"subsystem": "mysubsys",
"components": [
{
"component": "hello",
"features": []
}
]
}
"subsystem": "mysubsys",
表示添加的子系统是mysubsys"component": "hello",
表示添加的子系统中包含的组件名称是hello先进行增量编译出子系统的动态库,增量编译没有报错后。再全量编译出镜像,将其烧录到开发板上。
./build.sh --product-name rk3568 --ccache --build-target=hellonapi --target-cpu arm64
从OpenHarmony 3.2 Beta2起,SDK会同时提供Public SDK和Full SDK。通过DevEco Studio默认获取的SDK为Public SDK。
两者差异如下:
笔者使用的DevEco Studio版本为3.0.0.993,即DevEco Studio 3.0。API为API9。
若提示找不到npm,需要配置一下环境变量,将以下路径添加到环境变量中即可
D:\DevEco Studio\ohos\sdk\ets\build-tools\ets-loader
新建项目,选择OpenHarmony。
compile sdk选择9,其他保持默认即可。
第一步:调用方式和ArkUI框架提供的API一样,先import引入扩展的NAPI模块,后直接调用。
index.ets内容如下:
import prompt from '@system.prompt' //显示文本弹窗 // 引入扩展的NAPI模块 // 在hellonapi.cpp文件中定义nm_modname(模块名称)为hellonapi // 在BUILD.gn文件中定义ohos_shared_library结构体名称为hellonapi // 所以是import hellonapi from '@ohos.hellonapi' import hellonapi from '@ohos.hellonapi' @Entry @Component struct HelloNAPI { build() { Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { Button("NAPI: hellonapi.getHelloString()").margin(10).fontSize(24).onClick(() => { // hellonapi.cpp对外具体的提供的API是getHelloString let strFromNAPI = hellonapi.getHelloString() prompt.showToast({ message: strFromNAPI }) }) } .width('100%') .height('100%') } }
第二步(可选):参考其他模块的.d.ts创建扩展模块@ohos.hellonapi.d.ts定义文件,放到IDE安装OpenHarmony SDK的目录路径ohos\sdk\ets\3.2.7.5\api下。
@ohos.hellonapi.d.ts内容如下:
declare namespace hellonapi {
function getHelloString(): string;
/**
*
*
* @since 9
* @syscap SystemCapability.Ability.AbilityRuntime.AbilityCore
*/
}
export default hellonapi;
@since 9
表示API的版本为9@syscap SystemCapability.Ability.AbilityRuntime.AbilityCore
语句在.d.ts文件中一定要添加,否则IDE还是会报错找不到该文件。declare namespace hellonapi
和export default hellonapi
的hellonapi
是BUILD.gn中的定义的ohos_shared_library_name。function getHelloString(): string;
中的getHelloString()
是hellonapi.cpp文件中指定的模块注册对外接口的处理函数则IDE扫描如下:
标准应用编译不是强依赖OpenHarmony SDK,所以可忽略IDE中告警,直接编译打包hap。但是有的时候IDE会提示找不到@ohos.hellonapi.d.ts,然后有小概率的机会无法安装hap。这个时候就要参考ohos\sdk\ets\3.2.7.5\api下的.d.ts文件编写@ohos.hellonapi.d.ts了。
如果不新建@ohos.hellonapi.d.ts放在sdk\ets\3.2.7.5\api,则IDE会报错
第三步:选择自动签名
第四步:将应用安装到dayu200开发板上
运行效果如下:
可以查阅ohos3.2beta3源码(笔者在撰写此篇文章时使用的是这个版本的源码)foundation/arkui/napi下的BUILD.gn文件验证
分析上图可以知道编译foundation子系统下的arkui部件下的napi组件生成libace_napi.z.so动态库。
表1 OpenHarmony支持的标准库
名称 | 简介 |
---|---|
标准C库 | libc、libm、libdl组合实现C11标准C库。 |
标准C++库 | libc++ 是C++标准库的一种实现。 |
OpenSL ES | OpenSL ES是一个嵌入式跨平台的音频处理库。 |
zlib | Zlib是基于C/C++语言实现的一个通用的数据压缩库。 |
EGL | EGL是渲染API与底层原生窗口系统之间的一种标准的软件接口。 |
OpenGL ES | OpenGL ES是一个嵌入式跨平台的为 3D 图形处理硬件指定标准的软件接口。 |
为了能让大家更好的学习鸿蒙(HarmonyOS NEXT)开发技术,这边特意整理了《鸿蒙开发学习手册》(共计890页),希望对大家有所帮助:https://qr21.cn/FV7h05
https://qr21.cn/FV7h05
https://qr21.cn/FV7h05
https://qr21.cn/FV7h05
https://qr18.cn/F781PH
https://qr18.cn/F781PH
1.项目开发必备面试题
2.性能优化方向
3.架构方向
4.鸿蒙开发系统底层方向
5.鸿蒙音视频开发方向
6.鸿蒙车载开发方向
7.鸿蒙南向开发方向
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。