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

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

3天内不再提示

【润和软件DAYU200开发板体验】三方库移植之NAPI开发[1]—Hello OpenHarmony NAPI

开发板试用精选 来源:开发板试用 作者:电子发烧友论坛 2022-10-12 10:38 次阅读

本文来源电子发烧友社区,作者:离北况归, 帖子地址:https://bbs.elecfans.com/jishu_2308792_1_1.html


本文通过一个Hello OpenHarmony NAPI样例讲述了NPAI接口开发基础知识。开发基于最新的OpenHarmony3.2Beta3版本及其对应SDK。标准系统开发板为润和软件dayu200。(附开发板体验完整视频,详见作者原帖子)

将C/C++ 三方库移植到OpenHarmony标准系统后,需要通过NAPI框架将其C/C++ 接口转换成JS/ETS接口给应用层调用。


通过本文您将熟悉

  • 如何注册NAPI模块及接口。

  • 如何在ArkUI eTS代码中调用扩展的NAPI接口。

  • full-SDK的替换。

    什么是NAPI

  • NAPI(Native API)组件是一套对外接口基于Node.js N-API规范开发的原生模块扩展开发框架。

image.png

  • OpenHarmony 标准系统应用开发基于ArkUI框架,开发语言使用JS/eTS。部分业务场景依赖使用现有的C/C++ 库,或为了获取更高的性能。OpenHarmony提供NAPI机制,用于规范封装IO、CPU密集型、OS底层等能力并对外暴露JS接口,通过NAPI实现JS和C/C++代码的互相访问.

    • 例如: 钟禄平和林嘉诚老师在如何在OpenHarmony上使用SeetaFace2人脸识别库?一文中,重点讲解了NAPI接口如何实现OpenCV以及SeetaFace的调用。一句话概括就是,钟禄平和林嘉诚老师讲述了移植了三方库后通过NAPI将库的C/C++接口变成JS/ETS接口给应用层调用。
  • 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自定义子系统、组件、模块

  • 这部分内容涉及三方库移植,为便于本篇NAPI基础的学习。笔者在此自定义一个子系统用于开发NAPI。如在已存在的子系统组件中添加扩展NAPI,则跳过此步。
  • 需要准备好OpenHarmonyBeta3源码和编译环境

添加子系统、组件

直接在OpenHarmony源码根目录创建子系统文件夹,取名mysubsys。并在目录下添加子系统的构建配置文件ohos.build
完整内容如下:

{
  "subsystem": "mysubsys",
  "parts": {
    "hello": {
      "module_list": [
        "//mysubsys/hello/hellonapi:hellonapi"
      ],
      "inner_kits": [
      ],
      "system_kits": [
      ],
      "test_list": [
      ]
    }
  }
}
  • 另外ohos.build里面不支持加注释,后面编译的时候会莫名其妙报错。别问,问就是笔者踩过坑了。(好像也没必要加注释)
    image.png
    需要明白以下知识点:
"subsystem": "mysubsys",
  • subsystem后面的mysubsy是子系统的名称。
"parts": {
    "hello": {
   }
  }
  • hello是组件名称,被mysubsys子系统包含
