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