• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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