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