1# Wrapping a Native Object in an ArkTS Object 2 3## When to Use 4 5You can use **napi_wrap** to wrap a C++ object in an ArkTS object, and use **napi_unwrap** to retrieve the C++ object previously wrapped in the ArkTS object for subsequent operations. 6 7## Example 8 91. Declare the APIs, configure compile settings, and register the modules. 10 11 **Declare the APIs.** 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 **Configure compile settings.** 25 26 ``` 27 // CMakeLists.txt 28 # Minimum version of CMake. 29 cmake_minimum_required(VERSION 3.4.1) 30 project(object_wrap) 31 32 set(NATIVERENDER_ROOT_PATH ${CMAKE_CURRENT_SOURCE_DIR}) 33 34 include_directories(${NATIVERENDER_ROOT_PATH} 35 ${NATIVERENDER_ROOT_PATH}/include) 36 37 add_definitions("-DLOG_DOMAIN=0x0000") 38 add_definitions("-DLOG_TAG=\"testTag\"") 39 40 add_library(object_wrap SHARED object_wrap.cpp) 41 target_link_libraries(object_wrap PUBLIC libace_napi.z.so libhilog_ndk.z.so) 42 ``` 43 44 **Register the module.** 45 46 ```cpp 47 // object_wrap.cpp 48 class MyObject { 49 public: 50 static napi_value Init(napi_env env, napi_value exports); 51 static void Destructor(napi_env env, void* nativeObject, void* finalize_hint); 52 53 private: 54 explicit MyObject(double value_ = 0); 55 ~MyObject(); 56 57 static napi_value New(napi_env env, napi_callback_info info); 58 static napi_value GetValue(napi_env env, napi_callback_info info); 59 static napi_value SetValue(napi_env env, napi_callback_info info); 60 static napi_value PlusOne(napi_env env, napi_callback_info info); 61 62 double value_; 63 napi_env env_; 64 napi_ref wrapper_; 65 }; 66 67 static thread_local napi_ref g_ref = nullptr; 68 69 MyObject::MyObject(double value) 70 : value_(value), env_(nullptr), wrapper_(nullptr) {} 71 72 MyObject::~MyObject() 73 { 74 napi_delete_reference(env_, wrapper_); 75 } 76 77 void MyObject::Destructor(napi_env env, 78 void* nativeObject, 79 [[maybe_unused]] void* finalize_hint) 80 { 81 OH_LOG_INFO(LOG_APP, "MyObject::Destructor called"); 82 reinterpret_cast<MyObject*>(nativeObject)->~MyObject(); 83 } 84 85 napi_value MyObject::Init(napi_env env, napi_value exports) 86 { 87 napi_property_descriptor properties[] = { 88 {"value", 0, 0, GetValue, SetValue, 0, napi_default, 0}, 89 { "plusOne", nullptr, PlusOne, nullptr, nullptr, nullptr, napi_default, nullptr } 90 }; 91 92 napi_value cons; 93 assert(napi_define_class(env, "MyObject", NAPI_AUTO_LENGTH, New, nullptr, 2, 94 properties, &cons) == napi_ok); 95 96 assert(napi_create_reference(env, cons, 1, &g_ref) == napi_ok); 97 assert(napi_set_named_property(env, exports, "MyObject", cons) == napi_ok); 98 return exports; 99 } 100 101 EXTERN_C_START 102 static napi_value Init(napi_env env, napi_value exports) 103 { 104 MyObject::Init(env, exports); 105 return exports; 106 } 107 EXTERN_C_END 108 109 static napi_module nativeModule = { 110 .nm_version = 1, 111 .nm_flags = 0, 112 .nm_filename = nullptr, 113 .nm_register_func = Init, 114 .nm_modname = "object_wrap", 115 .nm_priv = nullptr, 116 .reserved = { 0 }, 117 }; 118 119 extern "C" __attribute__((constructor)) void RegisterObjectWrapModule() 120 { 121 napi_module_register(&nativeModule); 122 } 123 ``` 124 1252. Wrap a C++ object in an ArkJS object in a constructor. 126 127 ```cpp 128 napi_value MyObject::New(napi_env env, napi_callback_info info) 129 { 130 OH_LOG_INFO(LOG_APP, "MyObject::New called"); 131 132 napi_value newTarget; 133 assert(napi_get_new_target(env, info, &newTarget) == napi_ok); 134 if (newTarget != nullptr) { 135 // Invoked as the constructor `new MyObject(...)`. 136 size_t argc = 1; 137 napi_value args[1]; 138 napi_value jsThis; 139 assert(napi_get_cb_info(env, info, &argc, args, &jsThis, nullptr) == napi_ok); 140 141 double value = 0.0; 142 napi_valuetype valuetype; 143 assert(napi_typeof(env, args[0], &valuetype) == napi_ok); 144 if (valuetype != napi_undefined) { 145 assert(napi_get_value_double(env, args[0], &value) == napi_ok); 146 } 147 148 MyObject* obj = new MyObject(value); 149 150 obj->env_ = env; 151 // Use napi_wrap to wrap the C++ object obj in the ArkTS object jsThis. 152 assert(napi_wrap(env, 153 jsThis, 154 reinterpret_cast<void*>(obj), 155 MyObject::Destructor, 156 nullptr, // finalize_hint 157 &obj->wrapper_) == napi_ok); 158 159 return jsThis; 160 } else { 161 // Invoked as the plain function `MyObject(...)`. 162 size_t argc = 1; 163 napi_value args[1]; 164 assert(napi_get_cb_info(env, info, &argc, args, nullptr, nullptr) == napi_ok && argc == 1); 165 166 napi_value cons; 167 assert(napi_get_reference_value(env, g_ref, &cons) == napi_ok); 168 napi_value instance; 169 assert(napi_new_instance(env, cons, argc, args, &instance) == napi_ok); 170 171 return instance; 172 } 173 } 174 ``` 175 1763. Retrieve the C++ object from the ArkTS object and perform subsequent operations on the C++ object. 177 178 ```cpp 179 napi_value MyObject::GetValue(napi_env env, napi_callback_info info) 180 { 181 OH_LOG_INFO(LOG_APP, "MyObject::GetValue called"); 182 183 napi_value jsThis; 184 assert(napi_get_cb_info(env, info, nullptr, nullptr, &jsThis, nullptr) == napi_ok); 185 186 MyObject* obj; 187 // Use napi_unwrap to retrieve obj (the C++ object) previously wrapped in jsThis (the ArkTS object), and perform subsequent operations. 188 assert(napi_unwrap(env, jsThis, reinterpret_cast<void**>(&obj)) == napi_ok); 189 napi_value num; 190 assert(napi_create_double(env, obj->value_, &num) == napi_ok); 191 192 return num; 193 } 194 195 napi_value MyObject::SetValue(napi_env env, napi_callback_info info) 196 { 197 OH_LOG_INFO(LOG_APP, "MyObject::SetValue called"); 198 199 size_t argc = 1; 200 napi_value value; 201 napi_value jsThis; 202 203 assert(napi_get_cb_info(env, info, &argc, &value, &jsThis, nullptr) == napi_ok); 204 205 MyObject* obj; 206 // Use napi_unwrap to retrieve obj (the C++ object) previously wrapped in jsThis (the ArkTS object), and perform subsequent operations. 207 assert(napi_unwrap(env, jsThis, reinterpret_cast<void**>(&obj)) == napi_ok); 208 assert(napi_get_value_double(env, value, &obj->value_) == napi_ok); 209 210 return nullptr; 211 } 212 213 napi_value MyObject::PlusOne(napi_env env, napi_callback_info info) 214 { 215 OH_LOG_INFO(LOG_APP, "MyObject::PlusOne called"); 216 217 napi_value jsThis; 218 assert(napi_get_cb_info(env, info, nullptr, nullptr, &jsThis, nullptr) == napi_ok); 219 220 MyObject* obj; 221 // Use napi_unwrap to retrieve obj (the C++ object) previously wrapped in jsThis (the ArkTS object), and perform subsequent operations. 222 assert(napi_unwrap(env, jsThis, reinterpret_cast<void**>(&obj)) == napi_ok); 223 obj->value_ += 1; 224 napi_value num; 225 assert(napi_create_double(env, obj->value_, &num) == napi_ok); 226 227 return num; 228 } 229 ``` 230 2314. The following provides the sample ArkTS code. 232 233 ```ts 234 import hilog from '@ohos.hilog'; 235 import { MyObject } from 'libobject_wrap.so' 236 237 let object : MyObject = new MyObject(0); 238 object.value = 1023; 239 hilog.info(0x0000, 'testTag', 'MyObject value after set: %{public}d', object.value); 240 hilog.info(0x0000, 'testTag', 'MyObject plusOne: %{public}d', object.plusOne()); 241 ``` 242