• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# 使用Node-API进行class相关开发
2<!--Kit: NDK-->
3<!--Subsystem: arkcompiler-->
4<!--Owner: @xliu-huanwei; @shilei123; @huanghello-->
5<!--Designer: @shilei123-->
6<!--Tester: @kirl75; @zsw_zhushiwei-->
7<!--Adviser: @fang-jinxu-->
8
9## 简介
10
11使用Node-API接口进行class相关开发,处理ArkTS中的类,例如定义类、构造实例等。
12
13## 基本概念
14
15在使用Node-API接口进行class相关开发时,需要理解以下基本概念:
16
17- **类**:类是用于创建对象的模板。它提供了一种封装数据和行为的方式,以便于对数据进行处理和操作。类在ArkTS中是建立在原型(prototype)的基础上的,并且还引入了一些类独有的语法和语义。
18- **实例**:实例是通过类创建具体的对象。类定义了对象的结构和行为,而实例则是类的具体表现。通过实例化类,我们可以访问类中定义的属性和方法,并且每个实例都具有自己的属性值。
19
20## 场景和功能介绍
21
22以下Node-API接口主要用于处理class。他们的使用场景如下:
23| 接口 | 描述 |
24| -------- | -------- |
25| napi_new_instance | 需要通过给定的构造函数构建一个实例时,可以使用这个函数。 |
26| napi_get_new_target | 使用此函数获取构造函数调用的new.target。 |
27| napi_define_class | 在Node-API模块定义与ArkTS类相对应的类。这个函数允许将Node-API模块类绑定到ArkTS类。 |
28| napi_wrap | 在ArkTS对象上绑定一个Node-API模块对象实例。这个函数通常在将Node-API模块对象与ArkTS对象进行绑定时使用,以便在ArkTS中使用本地对象的方法和属性。 |
29| napi_unwrap | 从ArkTS对象上获取之前绑定的Node-API模块对象实例。 |
30| napi_remove_wrap | 从ArkTS对象上获取之前绑定的Node-API模块对象实例,并解除绑定。 |
31
32## 使用示例
33
34Node-API接口开发流程参考[使用Node-API实现跨语言交互开发流程](use-napi-process.md),本文仅对接口对应C++及ArkTS相关代码进行展示。
35
36### napi_new_instance
37
38通过给定的构造函数实例化一个对象,将这个对象返回ArkTS侧使用。
39
40> **说明:**
41>
42> 参数constructor不是function类型则返回napi_function_expected。
43
44cpp部分代码
45
46```cpp
47static napi_value NewInstance(napi_env env, napi_callback_info info)
48{
49    // 传入并解析参数,第一个参数为传入的构造函数,第二个参数为需要传入构造函数的参数
50    size_t argc = 2;
51    napi_value args[2] = {nullptr};
52    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
53    // 调用napi_new_instance接口,实例化一个对象,将这个对象返回
54    napi_value result = nullptr;
55    napi_new_instance(env, args[0], 1, &args[1], &result);
56    return result;
57}
58```
59<!-- @[napi_new_instance](https://gitcode.com/openharmony/applications_app_samples/blob/master/code/DocsSample/ArkTS/NodeAPI/NodeAPIUse/NodeAPIClass/entry/src/main/cpp/napi_init.cpp) -->
60
61接口声明
62
63```ts
64// index.d.ts
65export const newInstance: (obj: Object, param: string) => Object;
66```
67<!-- @[napi_new_instance_api](https://gitcode.com/openharmony/applications_app_samples/blob/master/code/DocsSample/ArkTS/NodeAPI/NodeAPIUse/NodeAPIClass/entry/src/main/cpp/types/libentry/Index.d.ts) -->
68
69ArkTS侧示例代码
70
71```ts
72import { hilog } from '@kit.PerformanceAnalysisKit';
73import testNapi from 'libentry.so';
74class Fruit {
75  name: string;
76  constructor(name: string) {
77    this.name = name;
78  }
79}
80// 调用函数,用变量obj接收函数返回的实例化对象
81let obj = testNapi.newInstance(Fruit, 'test');
82// 打印实例化对象obj的信息
83hilog.info(0x0000, 'Node-API', 'napi_new_instance %{public}s', JSON.stringify(obj));
84```
85<!-- @[ark_napi_new_instance](https://gitcode.com/openharmony/applications_app_samples/blob/master/code/DocsSample/ArkTS/NodeAPI/NodeAPIUse/NodeAPIClass/entry/src/main/ets/pages/Index.ets) -->
86
87### napi_get_new_target
88
89用于获取构造函数的new.target值。在ArkTS中,new.target是一个特殊的元属性,用于在构造函数中判断是否通过new关键字调用了该构造函数。
90
91示例代码可以参考链接:
92
93[Native与ArkTS对象绑定](use-napi-object-wrap.md)
94
95### napi_define_class
96
97用于定义一个ArkTS类。该函数允许在Node-API模块中创建一个ArkTS类,并将类的方法和属性与相应的Node-API模块关联起来。
98
99示例代码可以参考链接:
100
101[Native与ArkTS对象绑定](use-napi-object-wrap.md)
102
103### napi_wrap
104
105在ArkTS object上绑定一个native对象实例。
106
107> **说明:**
108>
109> 参数js_object不为object类型或function类型时返回napi_object_expected。
110
111### napi_unwrap
112
113从一个被包装的对象中解除包装并获取与之关联的数据指针。
114
115> **说明:**
116>
117> 参数js_object不为object类型或function类型时返回napi_object_expected。
118
119### napi_remove_wrap
120
121从ArkTS object上获取先前绑定的native对象实例,并解除绑定。
122
123> **说明:**
124>
125> 参数js_object不为object类型或function类型时返回napi_object_expected。
126
127cpp部分代码
128
129```cpp
130#include <hilog/log.h>
131#include <string>
132#include "napi/native_api.h"
133
134static constexpr int INT_ARG_18 = 18; // 年龄18岁
135
136struct Object {
137    std::string name;
138    int32_t age;
139};
140
141static void DerefItem(napi_env env, void *data, void *hint) {
142    // 可选的原生回调,用于在ArkTS对象被垃圾回收时释放原生实例
143    OH_LOG_INFO(LOG_APP, "Node-API DerefItem");
144    Object *obj = reinterpret_cast<Object *>(data);
145    if (obj != nullptr) {
146        delete obj;
147    }
148}
149
150static napi_value Wrap(napi_env env, napi_callback_info info)
151{
152    OH_LOG_INFO(LOG_APP, "Node-API wrap");
153    // 初始化Node-API模块的object
154    struct Object *obj = new struct Object();
155    obj->name = "liLei";
156    obj->age = INT_ARG_18;
157    size_t argc = 1;
158    napi_value toWrap;
159    // 调用napi_wrap将Node-API模块的object绑定到ArkTS object上
160    napi_status status_cb = napi_get_cb_info(env, info, &argc, &toWrap, NULL, NULL);
161    if (status_cb != napi_ok) {
162        OH_LOG_ERROR(LOG_APP, "napi_get_cb_info failed");
163        delete obj;
164        return nullptr;
165    }
166    napi_status status = napi_wrap(env, toWrap, reinterpret_cast<void *>(obj), DerefItem, NULL, NULL);
167    if (status != napi_ok) {
168        // 主动释放内存
169        delete obj;
170    }
171
172    return toWrap;
173}
174
175static napi_value RemoveWrap(napi_env env, napi_callback_info info)
176{
177    OH_LOG_INFO(LOG_APP, "Node-API removeWrap");
178    size_t argc = 1;
179    napi_value wrapped = nullptr;
180    void *data = nullptr;
181    // 调用napi_remove_wrap从一个被包装的对象中解除包装
182    napi_get_cb_info(env, info, &argc, &wrapped, nullptr, nullptr);
183    napi_remove_wrap(env, wrapped, &data);
184    return nullptr;
185}
186
187static napi_value UnWrap(napi_env env, napi_callback_info info)
188{
189    OH_LOG_INFO(LOG_APP, "Node-API unWrap");
190    size_t argc = 1;
191    napi_value wrapped = nullptr;
192    napi_get_cb_info(env, info, &argc, &wrapped, nullptr, nullptr);
193    // 调用napi_unwrap取出绑定在ArkTS object中的数据并打印
194    struct Object *data = nullptr;
195    napi_status status = napi_unwrap(env, wrapped, reinterpret_cast<void **>(&data));
196    if (status != napi_ok || data == nullptr) {
197        OH_LOG_ERROR(LOG_APP, "Node-API napi_unwrap failed or data is nullptr");
198        return nullptr;
199    }
200    OH_LOG_INFO(LOG_APP, "Node-API name: %{public}s", data->name.c_str());
201    OH_LOG_INFO(LOG_APP, "Node-API age: %{public}d", data->age);
202    return nullptr;
203}
204```
205<!-- @[napi_wrap_unwrap_remove_wrap](https://gitcode.com/openharmony/applications_app_samples/blob/master/code/DocsSample/ArkTS/NodeAPI/NodeAPIUse/NodeAPIClass/entry/src/main/cpp/napi_init.cpp) -->
206
207接口声明
208
209```ts
210// index.d.ts
211export const wrap: (obj: Object) => Object;
212export const unWrap: (obj: Object) => void;
213export const removeWrap: (obj: Object) => void;
214```
215<!-- @[napi_wrap_unwrap_remove_wrap_api](https://gitcode.com/openharmony/applications_app_samples/blob/master/code/DocsSample/ArkTS/NodeAPI/NodeAPIUse/NodeAPIClass/entry/src/main/cpp/types/libentry/Index.d.ts) -->
216
217ArkTS侧示例代码
218
219```ts
220import { hilog } from '@kit.PerformanceAnalysisKit';
221import testNapi from 'libentry.so';
222try {
223    class Obj {}
224    let obj: Obj = {};
225    testNapi.wrap(obj)
226    testNapi.unWrap(obj)
227    testNapi.removeWrap(obj)
228} catch (error) {
229    hilog.error(0x0000, 'testTag', 'Test Node-API error: %{public}s', error.message);
230}
231```
232<!-- @[ark_napi_wrap_unwrap_remove_wrap](https://gitcode.com/openharmony/applications_app_samples/blob/master/code/DocsSample/ArkTS/NodeAPI/NodeAPIUse/NodeAPIClass/entry/src/main/ets/pages/Index.ets) -->
233
234以上代码如果要在native cpp中打印日志,需在CMakeLists.txt文件中添加以下配置信息(并添加头文件:#include "hilog/log.h"):
235
236```text
237// CMakeLists.txt
238add_definitions( "-DLOG_DOMAIN=0xd0d0" )
239add_definitions( "-DLOG_TAG=\"testTag\"" )
240target_link_libraries(entry PUBLIC libace_napi.z.so libhilog_ndk.z.so)
241```
242