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