[触觉智能RK3568使用体验]NAPI 类对象导出及其生命周期管理(下) 原创 精华
往期回顾:
三方库移植之NAPI开发[1]—Hello OpenHarmony NAPI
三方库移植之NAPI开发[2]C/C++与JS的数据类型转换
三方库移植之NAPI开发[4]异步调用:Callback&Promise
三方库移植之NAPI开发[5]NAPI 类对象导出及其生命周期管理(上)
目录
- 4. 样例工程源码剖析
- 4.1. NAPI导出对象和生命周期管理具体实现
- 4.1.1. 定义NapiTest类及方法
- 4.1.2 将NapiTest类定义为js类
- 4.1.3 导出js类
- 4.1.4 创建类的实例对象
- 4.2 index.d.ts声明文件编写
- 4.3 CMakeLists.txt文件
- 4.4 index.ets文件
- 知识点附送
4. 样例工程源码剖析
- 工程的模板是
Native C++
,模型是Stage
。 - 源码剖析主要围绕以下几个文件
4.1. NAPI导出对象和生命周期管理具体实现
4.1.1. 定义NapiTest类及方法
- Napi.h文件内容如下:
4.1.1.1 napi_value
-
Node.js Node-API的值用napi_value类型表示。
OpenHarmony NAPI将ECMAScript标准中定义的Boolean、Null、Undefined、Number、BigInt、String、Symbol和Object八种数据类型,以及函数对应的Function类型,统一封装成napi_value类型,下文中表述为JS类型,用于接收ArkUI应用传递过来的数据及返回数据给ArkUI应用。 -
这是一个不透明的指针,用于表示JavaScript值。
4.1.1.2 napi_ref
- 这是用来引用napi_value的抽象。这允许用户管理JavaScript值的生命周期,包括显式地定义它们的最小生命周期。
https://nodejs.org/docs/latest-v14.x/api/n-api.html#n_api_napi_ref
4.1.1.3 napi_env
- napi_env用于表示上下文,底层的Node-API实现可以使用该上下文持久保持VM-specific的状态。
https://nodejs.org/docs/latest-v14.x/api/n-api.html#n_api_napi_env
4.1.2 将NapiTest类定义为js类
4.1.2.1在定义js类之前,需要先设置js类对外导出的方法
4.1.2.1.1 napi_property_descriptor
参考 https://nodejs.org/docs/latest-v14.x/api/n-api.html#n_api_napi_property_descriptor
Node.js Node-API有一组API来获取和设置JavaScript对象的属性。在JavaScript中,属性被表示为一个键和一个值的元组。基本上,Node-API中的所有属性键都可以用以下形式中的任一一种表示:
- Named:一个简单的UTF-8编码的字符串
- Integer-Indexed:索引值,由uint32_t表示
- JavaScript value:在Node-API中通过napi_value表示。它可以是一个napi_value,表示字符串、数字或符号。
参数解析:
-
utf8name:在定义js类之前设置的js类对外导出的方法名字,编码为UTF8。必须为该属性提供utf8name或name中的一个。(utf8name和name其中一个必须是NULL)
-
name:可选的napi_value,指向一个JavaScript字符串或符号,用作属性的键。必须为该属性提供utf8name或name中的一个。
-
method:将属性描述符对象的value属性设置为method表示的JavaScript函数。如果传入这个参数,将value、getter和setter设置为NULL(因为这些成员不会被使用)。
-
attributes:与特定属性相关联的属性。
-
data:调用函数时传递给method、getter和setter的callback data。
4.1.2.2 定义与C++类相对应的JavaScript类
4.1.2.2.1 napi_define_class
napi_define_class
函数说明:
https://nodejs.org/docs/latest-v14.x/api/n-api.html#n_api_napi_define_class
功能:定义与C ++ 类相对应的JavaScript类。
参数说明:
- [in] env: 调用api的环境
- [in] utf8name: C ++ 类的名称
- [in] length: C ++ 类的名称的长度,默认自动长度使用
NAPI_AUTO_LENGTH
- [in] constructor: 处理C ++ 类实例构造的回调函数 (因为Constructor函数被napi_define_class调用了)。在导出C ++ 类对象时,这个函数必须是带有napi_callback签名(Constructor函数有napi_callback签名是指要满足typedef napi_value (*napi_callback)(napi_env, napi_callback_info);的形式)的静态成员。不能使用c ++ 的类构造函数。
- [in] data: 作为回调信息的数据属性传递给构造函数回调的可选数据
- [in] property_count: 属性数组中参数的个数
- [in] properties: 属性数组,具体看代码中napi_property_descriptor部分
- [out] result: 通过类构造函数绑定类实例的napi_value对象
返回:如果API调用成功返回napi_ok。
JS构造函数
如果一个js函数被使用new操作符来调用了,那么这个函数就称之为js构造函数
C++类回调函数
我们调用别人的API叫call,调用的第三方API调用我们的函数叫回调(callback)
4.1.2.3 实现js类的构造函数
当ArkTS应用在js端通过new方法获取类对象的时候,此时会调用 napi_define_class 中设置的 constructor 回调函数,该函数实现方法如下:
- NapiTest::Destructo方法是用来释放创建的对象:
4.1.2.3.1 napi_wrap
功能:将C++类实例绑定到js对象,并关联对应的生命周期
参数说明:
- [in] env: 调用api的环境
- [in] js_object: 绑定native_object的js对象
- [in] native_object: C++类实例对象
- [in] finalize_cb: 释放实例对象的回调函数
- [in] finalize_hint: 传递给回调函数的数据
- [out] result: 绑定js对象的引用
返回:调用成功返回0,失败返回其他
4.1.2.3.2 napi_get_cb_info
NAPI提供了napi_get_cb_info()方法可从napi_callback_info中获取参数列表、this及其他数据。这个方法在constructor回调函数中使用,从给定的回调信息中检索有关调用的详细信息,如参数和This指针。
参数说明:
- [in] env: 传入接口调用者的环境,包含js引擎等,由框架提供,默认情况下直接传入即可
- [in] cbinfo: napi_callback_info对象,上下文的信息
- [in-out] argc: argv数组的长度。若napi_callback_info中实际包含的参数的个数大于请求的数量argc,将只复制argc的值所指定数量的参数只argv中。若实际的参数个数小于请求的数量,将复制全部的参数,数组多余的空间用空值填充,并将参数实际长度写入argc。
- [out] argv: 用于接收参数列表
- [out] this_arg: 用于接收this对象
- [out] data: NAPI的上下文数据 返回值:返回napi_ok表示转换成功,其他值失败。下面的返回napi_status方法一样。
4.1.3 导出js类
4.1.3.1 在设置js类导出前,需要先创建生命周期
- constructor 定义js类时返回的代表类的构造函数的数据
- sConstructor_ 生命周期变量
4.1.3.1.1 napi_create_reference
napi_create_reference
为对象创建一个reference,以延长其生命周期。调用者需要自己管理reference生命周期。
napi_create_reference函数说明:
功能:通过引用对象创建新的生命周期引用对象
- [in] env: 调用 API 的环境
- [in] value: napi_value表示我们要引用的对象
- [in] initial_refcount: 生命周期变量的初始引用计数
- [out] result: 新建的生命周期引用对象
返回 napi_ok 这个API就是成功的.
4.1.3.2 将生命周期变量作为导出对象的传入属性,并将js类导出到exports中
4.1.3.2.1 napi_set_named_property
为给定对象的属性设置一个名称。
- [in] env: 调用API的环境
- [in] object: NapiTest对象相关属性要绑定的属性值
- [in] utf8Name: js类的名称
- [in] value: 要引用的对象
返回 napi_ok 则这个API是成功的
4.1.3.3 设置导出对象的属性
hello.cpp中
4.1.3.3.1 napi_define_properties
https://nodejs.org/docs/latest-v14.x/api/n-api.html#n_api_napi_define_properties
作用:批量的向给定Object中定义属性
- [in] env: 调用api的环境
- [in] object: js对象相关属性的导出变量
- [in] property_count: 属性数组中的元素数
- [in] properties: 属性数组
4.1.4 创建类的实例对象
- ArkTS应用除了调用new方法获取类的实例外,我们也可以提供一些方法让ArkTS应用获取对应的类的实例,如在我们的NapiTest类中,定义了一个Create方法,该方法实现了NapiTest类实例的获取。具体实现如下:
- 在napi接口的注册中将该方法以接口的方式导出,应用层就可以直接调用该接口并获取到该类的实例对。
特别说明:如果单独实现了一个类实例获取的方法,那么js的类构造函数可以不实现(也就是定义js结构体时实际的构建函数
Constructor及释放资源的函数
Destructor的代码够可以不写)
4.1.4.1 napi_get_reference_value
https://nodejs.org/docs/latest-v14.x/api/n-api.html#n_api_napi_get_reference_value
函数说明:
- 作用:获取与reference相关联的js对象
- [in] env: 调用API的环境
- [in] ref: 生命周期管理的变量
- [out] result: 对象引用的reference.
4.1.4.2 napi_new_instance
https://nodejs.org/docs/latest-v14.x/api/n-api.html#n_api_napi_new_instance
- 作用:通过给定的构造函数,构建一个对象
- [in] env: 调用API的环境
- [in] cons: napi_value表示要作为构造函数调用的 JavaScript 函数
- [in] argc: argv 数组中的元素计数
- [in] argv: JavaScript 值数组,表示构造函数的参数napi_value。
- [out] result: napi_value表示返回的 JavaScript 对象
4.2 index.d.ts声明文件编写
使用NAPI框架代码生成工具,可以根据.h生成.d.ts
https://gitee.com/openharmony/napi_generator/blob/master/docs/INSTRUCTION_ZH.md
也可以写成
楼主解读辛苦了
学无止境
引用链接整理的很全,收藏一下
对整个NAPI讲的不错