"module_list": [
        "//mysubsys/hello/hellonapi:hellonapi"
  • hellonapi是模块名,被hello组件包含。

接着将子系统配置到源码下buildsubsystem_config.json文件,在该文件中插入如下内容。

"mysubsys": {
    "project": "hmf/mysubsys",
    "path": "mysubsys",
    "name": "mysubsys",
    "dir": ""
  }
  • OpenHarmony系统架构中,子系统是一个逻辑概念,它具体由对应的组件构成。组件是对子系统的进一步拆分,可复用的软件单元,它包含源码、配置文件、资源文件和编译脚本;能独立构建,以二进制方式集成,具备独立验证能力的二进制单元。

本示例按子系统system > 组件part > 组件module 创建了3级目录

mysubsys                    -- 子系统目录
├── hello
│   └── hellonapi           -- 组件目录
│       ├── BUILD.gn
│       └── hellonapi.cpp   -- 组件module目录
└── ohos.build

源码实现

最后在组件目录下中创建代码文件hellonapi.cpp

完整内容如下:

#include 
#include "napi/native_node_api.h"
#include "napi/native_api.h"

//接口业务实现C/C++代码
//std::string 需要引入string头文件,#include 
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.指定模块注册对外接口的处理函数,具体扩展的接口在该函数中声明
static napi_value registerFunc(napi_env env, napi_value exports)
{
    static napi_property_descriptor desc[] = {
        // 声明该napi_module对外具体的提供的API
        DECLARE_NAPI_FUNCTION("getHelloString", getHelloString),
    };
    NAPI_CALL(env, napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc));
    return exports;
}

// 1.先定义napi_module,指定当前NAPI模块对应的模块名
//以及模块注册对外接口的处理函数,具体扩展的接口在该函数中声明
// nm_modname: 模块名称,对应eTS代码为import nm_modname from '@ohos.ohos_shared_library_name'
//示例对应eTS代码为:import hellonapi from '@ohos.hellonapi'
static napi_module hellonapiModule = {
    .nm_version = 1,
    .nm_flags = 0,
    .nm_filename = nullptr,
    .nm_register_func = registerFunc, // 模块对外接口注册函数
    .nm_modname = "hellonapi",  // 自定义模块名
    .nm_priv = ((void*)0),
    .reserved = { 0 },
};

//3.模块定义好后,调用NAPI提供的模块注册函数napi_module_register(napi_module* mod)函数注册到系统中。
// register module,设备启动时自动调用此constructor函数,把模块定义的模块注册到系统中
extern "C" __attribute__((constructor)) void hellonapiModuleRegister()
{
    napi_module_register(&hellonapiModule);
}

代码解析如下:

接口业务实现C/C++代码

// std::string 需要引入string头文件,#include 
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接口头文件

NAPI提供了提供了一系列接口函数,声明包含如下2个头文件中,先添加这2个头文件到hellonapi.cpp

#include "napi/native_api.h"
#include "napi/native_node_api.h"
  • native_api.h和native_node_api.h这两个头文件
    • 在OpenHarmony-3.1-release源码下是在//foundation/ace/napi/interfaces/kits目录下
    • 在3.2beta3版本中分别在//foundation/arkui/napi/interfaces/kits和//foundation/arkui/napi/interfaces/inner_api目录下了。

image.png

注册NAPI模块、添加接口声明

定义的hellonapi模块,其对应结构体为napi_module。

  • 指定当前NAPI模块对应的模块名以及模块注册对外接口的处理函数,具体扩展的接口在该函数中声明。
// 定义napi_module
// nm_modname: 模块名称,对应eTS代码为import nm_modname from '@ohos.ohos_shared_library_name'
// 示例对应eTS代码为:import hellonapi from '@ohos.hellonapi'
static napi_module hellonapiModule = {
    .nm_version = 1,
    .nm_flags = 0,
    .nm_filename = nullptr,
    .nm_register_func = registerFunc, // 模块对外接口注册函数
    .nm_modname = "hellonapi",  // 自定义模块名
    .nm_priv = ((void*)0),
    .reserved = { 0 },
};
  • NAPI提供DECLARE_NAPI_FUNCTION(name, func)函数用于声明api,传入名称和其他实现函数。在registerFunc函数中添加DECLARE_NAPI_FUNCTION,本例添加了一个getString接口。
  • 模块定义好后,调用NAPI提供的模块注册函数napi_module_register(napi_module* mod)函数注册到系统中。
// napi_addon_register_func
static napi_value registerFunc(napi_env env, napi_value exports)
{
    static napi_property_descriptor desc[] = {
        // 声明该napi_module对外具体的提供的API
        DECLARE_NAPI_FUNCTION("getHelloString", getHelloString),
    };
    NAPI_CALL(env, napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc));
    return exports;
}

