1# Native与ArkTS对象绑定 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通过`napi_wrap`将ArkTS对象与Native的C++对象绑定,后续操作时再通过`napi_unwrap`将ArkTS对象绑定的C++对象取出,并对其进行操作。 12 13## 使用示例 14 151. 接口声明、编译配置以及模块注册 16 17 **接口声明** 18 19 ```ts 20 // index.d.ts 21 export class MyObject { 22 constructor(arg: number); 23 plusOne: () => number; 24 25 public get value(); 26 public set value(newVal: number); 27 } 28 ``` 29 30 **编译配置** 31 32 ``` 33 # the minimum version of CMake. 34 cmake_minimum_required(VERSION 3.5.0) 35 project(napi_wrap_demo) 36 37 set(NATIVERENDER_ROOT_PATH ${CMAKE_CURRENT_SOURCE_DIR}) 38 39 if(DEFINED PACKAGE_FIND_FILE) 40 include(${PACKAGE_FIND_FILE}) 41 endif() 42 43 include_directories(${NATIVERENDER_ROOT_PATH} 44 ${NATIVERENDER_ROOT_PATH}/include) 45 46 add_definitions("-DLOG_DOMAIN=0x0000") 47 add_definitions("-DLOG_TAG=\"testTag\"") 48 49 add_library(entry SHARED napi_init.cpp) 50 target_link_libraries(entry PUBLIC libace_napi.z.so libhilog_ndk.z.so) 51 ``` 52 53 **模块注册** 54 55 ```cpp 56 // napi_init.cpp 57 #include "napi/native_api.h" 58 #include "hilog/log.h" 59 60 class MyObject { 61 public: 62 static napi_value Init(napi_env env, napi_value exports); 63 static void Destructor(napi_env env, void* nativeObject, void* finalize_hint); 64 65 private: 66 explicit MyObject(double value_ = 0); 67 ~MyObject(); 68 69 static napi_value New(napi_env env, napi_callback_info info); 70 static napi_value GetValue(napi_env env, napi_callback_info info); 71 static napi_value SetValue(napi_env env, napi_callback_info info); 72 static napi_value PlusOne(napi_env env, napi_callback_info info); 73 74 double value_; 75 napi_env env_; 76 napi_ref wrapper_; 77 }; 78 79 static thread_local napi_ref g_ref = nullptr; 80 81 MyObject::MyObject(double value) 82 : value_(value), env_(nullptr), wrapper_(nullptr) {} 83 84 MyObject::~MyObject() 85 { 86 napi_delete_reference(env_, wrapper_); 87 } 88 89 void MyObject::Destructor(napi_env env, 90 void* nativeObject, 91 [[maybe_unused]] void* finalize_hint) 92 { 93 OH_LOG_INFO(LOG_APP, "MyObject::Destructor called"); 94 delete reinterpret_cast<MyObject*>(nativeObject); 95 } 96 97 napi_value MyObject::Init(napi_env env, napi_value exports) 98 { 99 napi_property_descriptor properties[] = { 100 { "value", 0, 0, GetValue, SetValue, 0, napi_default, 0 }, 101 { "plusOne", nullptr, PlusOne, nullptr, nullptr, nullptr, napi_default, nullptr } 102 }; 103 104 napi_value cons; 105 napi_define_class(env, "MyObject", NAPI_AUTO_LENGTH, New, nullptr, 2, 106 properties, &cons); 107 108 napi_create_reference(env, cons, 1, &g_ref); 109 napi_set_named_property(env, exports, "MyObject", cons); 110 return exports; 111 } 112 113 EXTERN_C_START 114 static napi_value Init(napi_env env, napi_value exports) 115 { 116 MyObject::Init(env, exports); 117 return exports; 118 } 119 EXTERN_C_END 120 121 static napi_module nativeModule = { 122 .nm_version = 1, 123 .nm_flags = 0, 124 .nm_filename = nullptr, 125 .nm_register_func = Init, 126 .nm_modname = "entry", 127 .nm_priv = nullptr, 128 .reserved = { 0 }, 129 }; 130 131 extern "C" __attribute__((constructor)) void RegisterObjectWrapModule() 132 { 133 napi_module_register(&nativeModule); 134 } 135 ``` 136 1372. 在构造函数中绑定ArkTS与C++对象 138 139 ```cpp 140 napi_value MyObject::New(napi_env env, napi_callback_info info) 141 { 142 OH_LOG_INFO(LOG_APP, "MyObject::New called"); 143 144 napi_value newTarget; 145 napi_get_new_target(env, info, &newTarget); 146 if (newTarget != nullptr) { 147 // 使用`new MyObject(...)`调用方式 148 size_t argc = 1; 149 napi_value args[1]; 150 napi_value jsThis; 151 napi_get_cb_info(env, info, &argc, args, &jsThis, nullptr); 152 153 double value = 0.0; 154 napi_valuetype valuetype; 155 napi_typeof(env, args[0], &valuetype); 156 if (valuetype != napi_undefined) { 157 napi_get_value_double(env, args[0], &value); 158 } 159 160 MyObject* obj = new MyObject(value); 161 162 obj->env_ = env; 163 // 通过napi_wrap将ArkTS对象jsThis与C++对象obj绑定 164 napi_status status = napi_wrap(env, 165 jsThis, 166 reinterpret_cast<void*>(obj), 167 MyObject::Destructor, 168 nullptr, // finalize_hint 169 &obj->wrapper_); 170 // napi_wrap失败时,必须手动释放已分配的内存,以防止内存泄漏 171 if (status != napi_ok) { 172 OH_LOG_INFO(LOG_APP, "Failed to bind native object to js object" 173 ", return code: %{public}d", status); 174 delete obj; 175 return jsThis; 176 } 177 // 从napi_wrap接口的result获取napi_ref的行为,将会为jsThis创建强引用, 178 // 若开发者不需要主动管理jsThis的生命周期,可直接在napi_wrap最后一个参数中传入nullptr, 179 // 或者使用napi_reference_unref方法将napi_ref转为弱引用。 180 uint32_t refCount = 0; 181 napi_reference_unref(env, obj->wrapper_, &refCount); 182 183 return jsThis; 184 } else { 185 // 使用`MyObject(...)`调用方式 186 size_t argc = 1; 187 napi_value args[1]; 188 napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); 189 190 napi_value cons; 191 napi_get_reference_value(env, g_ref, &cons); 192 napi_value instance; 193 napi_new_instance(env, cons, argc, args, &instance); 194 195 return instance; 196 } 197 } 198 ``` 199 2003. 将ArkTS对象之前绑定的C++对象取出,并对其进行操作 201 202 ```cpp 203 napi_value MyObject::GetValue(napi_env env, napi_callback_info info) 204 { 205 OH_LOG_INFO(LOG_APP, "MyObject::GetValue called"); 206 207 napi_value jsThis; 208 napi_get_cb_info(env, info, nullptr, nullptr, &jsThis, nullptr); 209 210 MyObject* obj; 211 // 通过napi_unwrap将jsThis之前绑定的C++对象取出,并对其进行操作 212 napi_unwrap(env, jsThis, reinterpret_cast<void**>(&obj)); 213 napi_value num; 214 napi_create_double(env, obj->value_, &num); 215 216 return num; 217 } 218 219 napi_value MyObject::SetValue(napi_env env, napi_callback_info info) 220 { 221 OH_LOG_INFO(LOG_APP, "MyObject::SetValue called"); 222 223 size_t argc = 1; 224 napi_value value; 225 napi_value jsThis; 226 227 napi_get_cb_info(env, info, &argc, &value, &jsThis, nullptr); 228 229 MyObject* obj; 230 // 通过napi_unwrap将jsThis之前绑定的C++对象取出,并对其进行操作 231 napi_unwrap(env, jsThis, reinterpret_cast<void**>(&obj)); 232 napi_get_value_double(env, value, &obj->value_); 233 234 return nullptr; 235 } 236 237 napi_value MyObject::PlusOne(napi_env env, napi_callback_info info) 238 { 239 OH_LOG_INFO(LOG_APP, "MyObject::PlusOne called"); 240 241 napi_value jsThis; 242 napi_get_cb_info(env, info, nullptr, nullptr, &jsThis, nullptr); 243 244 MyObject* obj; 245 // 通过napi_unwrap将jsThis之前绑定的C++对象取出,并对其进行操作 246 napi_unwrap(env, jsThis, reinterpret_cast<void**>(&obj)); 247 obj->value_ += 1; 248 napi_value num; 249 napi_create_double(env, obj->value_, &num); 250 251 return num; 252 } 253 ``` 254 2554. ArkTS侧示例代码 256 257 ```ts 258 import { hilog } from '@kit.PerformanceAnalysisKit'; 259 import { MyObject } from 'libentry.so'; 260 261 let object : MyObject = new MyObject(0); 262 object.value = 1023; 263 hilog.info(0x0000, 'testTag', 'MyObject value after set: %{public}d', object.value); 264 hilog.info(0x0000, 'testTag', 'MyObject plusOne: %{public}d', object.plusOne()); 265 ``` 266