OpenHarmony5.0release设备开发基础之新增NAPI\NAPI开发
一、什么是NAPI? NAPINode-API, 曾用名NAPI(本文全称NAPI),是OpenHarmony中提供ArkTS/JS与C/C++跨语言调用的接口,是NDK接口中的一部分。该接口是在Node.js提供的Node-API基础上扩展而来,但与Node.js中的Node-API
一、什么是NAPI?
NAPI
Node-API, 曾用名NAPI(本文全称NAPI),是OpenHarmony中提供ArkTS/JS与C/C++跨语言调用的接口,是NDK接口中的一部分。该接口是在Node.js提供的Node-API基础上扩展而来,但与Node.js中的Node-API不完全兼容。
OpenHarmony Node-API是基于Node.js 12.x LTS的Node-API规范扩展开发的机制,为开发者提供了ArkTS/JS与C/C++模块之间的交互能力。它提供了一组稳定的、跨平台的API,可以在不同的操作系统上使用。
二、为什么使用NAPI?
一般情况下OpenHarmony应用开发使用ArkTS/JS语言,但部分场景由于性能、效率等要求,比如游戏、物理模拟等,需要依赖使用现有的C/C++库。Node-API规范封装了I/O、CPU密集型、OS底层等能力并对外暴露ArkTS/JS接口,从而实现ArkTS/JS和C/C++的交互。主要场景如下:
- 系统可以将框架层丰富的模块功能通过ArkTS/JS接口开放给上层应用。
- 应用开发者也可以选择将一些对性能、底层系统调用有要求的核心功能用C/C++封装实现,再通过ArkTS/JS接口使用,提高应用本身的执行效率。
2.1、新增NAPI与NativeC++工程的不同
新增NAPI适用于设备开发、系统开发,可以提供设备支持的sdk给开发者使用。NativeC++仅适用于应用开发。
新增的NAPI可以和其他系统NAPI一样配置预加载,应用加载对应so几乎不耗时。NativeC++需要使用时加载,自定义so无法配置预加载。
新增NAPI由于写在源码中,可以调用inner_api,权限更大,还可以配置自定义权限,ability等。NativeC++无法使用inner_api,仅使用系统暴露的接口。
基于此,本文将介绍如何在系统层面使用NAPI将框架层丰富的模块功能通过ArkTS/JS接口开放给上层应用 。
三、如何使用dts2cpp工具新增NAPI供上层应用使用
3.1、dts2cpp工具介绍及使用方法
简介
dts2cpp工具,它可以根据用户指定路径下的ts(typescript)接口文件一键生成NAPI框架代码、业务代码框架、GN文件等。在开发JS应用与NAPI间接口时,底层框架开发者无需关注js语法、C++与JS之间的数据类型转换等上层应用转换逻辑,只关注底层业务逻辑即可,专业的人做专业的事,从而可以大大提高开发效率。
约束
系统:建议Ubuntu 20.04
依赖版本:VS Code 1.62.0
使用方法
生成框架
安装typescript:在napi_generator/src/cli/dts2cpp/src目录下执行命令:
npm i typescript
安装stdio:在napi_generator/src/cli/dts2cpp目录下执行命令:
npm i stdio
将待转换的文件@ohos.napitest.d.ts拷贝到napi_generator/src/cli/dts2cpp/src/gen下,并在该目录下新建out目录;@ohos.napitest.d.ts如下所示:
declare namespace napitest { function myAdd(a: number, b: number): number; function myAddThirtyThoundTimes(a: number, b: number): number; } export default napitest;
在napi_generator/src/cli/dts2cpp/src/gen下执行以下命令生成napi框架代码:
node cmd_gen.js -f @ohos.napitest.d.ts -o out
其中,参数详情如下:
-f, 待转换的.d.ts文件,若同时转换多个文件,文件之间用“,”隔开;
-d, 根据指定路径转换该文件夹中所有.d.ts文件;
-i, 可选参数,默认false,待转换.d.ts文件中引用非basic.d.ts的ts文件时打开开关;
-o, 可选参数,默认为当前目录,指定生成框架代码输出路径;
-n, 可选参数,默认为uint32_t,指定生成框架代码中number类型全部为指定类型;
-s, 可选参数,默认为不配置业务代码,指定生成框架代码的业务配置文件,用于粘合工具代码和业务代码的配置。
备注1:-f与-d两个参数只选其中一个参数即可。
备注2:若.d.ts文件中声明了其它.d.ts文件,将此类文件放置在待转换.d.ts文件同级目录。
输出文件如下所示:
├── binding.gyp ├── BUILD.gn ├── bundle.json ├── napi_gen.log ├── napitest.cpp ├── napitest.h ├── napitest_middle.cpp ├── napitest_middle.h ├── test.sh ├── tool_utility.cpp └── tool_utility.h
3.2、NAPI框架生成代码集成到OpenHarmony的方法
场景说明
为了实现工具生成的接口被其它子系统或者应用调用,需将生成的代码编译集成到OpenHarmony系统中,使其生成动态库,供OpenHarmony应用层调用。 本文介绍如何将工具生成的源码利用OpenHarmony编译系统生成动态库供应用层调用,主要是有以下两种方式,分别为增加ohos.build文件方式和增加bundle.json文件方式。
建立模块位置
模块目录理论上可在OpenHarmony工程的任一位置,以5.0.0版本为例,4.1类似。假设OpenHarmony代码库的目录为OHOS_SRC,在OHOS_SRC/myFirstNapi目录下,建测试模块目录:napitest。napitest目录结构如下:
myFirstNapi
├── binding.gyp
├── BUILD.gn
├── bundle.json
├── napi_gen.log
├── napitest.cpp
├── napitest.h
├── napitest_middle.cpp
├── napitest_middle.h
├── test.sh
├── tool_utility.cpp
└── tool_utility.h
其中bundle.json为新增的编译配置文件,其它为工具生成的代码。
编译修改点
修改bundle.json文件
其中destPath选项中的"//foundation/napitest"指的是napitest目录,":napitest"指的是上面BUILD.gn中的目标ohos_shared_library("napitest")。
{
"name": "@ohos/napitest",
"description": "napitest provides atomic capabilities",
"version": "5.0.0",
"license": "Apache License 2.0",
"publishAs": "code-segment",
"segment": {
"destPath": "myFirstNapi"
},
"dirs": {},
"scripts": {},
"component": {
"name": "napitest",
"subsystem": "napitest",
"features": [],
"adapted_system_type": [
"standard"
],
"rom": "10000KB",
"ram": "10000KB",
"deps": {
"components": [
"napi",
"ipc_core",
"libhilog"
],
"third_party": [
"node"
]
},
"build": {
"sub_component": [
"//myFirstNapi:napitest"
],
"inner_kits": [
{
"header": {
"header_base": "//myFirstNapi",
"header_files": [
"tool_utility.h",
"napitest.h",
"napitest_middle.h"
]
},
"name": "//myFirstNapi:napitest"
}
]
}
}
}
修改BUILD.gn文件
删除ohos_shared_library("napitest")中的deps,并新增external_deps = [ "napi:ace_napi" ] ,修改后的BUILD.gn文件内容如下所示:
import("//build/ohos.gni")
ohos_shared_library("napitest")
{
sources = [
"napitest_middle.cpp",
"napitest.cpp",
"tool_utility.cpp",
]
include_dirs = [
".",
"//third_party/node/src",
]
external_deps = [ "napi:ace_napi" ]
remove_configs = [ "//build/config/compiler:no_rtti" ]
cflags=[
]
cflags_cc=[
"-frtti",
]
ldflags = [
]
relative_install_dir = "module"
part_name = "napitest"
subsystem_name = "napitest"
}
修改napitest.cpp文件
在myAdd方法、myAddThirtyThoundTimes方法中增加业务逻辑:
#include "napitest.h"
#include "napitest_middle.h"
namespace napitest {
namespace napitest_interface {
bool myAdd(NUMBER_TYPE_1& a, NUMBER_TYPE_2& b, NUMBER_TYPE_3& out)
{
out = a + b;
return true;
}
bool myAddThirtyThoundTimes(NUMBER_TYPE_4& a, NUMBER_TYPE_5& b, NUMBER_TYPE_6& out)
{
for (int i = 0; i < 300000; i++) {
out += a + b;
}
return true;
}
}
}
增加子系统
在源码/build/subsystem_config.json中增加子系统选项。如下所示:
"napitest": {
"path": "myFirstNapi",
"name": "napitest"
}
添加功能模块
在产品配置中添加上述子系统的功能模块,编译到产品产出文件中,例如在源码vendor/hihope/rk3568/config.json中增加part选项,其中the first napitest就是BUILD.gn文件中的subsystem_name,第二个napitest就是BUILD.gn文件中的part_name。
{
"subsystem": "napitest",
"components": [
{
"component": "napitest",
"features": []
}
]
}
编译验证
编译成功后,就会在 /out/产品名/packages/phone/system/lib/module/ 生成libnapitest.z.so,如下所示:
/out/rk3568/packages/phone/system/lib/module
调用
NAPI框架代码生成后,系统框架开发者进行二次开发后,即可集成到OpenHarmony编译系统,生成对应的库文件,供应用开发者调用接口。
3.3、NAPI框架生成结果验证
准备
硬件:rk3568开发套件。
系统镜像: 上一步生成的镜像,
DevEco 4.1Release
安装镜像环境:将out/rk3568/packages/phone目录下的images镜像文件下载并烧录到开发板上。
DevEco 4.1Release新建一个OpeHarmony项目,API选择11,打开项目生成的Index.ets文件
修改点1:扩展SDK接口
查看SDK目录:打开DevEco Studio ,点击 Tools -> SDK Manager -> SDK
将@ohos.napitest.d.ts文件拷贝到应用所使用的sdk目录下 的ets\api
修改点2:修改@ohos.napitest.d.ts,增加描述
不加上描述IDE扫描不到,会报错,修改后需要重启IDE才能加载不报红
/**
*
*
* @since 9
* @syscap SystemCapability.Ability.AbilityRuntime.AbilityCore
*/
declare namespace napitest {
function myAdd(a: number, b: number): number;
function myAddThirtyThoundTimes(a: number, b: number): number;
}
export default napitest;
修改点3:增加新接口调用
其中修改index.ets文件内容如下:
import napitest from '@ohos.napitest'
@Entry
@Component
struct Index {
@State message: string = 'Hello World';
jsAddThirtyThoundTimes(a: number, b: number): number {
let out = 0;
for (let i = 0; i < 300000; i++) {
out += a + b;
}
return out;
}
build() {
Row() {
Column() {
Text(this.message)
.fontSize(50)
.fontWeight(FontWeight.Bold)
.onClick(() => {
let start = new Date().getTime();
console.log(start.toString());
let b = this.jsAddThirtyThoundTimes(2, 3);
console.log(b.toString());
let time = new Date().getTime() - start;
console.log(time.toString());
start = new Date().getTime();
console.log(start.toString());
let a = napitest.myAddThirtyThoundTimes(2, 3);
console.log(a.toString());
time = new Date().getTime() - start;
console.log(time.toString());
})
Text(this.message)
.fontSize(50)
.fontWeight(FontWeight.Bold)
.onClick(() => {
let start = new Date().getTime();
console.log(start.toString());
let a = napitest.myAddThirtyThoundTimes(2, 3);
console.log(a.toString());
let time = new Date().getTime() - start;
console.log(time.toString());
start = new Date().getTime();
console.log(start.toString());
let b = this.jsAddThirtyThoundTimes(2, 3);
console.log(b.toString());
time = new Date().getTime() - start;
console.log(time.toString());
})
}
.width('100%')
}
.height('100%')
}
}
运行
点击run,将应用安装到设备上
查看结果
分别点击上下两个Hello World
,可以看到日志有如下打印。可以看到同样是300000次运算,c++快了很多。
四、参考
NDK开发导读:https://docs.openharmony.cn/pages/v5.0/zh-cn/application-dev/napi/ndk-development-overview.md
Node-API简介:https://docs.openharmony.cn/pages/v5.0/zh-cn/application-dev/napi/napi-introduction.md
napi_generator简介:https://gitee.com/openharmony/napi/_generator
三方库移植之NAPI开发[1]—Hello OpenHarmony NAPI:https://blog.csdn.net/maniuT/article/details/137689680
更多推荐
所有评论(0)