自定义子系统构建

hellonapi编译gn化,新增gn工程构建脚本。

在模块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。

  • 插入位置任意,但要注意行尾的逗号,确保格式json文件格式正确。
"parts":{
    ...
    "mysubsys:hello":{},
    ...
  }
  • mysubsys是本示例自定义的子系统名称
  • hello是自定义子系统下的组件名称
  • parts格式如下:
"parts":{
        "部件所属子系统名:部件名":{}
    }

修改build/subsystem_config.json

新增子系统定义。

  • subsystem_config.json文件定义了有哪些子系统以及这些子系统所在文件夹路径,添加子系统时需要说明子系统path与name,分别表示子系统路径和子系统名。

注意json文件也不支持注释!!!

"mysubsys": {
    "project": "hmf/mysubsys",
    "path": "mysubsys",
    "name": "mysubsys"
}

修改vendor/hihope/rk3568/config.json文件

将mysubsys子系统添加至rk3568开发板,在vendor目录下新增产品的定义。

{
      "subsystem": "mysubsys",
      "components": [
        {
          "component": "hello",
          "features": []
        }
      ]
    }

编译烧录

先进行增量编译出子系统的动态库,增量编译没有报错后。再全量编译出镜像,将其烧录到开发板上

  • 增量编译命令
./build.sh --product-name rk3568 --ccache --build-target=hellonapi --target-cpu arm64

image.png

  • 全量编译和烧录
    这部分的内容不重复叙述,大家可以参考社区文章。

镜像文件在源码目录下位置如下:
image.png

调用接口

full-SDK替换(可选)

从OpenHarmony 3.2 Beta2起,SDK会同时提供Public SDK和Full SDK。通过DevEco Studio默认获取的SDK为Public SDK。
两者差异如下

  • Public SDK
    • 面向应用开发者提供,不包含需要使用系统权限的系统接口。通过DevEco Studio默认获取的SDK为Public SDK。
  • Full SDK
    • 面向OEM厂商提供,包含了需要使用系统权限的系统接口。使用Full SDK时需要手动从镜像站点获取,并在DevEco Studio中替换

笔者使用的DevEco Studio版本为3.0.0.993,即DevEco Studio 3.0。API为API9。
image.png
image.png

full-SDK替换请参考官方文档:full-SDK替换指南

若提示找不到npm,需要配置一下环境变量,将以下路径添加到环境变量中即可
image.png

image.png

D:DevEco Studioohossdketsbuild-toolsets-loader

image.png

创建OpenHarmony标准应用

新建项目,选择OpenHarmony。
image.png
compile sdk选择9,其他保持默认即可。
image.png

插一句题外话,3.1release版本发布的时候。华为是把DevEco Studio分成了OpenHarmony和HarmonyOS两个版本的,现在又合并到一起了。

image.png
image.png

调用接口

  • 调用方式和ArkUI框架提供的API一样,先import引入扩展的NAPI模块,后直接调用。

image.png

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(() => {
        // 调用getHelloString接口
        let strFromNAPI = hellonapi.getHelloString()
        prompt.showToast({ message: strFromNAPI })
      })
    }
    .width('100%')
    .height('100%')
  }
}

然后选择自动签名
image.png

image.png

将应用安装到dayu200开发板上
image.png

运行效果如下:
动画2.gif

  • 也可以参考其他模块的.d.ts创建扩展模块@ohos.hellonapi.d.ts定义文件,放到IDE安装OpenHarmony SDK的目录路径ohossdkets3.2.7.5api下。
    • .d.ts文件的命名为@ohos.ohos_shared_library_name.d.ts,ohos_shared_library为BUID.gn文件中定义的动态库名称image.png

@ohos.hellonapi.d.ts内容如下:

declare namespace hellonapi {
	function getHelloString(): string;
    /**
     * 
     *
     * @since 9
     * @syscap SystemCapability.HiviewDFX.HiAppEvent
     */

}
export default hellonapi;
  • 其中@syscap SystemCapability.HiviewDFX.HiAppEvent语句在.d.ts文件中一定要添加,否则IDE还是会报错找不到该文件。
  • 其中declare namespace hellonapi的hellonapi是BUILD.gn中的定义的ohos_shared_library_name。
  • 其中function getHelloString(): string;中的getHelloString()是hellonapi.cpp文件中指定的模块注册对外接口的处理函数

IDE问题扫描如下:
image.png

如果不新建@ohos.hellonapi.d.ts放在sdkets3.2.7.5api,则IDE会报错
image.png

标准应用编译不是强依赖OpenHarmony SDK,所以可忽略IDE中告警,直接编译打包hap。但是有的时候IDE会提示找不到@ohos.hellonapi.d.ts,然后有小概率的机会无法安装hap。这个时候就要参考ohossdkets3.2.7.5api下的.d.ts文件编写@ohos.hellonapi.d.ts了。

知识点附送

Native API中支持的标准库

表1OpenHarmony支持的标准库

名称 简介
标准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 图形处理硬件指定标准的软件接口。
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • dayu200
    +关注

    关注

    1

    文章

    26

    浏览量

    1187
  • 润和软件
    +关注

    关注

    1

    文章

    260

    浏览量

    860
收藏 人收藏

    评论

    相关推荐

    【RA8D1试用活动】RA8D1B-CPKCOR开发板移植linux

    【RA8D1试用活动】RA8D1B-CPKCOR开发板移植linux
    的头像 发表于 11-16 01:02 173次阅读
    【RA8D<b class='flag-5'>1</b>试用活动】RA8D<b class='flag-5'>1</b>B-CPKCOR<b class='flag-5'>开发板</b><b class='flag-5'>移植</b>linux

    瑞芯微RK3566鸿蒙开发板Android11修改第三方输入法为默认输入法

    本文适用于触觉智能所有支持Android11系统的开发板修改第三方输入法为默认输入法。本次使用的是触觉智能的Purple Pi OH鸿蒙开源主板,搭载了瑞芯微RK3566芯片,类树莓派设计,是Laval官方社区主荐的一款鸿蒙开发板
    的头像 发表于 09-24 09:43 371次阅读
    瑞芯微RK3566鸿蒙<b class='flag-5'>开发板</b>Android11修改第<b class='flag-5'>三方</b>输入法为默认输入法

    Openharmony软件评估指南-米尔瑞芯微RK3568开发板

    MYD-LR3568开发板正面 图1-2. 米尔MYD-LR3568开发板反面 1.软件资源米尔米粉派3568系列
    发表于 09-06 20:06

    开鸿“龙芯+OpenHarmony开发平台DAYU431先锋派新品发布

    开鸿基于全新龙芯2K0300芯片平台的重磅新品开鸿HH-SCDAYU431先锋派开发平台正式上市,成为开鸿DAYU系列产品中符合
    的头像 发表于 08-07 14:50 479次阅读
    <b class='flag-5'>润</b>开鸿“龙芯+<b class='flag-5'>OpenHarmony</b>”<b class='flag-5'>开发</b>平台<b class='flag-5'>DAYU</b>431先锋派新品发布

    鸿蒙OpenHarmony【标准系统编写“Hello World”程序】 (基于RK3568开发板

    源码],创建RK3568开发板的源码工程。 示例目录 拉取openharmony项目代码,在代码根目录创建sample子系统文件夹,在子系统目录下创建hello部件文件夹,hello
    的头像 发表于 04-24 17:32 725次阅读
    鸿蒙<b class='flag-5'>OpenHarmony</b>【标准系统编写“<b class='flag-5'>Hello</b> World”程序】 (基于RK3568<b class='flag-5'>开发板</b>)

    鸿蒙OpenHarmony【集成三方SDK】 (基于Hi3861开发板

    OpenHarmony致力于打造一套更加开放完善的IoT生态系统,为此OpenHarmony规划了一组目录,用于将各厂商的SDK集成到OpenHarmony中。本文档基于Hi3861开发板
    的头像 发表于 04-24 15:11 1066次阅读
    鸿蒙<b class='flag-5'>OpenHarmony</b>【集成<b class='flag-5'>三方</b>SDK】 (基于Hi3861<b class='flag-5'>开发板</b>)

    OpenHarmony鸿蒙南向开发案例:【智能猫眼(基于Hi3518开发板)】

    基于Hi3518开发板,使用开源OpenHarmony开发的RTSP协议流媒体应用。达到将Hi3518开发板中摄像头获取的数据通过RTSP协议传输到手机并显示 。
    的头像 发表于 04-22 15:46 1962次阅读
    <b class='flag-5'>OpenHarmony</b>鸿蒙南向<b class='flag-5'>开发</b>案例:【智能猫眼(基于Hi3518<b class='flag-5'>开发板</b>)】

    OpenHarmony鸿蒙南向开发案例:【智能猫眼(基于3516开发板)】

    基于Hi3516开发板,使用开源OpenHarmony开发的RTSP协议流媒体应用。达到将Hi3516开发板中摄像头获取的数据通过RTSP协议传输到手机并显示 。
    的头像 发表于 04-19 22:01 564次阅读
    <b class='flag-5'>OpenHarmony</b>鸿蒙南向<b class='flag-5'>开发</b>案例:【智能猫眼(基于3516<b class='flag-5'>开发板</b>)】

    移植libmodbus到米尔-全志T113-i开发板

    测试开发板在工业领域的应用,modbus作为工业领域的一个重要协议,那好就移植libmodbus
    的头像 发表于 03-05 22:37 2350次阅读
    <b class='flag-5'>移植</b>libmodbus<b class='flag-5'>库</b>到米尔-全志T113-i<b class='flag-5'>开发板</b>

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

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

    请问DAYU200有SPI可以用么

    大家好,请问DAYU200有SPI可以用么 我看这里https://developer.huawei.com/consumer/cn/market/prod-detail?productId
    发表于 02-20 11:38

    OpenHarmony NAPI 框架介绍

    环境中的 JS 变量与方法。 OpenHarmony 中的 NAPI OpenAtom OpenHarmony(以下简称 “OpenHarmony”)应用层基于 javascript
    的头像 发表于 02-01 17:34 673次阅读
    <b class='flag-5'>OpenHarmony</b> <b class='flag-5'>之</b> <b class='flag-5'>NAPI</b> 框架介绍

    开源大师兄开发板通过 OpenHarmony 3.2 Release版本兼容性测评

    近期,江苏开鸿数字科技有限公司(以下简称“开鸿”)开源⼤师兄开发板顺利通过OpenHarmony3.2.1Release版本兼容性测评,为基于开源大师兄
    的头像 发表于 01-20 08:02 871次阅读
    开源大师兄<b class='flag-5'>开发板</b>通过 <b class='flag-5'>OpenHarmony</b> 3.2 Release版本兼容性测评

    鸿蒙OpenHarmony NAPI技术-基础学习

    NAPI(Native API)是OpenHarmony系统中的一套原生模块扩展开发框架,它基于Node.js N-API规范开发,为开发
    的头像 发表于 01-19 16:57 937次阅读
    鸿蒙<b class='flag-5'>OpenHarmony</b> <b class='flag-5'>NAPI</b>技术-基础学习

    开鸿基于高性能RISC-V开源架构DAYU800通过OpenHarmony兼容性测评

    的重要一环。 开鸿基于高性能RISC-V开源架构的DAYU800开发平台OpenHarmony兼容性证书 开鸿
    发表于 12-14 17:33