• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Using Node-API Extension APIs
2
3## Introduction
4
5The Node-API [extension APIs](napi-data-types-interfaces.md#extended-capabilities) extend Node-API functionalities and allow you to create custom ArkTS objects, which enable more flexible interaction between ArkTS and C/C++.
6
7If you are just starting out with Node-API, see [Node-API Development Process](use-napi-process.md). The following demonstrates only the C++ and ArkTS code involved in the Node-API extension APIs.
8
9## Module Loading
10
11### Available APIs
12
13| API| Description|
14| -------- | -------- |
15| napi_load_module | Loads an .abc file as a module. This API returns the namespace of the module. You can use it for the applications that need to dynamically load modules or resources in runtime.|
16| napi_load_module_with_info | Loads a module. After the module is loaded, you can use **napi_get_property** to obtain the variables exported by the module or use **napi_get_named_property** to obtain the functions exported by the module. The **napi_load_module_with_info** API can be used in a [newly created ArkTS runtime environment](use-napi-ark-runtime.md).|
17| napi_module_register | Registers a native module. Sometimes, you may need to implement certain functionalities using Node-API for better performance. You can use **napi_module_register** to customize the functionalities implemented using Node-API as a module and register it with ArkTS. This can improve the overall performance.|
18
19### Example
20
21#### napi_load_module
22
23Call **napi_load_module** to [load a module in the main thread](use-napi-load-module.md).
24
25#### napi_load_module_with_info
26
27Call **napi_load_module_with_info** to [load a module](use-napi-load-module-with-info.md).
28
29#### napi_module_register
30
31Call **napi_module_register** to register a custom module, which is implemented by using Node-API, with the ArkTS environment.
32
33CPP code:
34
35```cpp
36#include "napi/native_api.h"
37
38// This module is a Node-API callback function.
39static napi_value Add(napi_env env, napi_callback_info info)
40{
41    // Obtain the two parameters passed in.
42    size_t requireArgc = 2;
43    size_t argc = 2;
44    napi_value args[2] = {nullptr};
45    napi_get_cb_info(env, info, &argc, args , nullptr, nullptr);
46
47    // Convert the parameter of the napi_value type to the double type.
48    double valueLeft;
49    double valueRight;
50    napi_get_value_double(env, args[0], &valueLeft);
51    napi_get_value_double(env, args[1], &valueRight);
52
53    // Add up the converted double values, convert the sum into napi_value, and return the result to ArkTS.
54    napi_value sum;
55    napi_create_double(env, valueLeft + valueRight, &sum);
56
57    return sum;
58}
59
60// Call the C++ Init() function to initialize the addon, which associates the functions or properties in ArkTS with those in C++.
61EXTERN_C_START
62static napi_value Init(napi_env env, napi_value exports)
63{
64    // Use the napi_property_descriptor struct to define the properties to be exported and used in the Node-API module. napi_define_properties associates ArkTS properties with C++ functions so that they can be accessed and called from ArkTS.
65    napi_property_descriptor desc[] = {
66        { "add", nullptr, Add, nullptr, nullptr, nullptr, napi_default, nullptr }
67    };
68    napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
69    return exports;
70}
71EXTERN_C_END
72
73// The addon initialization is defined in a struct named demoModule, which contains the basic module information, such as the version number and registered functions.
74static napi_module demoModule = {
75    .nm_version =1,
76    .nm_flags = 0,
77    .nm_filename = nullptr,
78    .nm_register_func = Init,
79    .nm_modname = "entry",
80    .nm_priv = ((void*)0),
81    .reserved = { 0 },
82};
83
84// In the RegisterEntryModule function, the napi_module_register function is used to register and export the addon.
85extern "C" __attribute__((constructor)) void RegisterEntryModule(void)
86{
87    napi_module_register(&demoModule);
88}
89```
90
91API declaration:
92
93```ts
94// index.d.ts
95export const add: (a: number, b: number) => number;
96```
97
98ArkTS code:
99
100```ts
101import hilog from '@ohos.hilog';
102import testNapi from 'libentry.so';
103
104hilog.info(0x0000, 'testTag', 'Test Node-API 2 + 3 = %{public}d', testNapi.add(2, 3));
105```
106
107## ArkTS Object Operations
108
109### Available APIs
110
111| API| Description|
112| -------- | -------- |
113| napi_create_object_with_properties | Creates an ArkTS object with the given **napi_property_descriptor** in a native module. The key in **napi_property_descriptor** must be a string and cannot be converted into a number.|
114| napi_create_object_with_named_properties | Creates an ArkTS object with the given **napi_value** and key in a native module. The key must be a string and cannot be converted into a number.|
115
116### Example
117
118#### napi_create_object_with_properties
119
120Call **napi_create_object_with_properties** to create an ArkTS object with the given **napi_property_descriptor**. The key of **napi_property_descriptor** must be a string and cannot be converted into a number.
121
122CPP code:
123
124```cpp
125#include "napi/native_api.h"
126
127static napi_value CreateObjectWithProperties(napi_env env, napi_callback_info info)
128{
129    size_t argc = 1;
130    napi_value argv[1] = {nullptr};
131    // Obtain the parameters of the call.
132    napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
133    // Declare a desc array in napi_property_descriptor. The desc array contains a property named "name", whose value is the first input parameter argv[0].
134    napi_property_descriptor desc[] = {
135        {"name", nullptr, nullptr, nullptr, nullptr, argv[0], napi_default_jsproperty, nullptr}};
136    napi_value object = nullptr;
137    // Call napi_create_object_with_properties to create an ArkTS object with the specified properties.
138    napi_create_object_with_properties(env, &object, sizeof(desc) / sizeof(desc[0]), desc);
139    napi_valuetype valueType;
140    napi_typeof(env, object, &valueType);
141    if (valueType == napi_object) {
142        return object;
143    }
144}
145```
146
147API declaration:
148
149```ts
150// index.d.ts
151export const createObjectWithProperties: (data: string) => Object;
152```
153
154ArkTS code:
155
156```ts
157import hilog from '@ohos.hilog';
158import testNapi from 'libentry.so';
159
160let value = testNapi.createObjectWithProperties('createObject');
161hilog.info(0x0000, 'testTag', 'Node-API napi_create_object_with_properties:%{public}s', JSON.stringify(value));
162```
163
164#### napi_create_object_with_named_properties
165
166Call **napi_create_object_with_named_properties** to create an ArkTS object with the specified **napi_value** and key. The key must be a string and cannot be converted into a number.
167
168CPP code:
169
170```cpp
171#include "napi/native_api.h"
172
173static napi_value CreateObjectWithNameProperties(napi_env env, napi_callback_info info)
174{
175    size_t argc = 1;
176    napi_value argv[1] = {nullptr};
177    // Obtain the parameters of the call.
178    napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
179    napi_value obj = nullptr;
180    const char *key[] = {
181        "name",
182    };
183    const napi_value values[] = {
184        argv[0],
185    };
186    napi_property_descriptor desc[] = {{"name", nullptr, nullptr,
187                                        nullptr, nullptr, nullptr, napi_default, nullptr}};
188    napi_status status;
189    status = napi_create_object_with_named_properties(env, &obj, sizeof(desc) / sizeof(desc[0]), key, values);
190    if (status != napi_ok) {
191        return argv[0];
192    }
193    return obj;
194}
195```
196
197API declaration:
198
199```ts
200// index.d.ts
201export const createObjectWithNameProperties: (data: string) => string | { name: string };
202```
203
204ArkTS code:
205
206```ts
207import hilog from '@ohos.hilog';
208import testNapi from 'libentry.so';
209
210let value = testNapi.createObjectWithNameProperties('ls');
211hilog.info(0x0000, 'testTag', 'Node-API napi_create_object_with_named_properties:%{public}s', JSON.stringify(value));
212```
213
214## Running an .abc File
215
216### Available APIs
217
218| API| Description|
219| -------- | -------- |
220| napi_run_script_path | Runs the specified .abc file.|
221
222### Example
223
224#### napi_run_script_path
225
226Call **napi_run_script_path** to run an .abc file.
227
228CPP code:
229
230```cpp
231#include "napi/native_api.h"
232
233static napi_value RunScriptPath(napi_env env, napi_callback_info info)
234{
235    napi_value value = nullptr;
236    // The .abc file in the rawfile directory of the application.
237    const char *scriptPath = "/entry/resources/rawfile/test.abc";
238    // Call napi_run_script_path to execute the file of the specified path.
239    napi_status status = napi_run_script_path(env, scriptPath, &value);
240    // Check whether the script execution is successful. If the execution fails, return false.
241    napi_value returnValue = nullptr;
242    if (value == nullptr || status != napi_ok) {
243        napi_get_boolean(env, false, &returnValue);
244    } else {
245        napi_get_boolean(env, true, &returnValue);
246    }
247    return returnValue;
248}
249```
250
251API declaration:
252
253```ts
254// index.d.ts
255export const runScriptPath: () => boolean;
256```
257
258ArkTS code:
259
260```ts
261import hilog from '@ohos.hilog';
262import testNapi from 'libentry.so';
263
264try {
265  // Return true is the script is executed successfully; return false otherwise.
266  hilog.info(0x0000, 'testTag', 'Test Node-API napi_run_script_path: %{public}s', testNapi.runScriptPath());
267} catch (error) {
268  hilog.error(0x0000, 'testTag', 'Test Node-API napi_run_script_path errorMessage: %{public}s', error.message);
269}
270```
271
272To compile JS code, **test.js** for example, into an .abc file, perform the following steps:
273
2741. Place the **test.js** file in the **ets/build-tools/ets-loader/bin/ark/build-win/bin** directory of the SDK.
2752. Run the **es2abc.exe test.js --output test.abc** command. The **test.abc** file is generated.
276
277Save the file to the **/entry/resources/rawfile** directory.
278
279```js
280function add(a, b) {
281  return a+b;
282}
283add(1, 2);
284```
285
286## Adding an Async Work with the Specified Priority to a Queue
287
288### Available APIs
289
290| API| Description|
291| -------- | -------- |
292| napi_queue_async_work_with_qos | Adds an async work object to the queue so that it can be scheduled for execution based on the QoS priority passed in.|
293
294### Example
295
296#### napi_queue_async_work_with_qos
297
298Call **napi_queue_async_work_with_qos** to add an async work to the queue. Then, the async work will be scheduled for execution based on the specified QoS priority.
299
300<!--Del-->
301See [Prioritizing Asynchronous Tasks](../performance/develop-Native-modules-using-NAPI-safely-and-efficiently.md#prioritizing-asynchronous-tasks).
302<!--DelEnd-->
303
304## Binding an ArkTS Object and a Native Callback with Parameters
305
306### Available APIs
307
308| API| Description|
309| -------- | -------- |
310| napi_coerce_to_native_binding_object | Forcibly binds an ArkTS object and a native callback with necessary data. This API allows the ArkTS object to carry native information.|
311
312### Example
313
314#### napi_coerce_to_native_binding_object
315
316Call **napi_coerce_to_native_binding_object** to bind an ArkTS object and a native callback with necessary data. This API allows the ArkTS object to carry native information.
317
318CPP code:
319
320```cpp
321#include <bits/alltypes.h>
322#include <hilog/log.h>
323#include <mutex>
324#include <unordered_set>
325#include <uv.h>
326#include "napi/native_api.h"
327
328class Object {
329public:
330    Object() = default;
331    ~Object() = default;
332
333    static Object* GetInstance()
334    {
335        Object* instance = new Object();
336        return instance;
337    }
338
339    static napi_value GetAddress(napi_env env, napi_callback_info info)
340    {
341        napi_value thisVar = nullptr;
342        napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr);
343        if (thisVar == nullptr) {
344            return nullptr;
345        }
346        void* object = nullptr;
347        napi_unwrap(env, thisVar, &object);
348        if (object == nullptr) {
349            return nullptr;
350        }
351        uint64_t addressVal = reinterpret_cast<uint64_t>(object);
352        napi_value address = nullptr;
353        napi_create_bigint_uint64(env, addressVal, &address);
354        return address;
355    }
356
357    // Obtain the array size.
358    static napi_value GetSetSize(napi_env env, napi_callback_info info)
359    {
360        napi_value thisVar = nullptr;
361        napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr);
362        if (thisVar == nullptr) {
363            return nullptr;
364        }
365        void* object = nullptr;
366        napi_unwrap(env, thisVar, &object);
367        if (object == nullptr) {
368            return nullptr;
369        }
370        std::lock_guard<std::mutex> lock(reinterpret_cast<Object*>(object)->numberSetMutex_);
371        uint32_t setSize = reinterpret_cast<Object*>(object)->numberSet_.size();
372        napi_value napiSize = nullptr;
373        napi_create_uint32(env, setSize, &napiSize);
374        return napiSize;
375    }
376
377    // Insert an element into the array.
378    static napi_value Store(napi_env env, napi_callback_info info)
379    {
380        size_t argc = 1;
381        napi_value args[1] = {nullptr};
382        napi_value thisVar = nullptr;
383        napi_get_cb_info(env, info, &argc, args, &thisVar, nullptr);
384        if (argc != 1) {
385            napi_throw_error(env, nullptr, "Store args number must be one.");
386            return nullptr;
387        }
388        napi_valuetype type = napi_undefined;
389        napi_typeof(env, args[0], &type);
390        if (type != napi_number) {
391            napi_throw_error(env, nullptr, "Store args is not number.");
392            return nullptr;
393        }
394        if (thisVar == nullptr) {
395            return nullptr;
396        }
397        uint32_t value = 0;
398        napi_get_value_uint32(env, args[0], &value);
399        void* object = nullptr;
400        napi_unwrap(env, thisVar, &object);
401        if (object == nullptr) {
402            return nullptr;
403        }
404        std::lock_guard<std::mutex> lock(reinterpret_cast<Object*>(object)->numberSetMutex_);
405        reinterpret_cast<Object *>(object)-> numberSet_.insert(value);
406        return nullptr;
407    }
408
409    // Delete an element from the array.
410    static napi_value Erase(napi_env env, napi_callback_info info)
411    {
412        size_t argc = 1;
413        napi_value args[1] = {nullptr};
414        napi_value thisVar = nullptr;
415        napi_get_cb_info(env, info, &argc, args, &thisVar, nullptr);
416        if (argc != 1) {
417            napi_throw_error(env, nullptr, "Erase args number must be one.");
418            return nullptr;
419        }
420        napi_valuetype type = napi_undefined;
421        napi_typeof(env, args[0], &type);
422        if (type != napi_number) {
423            napi_throw_error(env, nullptr, "Erase args is not number.");
424            return nullptr;
425        }
426        if (thisVar == nullptr) {
427            return nullptr;
428        }
429        uint32_t value = 0;
430        napi_get_value_uint32(env, args[0], &value);
431        void* object = nullptr;
432        napi_unwrap(env, thisVar, &object);
433        if (object == nullptr) {
434            return nullptr;
435        }
436        std::lock_guard<std::mutex> lock(reinterpret_cast<Object*>(object)->numberSetMutex_);
437        reinterpret_cast<Object *>(object)->numberSet_.erase(value);
438        return nullptr;
439    }
440
441    // Clear the array.
442    static napi_value Clear(napi_env env, napi_callback_info info)
443    {
444        napi_value thisVar = nullptr;
445        napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr);
446        if (thisVar == nullptr) {
447            return nullptr;
448        }
449        void* object = nullptr;
450        napi_unwrap(env, thisVar, &object);
451        if (object == nullptr) {
452            return nullptr;
453        }
454        std::lock_guard<std::mutex> lock(reinterpret_cast<Object*>(object)->numberSetMutex_);
455        reinterpret_cast<Object *>(object)->numberSet_.clear();
456        return nullptr;
457    }
458
459private:
460    Object(const Object &) = delete;
461    Object &operator=(const Object &) = delete;
462
463    std::unordered_set<uint32_t> numberSet_{};
464    std::mutex numberSetMutex_{};
465};
466
467void FinializerCallback(napi_env env, void *data, void *hint)
468{
469    return;
470}
471
472// Detach a callback. Generally, it is called in serialization to perform cleanup operations when the object is detached.
473void* DetachCallback(napi_env env, void *value, void *hint)
474{
475    return value;
476}
477
478// Attach the callback, which is called during deserialization.
479napi_value AttachCallback(napi_env env, void* value, void* hint)
480{
481    napi_value object = nullptr;
482    napi_create_object(env, &object);
483    napi_property_descriptor desc[] = {
484        {"getAddress", nullptr, Object::GetAddress, nullptr, nullptr, nullptr, napi_default, nullptr},
485        {"getSetSize", nullptr, Object::GetSetSize, nullptr, nullptr, nullptr, napi_default, nullptr},
486        {"store", nullptr, Object::Store, nullptr, nullptr, nullptr, napi_default, nullptr},
487        {"erase", nullptr, Object::Erase, nullptr, nullptr, nullptr, napi_default, nullptr},
488        {"clear", nullptr, Object::Clear, nullptr, nullptr, nullptr, napi_default, nullptr}};
489    napi_define_properties(env, object, sizeof(desc) / sizeof(desc[0]), desc);
490    // Bind the ArkTS object named object to the lifecycle of the native object named value.
491    napi_status status = napi_wrap(env, object, value, FinializerCallback, nullptr, nullptr);
492    if (status != napi_ok) {
493        OH_LOG_INFO(LOG_APP, "Node-API attachCallback is failed.");
494    }
495    // Enable the ArkTS object to carry native information.
496    napi_coerce_to_native_binding_object(env, object, DetachCallback, AttachCallback, value, hint);
497    return object;
498}
499
500EXTERN_C_START
501static napi_value Init(napi_env env, napi_value exports)
502{
503    napi_property_descriptor desc[] = {
504        {"getAddress", nullptr, Object::GetAddress, nullptr, nullptr, nullptr, napi_default, nullptr},
505        {"getSetSize", nullptr, Object::GetSetSize, nullptr, nullptr, nullptr, napi_default, nullptr},
506        {"store", nullptr, Object::Store, nullptr, nullptr, nullptr, napi_default, nullptr},
507        {"erase", nullptr, Object::Erase, nullptr, nullptr, nullptr, napi_default, nullptr},
508        {"clear", nullptr, Object::Clear, nullptr, nullptr, nullptr, napi_default, nullptr}};
509    napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
510    auto object = Object::GetInstance();
511    napi_status status = napi_wrap(env, exports, reinterpret_cast<void*>(object), FinializerCallback, nullptr, nullptr);
512    if (status != napi_ok) {
513        delete object;
514    }
515    napi_coerce_to_native_binding_object(env, exports, DetachCallback, AttachCallback, reinterpret_cast<void*>(object),
516                                         nullptr);
517    return exports;
518}
519EXTERN_C_END
520
521static napi_module demoModule = {
522    .nm_version = 1,
523    .nm_flags = 0,
524    .nm_filename = nullptr,
525    .nm_register_func = Init,
526    .nm_modname = "entry",
527    .nm_priv = ((void*)0),
528    .reserved = { 0 },
529};
530
531extern "C" __attribute__((constructor)) void RegisterEntryModule(void)
532{
533    napi_module_register(&demoModule);
534}
535```
536
537API declaration:
538
539```ts
540// index.d.ts
541export const getAddress: () => number;
542export const getSetSize: () => number;
543export const store: (a: number) => void;
544export const erase: (a: number) => void;
545export const clear: () => void;
546```
547
548ArkTS code:
549
550```ts
551// index.ets
552import testNapi from 'libentry.so';
553import taskpool from '@ohos.taskpool';
554
555@Concurrent
556function getAddress() {
557  let address: number = testNapi.getAddress();
558  console.info("taskpool:: address is " + address);
559}
560
561@Concurrent
562function store(a:number, b:number, c:number) {
563  let size:number = testNapi.getSetSize();
564  console.info("set size is " + size + " before store");
565  testNapi.store(a);
566  testNapi.store(b);
567  testNapi.store(c);
568  size = testNapi.getSetSize();
569  console.info("set size is " + size + " after store");
570}
571
572@Concurrent
573function erase(a:number) {
574  let size:number = testNapi.getSetSize();
575  console.info("set size is " + size + " before erase");
576  testNapi.erase(a);
577  size = testNapi.getSetSize();
578  console.info("set size is " + size + " after erase");
579}
580
581@Concurrent
582function clear() {
583  let size:number = testNapi.getSetSize();
584  console.info("set size is " + size + " before clear");
585  testNapi.clear();
586  size = testNapi.getSetSize();
587  console.info("set size is " + size + " after clear");
588}
589
590async function test01(): Promise<void> {
591    let address:number = testNapi.getAddress();
592    console.info("host thread address is " + address);
593
594    let task1 = new taskpool.Task(getAddress);
595    await taskpool.execute(task1);
596
597    let task2 = new taskpool.Task(store, 1, 2, 3);
598    await taskpool.execute(task2);
599
600    let task3 = new taskpool.Task(store, 4, 5, 6);
601    await taskpool.execute(task3);
602
603    let task4 = new taskpool.Task(erase, 3);
604    await taskpool.execute(task4);
605
606    let task5 = new taskpool.Task(erase, 5);
607    await taskpool.execute(task5);
608
609    let task6 = new taskpool.Task(clear);
610    await taskpool.execute(task6);
611}
612
613test01();
614```
615
616**NOTE**
617
618Call **napi_coerce_to_native_binding_object** to add the **detach()** and **attach()** callbacks and native object information to ArkTs object A, and then pass object A across threads. Object A needs to be serialized and deserialized when passed cross threads. In thread 1, "data" is obtained after object A is serialized, and the **detach()** callback is invoked in the serialization process. Then, "data" is passed to thread 2 and deserialized in thread 2. The **attach()** callback is invoked to obtain the ArkTS object A.
619
620![napi_coerce_to_native_binding_object](figures/napi_coerce_to_native_binding_object.png)
621
622## Event Loop
623
624### Available APIs
625
626| API| Description|
627| -------- | -------- |
628| napi_run_event_loop | Runs an underlying event loop.|
629| napi_stop_event_loop | Stops an underlying event loop.|
630
631### Example
632
633#### napi_run_event_loop and napi_stop_event_loop
634
635See [Running or Stopping an Event Loop in an Asynchronous Thread Using Node-API Extensions](use-napi-event-loop.md)
636
637## ArkTS Runtime Environment
638
639### Available APIs
640
641| API| Description|
642| -------- | -------- |
643| napi_create_ark_runtime | Creates an ArkTS runtime environment.|
644| napi_destroy_ark_runtime | Destroys the ArkTS runtime environment.|
645
646### Example
647
648#### napi_create_ark_runtime and napi_destroy_ark_runtime
649
650See [Creating an ArkTs Runtime Environment Using Node-API](use-napi-ark-runtime.md).
651
652## Serialization and Deserialization
653
654### Available APIs
655
656| API| Description|
657| -------- | -------- |
658| napi_serialize | Converts an ArkTS object into native data. <br>The first parameter **env** indicates the ArkTS environment where the API is executed. The second parameter **object** indicates the ArkTS object to be serialized. The third parameter **transfer_list** indicates an array that holds the **arrayBuffer** to be passed. This parameter can be set to **undefined** if there is no data to be passed. The fourth parameter **clone_list** indicates an array that holds the sendable object to be cloned. This parameter can be set to **undefined** if there is no data to be cloned. The fifth parameter **result** indicates the serialized data obtained.|
659| napi_deserialize | Converts native data into an ArkTS object. The first parameter **env** indicates the ArkTS environment where the API is executed. The second parameter **buffer** indicates the data to be deserialized. The third parameter **object** indicates the deserialized data obtained.|
660| napi_delete_serialization_data | Deletes serialized data.|
661
662### Example
663
664#### napi_serialize, napi_deserialize, and napi_delete_serialization_data
665
666Call **napi_serialize** to convert an ArkTS object into native data; call **napi_deserialize** to convert native data into an ArkTS object; call **napi_delete_serialization_data** to delete serialized data.
667
668CPP code:
669
670```cpp
671#include "napi/native_api.h"
672
673static napi_value AboutSerialize(napi_env env, napi_callback_info info)
674{
675    // Obtain an ArkTS object as a parameter.
676    size_t argc = 1;
677    napi_value args[1] = {nullptr};
678    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
679    napi_value undefined = nullptr;
680    // Construct the parameters required by the napi_serialize method.
681    napi_get_undefined(env, &undefined);
682    void *data = nullptr;
683    // Call napi_serialize to convert the ArkTS object into native data.
684    napi_status status = napi_serialize(env, args[0], undefined, undefined, &data);
685    if (status != napi_ok ||data == nullptr) {
686        napi_throw_error(env, nullptr, "Node-API napi_serialize fail");
687        return nullptr;
688    }
689    // Construct data of the napi_value type to hold the ArkTS object converted from the native data.
690    napi_value result = nullptr;
691    napi_deserialize(env, data, &result);
692    napi_value number = nullptr;
693    // Obtain the value of the numKey property in the ArkTS object converted from native data.
694    napi_get_named_property(env, result, "numKey", &number);
695    // Check whether the obtained property value is of the number type.
696    napi_valuetype valuetype;
697    napi_typeof(env, number, &valuetype);
698    if (valuetype != napi_number) {
699        napi_throw_error(env, nullptr, "Node-API Wrong type of argument. Expects a number.");
700        return nullptr;
701    }
702    // Call napi_delete_serialization_data to delete the serialized data.
703    napi_delete_serialization_data(env, data);
704    // Return the obtained property value.
705    return number;
706}
707```
708
709API declaration:
710
711```ts
712// index.d.ts
713export const aboutSerialize: (obj: Object) => number;
714```
715
716ArkTS code:
717
718```ts
719import hilog from '@ohos.hilog';
720import testNapi from 'libentry.so';
721class Obj {
722  numKey:number = 0;
723}
724let obj: Obj = { numKey: 500 };
725hilog.info(0x0000, 'testTag', ' Node-API aboutSerialize: %{public}d', testNapi.aboutSerialize(obj));
726```
727
728## Passing a Task from an Asynchronous Thread to an ArkTS Thread
729
730### Available APIs
731
732| API| Description|
733| -------- | -------- |
734| napi_call_threadsafe_function_with_priority | Calls a task with the specified priority and enqueuing mode into the ArkTS main thread.|
735
736### Example
737
738#### napi_call_threadsafe_function_with_priority
739
740See [Passing a Task with the Specified Priority to an ArkTS Thread from an Asynchronous Thread Using Node-API](use-call-threadsafe-function-with-priority.md).
741
742## Sendable-related Operations
743
744### Available APIs
745
746| API                      | Description                              |
747| -------------------------- | ---------------------------------- |
748| napi_is_sendable           | Checks whether an ArkTS value is sendable.|
749| napi_define_sendable_class | Creates a sendable class.              |
750| napi_create_sendable_object_with_properties | Creates a sendable object with the given **napi_property_descriptor**.|
751| napi_create_sendable_array | Creates a sendable array.|
752| napi_create_sendable_array_with_length | Creates a sendable array of the specified length.|
753| napi_create_sendable_arraybuffer | Creates a sendable **ArrayBuffer**.|
754| napi_create_sendable_typedarray | Creates a sendable **TypedArray**.|
755| napi_wrap_sendable | Wraps a native instance into an ArkTS object.|
756| napi_wrap_sendable_with_size | Wraps a native instance of the specified size into an ArkTS object.|
757| napi_unwrap_sendable | Unwraps the native instance from an ArkTS object.|
758| napi_remove_wrap_sendable | Removes the native instance from an ArkTS object.|
759
760### Example
761
762#### napi_is_sendable
763
764Call **napi_is_sendable** to check whether an ArkTS value is sendable.
765
766CPP code:
767
768```cpp
769#include "napi/native_api.h"
770
771static napi_value IsSendable(napi_env env, napi_callback_info info) {
772    size_t argc = 1;
773    napi_value args[1] = {nullptr};
774    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
775    bool isSendable = false;
776    napi_is_sendable(env, args[0], &isSendable);
777    napi_value result;
778    napi_get_boolean(env, isSendable, &result);
779    return result;
780}
781```
782
783API declaration:
784
785```ts
786// index.d.ts
787export const isSendable: <T>(a: T) => boolean;
788```
789
790ArkTS code:
791
792```ts
793import hilog from '@ohos.hilog';
794import testNapi from 'libentry.so';
795
796let value = testNapi.isSendable('createObject');
797hilog.info(0x0000, 'testTag', 'Node-API napi_is_sendable: %{public}s', JSON.stringify(value));
798```
799
800#### napi_define_sendable_class
801
802Call **napi_define_sendable_class** to create a sendable class.
803
804CPP code:
805
806```cpp
807#include "napi/native_api.h"
808
809static napi_value func(napi_env env, napi_callback_info info) {
810    napi_value val;
811    napi_create_string_utf8(env, "func result", NAPI_AUTO_LENGTH, &val);
812    return val;
813}
814
815static napi_value DefineSendableClass(napi_env env) {
816    napi_value str;
817    napi_create_string_utf8(env, "str", NAPI_AUTO_LENGTH, &str);
818
819    napi_property_descriptor props[] = {
820        {"staticStr", nullptr, nullptr, nullptr, nullptr, str,
821         static_cast<napi_property_attributes>(napi_static | napi_writable), nullptr},
822        {"staticFunc", nullptr, func, nullptr, nullptr, nullptr, napi_static, nullptr},
823        {"str", nullptr, nullptr, nullptr, nullptr, str, static_cast<napi_property_attributes>(1 << 9 | napi_writable),
824         nullptr},
825        {"func", nullptr, nullptr, nullptr, nullptr, nullptr,
826         static_cast<napi_property_attributes>(1 << 11 | napi_writable), nullptr},
827    };
828
829    napi_value sendableClass = nullptr;
830    napi_define_sendable_class(
831        env, "SendableClass", NAPI_AUTO_LENGTH,
832        [](napi_env env, napi_callback_info info) -> napi_value {
833            napi_value thisVar = nullptr;
834            napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr);
835            napi_value str;
836            napi_create_string_utf8(env, "instance str", NAPI_AUTO_LENGTH, &str);
837            napi_property_descriptor props[] = {
838                {"str", nullptr, nullptr, nullptr, nullptr, str, napi_default, nullptr},
839                {"func", nullptr, func, nullptr, nullptr, nullptr, napi_default, nullptr},
840            };
841            napi_define_properties(env, thisVar, sizeof(props) / sizeof(props[0]), props);
842            return thisVar;
843        },
844        nullptr, sizeof(props) / sizeof(props[0]), props, nullptr, &sendableClass);
845
846    return sendableClass;
847}
848
849EXTERN_C_START
850static napi_value Init(napi_env env, napi_value exports)
851{
852    napi_property_descriptor desc[] = {};
853    napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
854    napi_value cons = DefineSendableClass(env);
855    napi_set_named_property(env, exports, "SendableClass", cons);
856    return exports;
857}
858EXTERN_C_END
859
860static napi_module demoModule = {
861    .nm_version = 1,
862    .nm_flags = 0,
863    .nm_filename = nullptr,
864    .nm_register_func = Init,
865    .nm_modname = "entry",
866    .nm_priv = ((void*)0),
867    .reserved = { 0 },
868};
869
870extern "C" __attribute__((constructor)) void RegisterEntryModule(void)
871{
872    napi_module_register(&demoModule);
873}
874```
875
876API declaration:
877
878```ts
879// index.d.ts
880@Sendable
881export class SendableClass {
882  static staticStr: string;
883  static staticFunc(): string;
884  str: string;
885  func(): string;
886}
887```
888
889ArkTS code:
890
891```ts
892import hilog from '@ohos.hilog';
893import testNapi from 'libentry.so';
894
895let value = new testNapi.SendableClass();
896hilog.info(0x0000, 'testTag', 'Node-API napi_define_sendable_class: %{public}s', value.str);
897```
898
899#### napi_create_sendable_object_with_properties
900
901Call **napi_create_sendable_object_with_properties** to create a sendable object with the given **napi_property_descriptor**.
902
903CPP code:
904
905```cpp
906#include "napi/native_api.h"
907
908static napi_value GetSendableObject(napi_env env, napi_callback_info info) {
909    napi_value val_true;
910    napi_get_boolean(env, true, &val_true);
911    napi_property_descriptor desc1[] = {
912        {"x", nullptr, nullptr, nullptr, nullptr, val_true, napi_default_jsproperty, nullptr},
913    };
914    napi_value obj;
915    napi_create_sendable_object_with_properties(env, 1, desc1, &obj);
916    return obj;
917}
918```
919
920API declaration:
921
922```ts
923// index.d.ts
924export const getSendableObject: () => { x: true };
925```
926
927ArkTS code:
928
929```ts
930import hilog from '@ohos.hilog';
931import testNapi from 'libentry.so';
932
933let value = testNapi.getSendableObject();
934hilog.info(0x0000, 'testTag', 'Node-API napi_create_sendable_object_with_properties: %{public}s', JSON.stringify(value));
935```
936
937#### napi_create_sendable_array
938
939Call **napi_create_sendable_array** to create a sendable array.
940
941CPP code:
942
943```cpp
944#include "napi/native_api.h"
945
946static napi_value GetSendableArray(napi_env env, napi_callback_info info) {
947    napi_value result = nullptr;
948    napi_create_sendable_array(env, &result);
949    return result;
950}
951```
952
953API declaration:
954
955```ts
956// index.d.ts
957export const getSendableArray: () => [];
958```
959
960ArkTS code:
961
962```ts
963import hilog from '@ohos.hilog';
964import testNapi from 'libentry.so';
965
966let value = testNapi.getSendableArray();
967hilog.info(0x0000, 'testTag', 'Node-API napi_create_sendable_array: %{public}s', JSON.stringify(value));
968```
969
970#### napi_create_sendable_array_with_length
971
972Call **napi_create_sendable_array_with_length** to create a sendable array of the specified length.
973
974CPP code:
975
976```cpp
977static napi_value GetSendableArrayWithLength(napi_env env, napi_callback_info info) {
978    napi_value result = nullptr;
979    napi_create_sendable_array_with_length(env, 1, &result);
980    return result;
981}
982```
983
984API declaration:
985
986```ts
987// index.d.ts
988export const getSendableArrayWithLength: () => [];
989```
990
991ArkTS code:
992
993```ts
994import hilog from '@ohos.hilog';
995import testNapi from 'libentry.so';
996
997let value = testNapi.getSendableArrayWithLength();
998hilog.info(0x0000, 'testTag', 'Node-API napi_create_sendable_array_with_length: %{public}s', JSON.stringify(value.length));
999```
1000
1001#### napi_create_sendable_arraybuffer
1002
1003Call **napi_create_sendable_arraybuffer** to create a sendable **ArrayBuffer**.
1004
1005CPP code:
1006
1007```cpp
1008#include "napi/native_api.h"
1009#include "hilog/log.h"
1010
1011static napi_value GetSendableArrayBuffer(napi_env env, napi_callback_info info) {
1012    static size_t LENGTH = 1024;
1013    void *data;
1014    napi_value result = nullptr;
1015    napi_create_sendable_arraybuffer(env, LENGTH, &data, &result);
1016    bool isArrayBuffer = false;
1017    napi_is_arraybuffer(env, result, &isArrayBuffer);
1018    OH_LOG_INFO(LOG_APP, "isArrayBuffer: %{public}d", isArrayBuffer);
1019    return result;
1020}
1021```
1022
1023API declaration:
1024
1025```ts
1026// index.d.ts
1027export const getSendableArrayBuffer: () => void;
1028```
1029
1030ArkTS code:
1031
1032```ts
1033import hilog from '@ohos.hilog';
1034import testNapi from 'libentry.so';
1035
1036testNapi.getSendableArrayBuffer();
1037```
1038
1039#### napi_create_sendable_typedarray
1040
1041Call **napi_create_sendable_typedarray** to create a sendable **TypedArray**.
1042
1043CPP code:
1044
1045```cpp
1046#include "napi/native_api.h"
1047#include "hilog/log.h"
1048
1049static napi_value GetSendableTypedArray(napi_env env, napi_callback_info info) {
1050    static size_t LENGTH = 1024;
1051    static size_t OFFSET = 0;
1052    void *data;
1053    napi_value arraybuffer = nullptr;
1054    napi_create_sendable_arraybuffer(env, LENGTH, &data, &arraybuffer);
1055
1056    napi_value result = nullptr;
1057    napi_create_sendable_typedarray(env, napi_uint8_array, LENGTH, arraybuffer, OFFSET, &result);
1058    bool isTypedArray = false;
1059    napi_is_typedarray(env, result, &isTypedArray);
1060    OH_LOG_INFO(LOG_APP, "isTypedArray: %{public}d", isTypedArray);
1061    return result;
1062}
1063```
1064
1065API declaration:
1066
1067```ts
1068// index.d.ts
1069export const getSendableTypedArray: () => void;
1070```
1071
1072ArkTS code:
1073
1074```ts
1075import hilog from '@ohos.hilog';
1076import testNapi from 'libentry.so';
1077
1078testNapi.getSendableTypedArray();
1079```
1080
1081#### napi_wrap_sendable
1082
1083Call **napi_wrap_sendable** to wrap a native instance into an ArkTS object.
1084
1085CPP code:
1086
1087```cpp
1088#include "napi/native_api.h"
1089
1090static napi_value WrapSendable(napi_env env, napi_callback_info info) {
1091    napi_value val_true;
1092    napi_get_boolean(env, true, &val_true);
1093    napi_property_descriptor desc1[] = {
1094        {"x", nullptr, nullptr, nullptr, nullptr, val_true, napi_default_jsproperty, nullptr},
1095    };
1096    napi_value obj;
1097    napi_create_sendable_object_with_properties(env, 1, desc1, &obj);
1098
1099    const char* testStr = "test";
1100    napi_wrap_sendable(env, obj, (void*)testStr, [](napi_env env, void* data, void* hint) {}, nullptr);
1101
1102    return nullptr;
1103}
1104```
1105
1106API declaration:
1107
1108```ts
1109// index.d.ts
1110export const wrapSendable: () => void;
1111```
1112
1113ArkTS code:
1114
1115```ts
1116import hilog from '@ohos.hilog';
1117import testNapi from 'libentry.so';
1118
1119testNapi.wrapSendable();
1120```
1121
1122#### napi_wrap_sendable_with_size
1123
1124Call **napi_wrap_sendable_with_size** to wrap a native instance of the specified size into an ArkTS object.
1125
1126CPP code:
1127
1128```cpp
1129#include "napi/native_api.h"
1130
1131static napi_value WrapSendableWithSize(napi_env env, napi_callback_info info) {
1132    napi_value val_true;
1133    napi_get_boolean(env, true, &val_true);
1134    napi_property_descriptor desc1[] = {
1135        {"x", nullptr, nullptr, nullptr, nullptr, val_true, napi_default_jsproperty, nullptr},
1136    };
1137    napi_value obj;
1138    napi_create_sendable_object_with_properties(env, 1, desc1, &obj);
1139
1140    const char* testStr = "test";
1141    napi_wrap_sendable_with_size(env, obj, (void*)testStr, [](napi_env env, void* data, void* hint) {}, nullptr, 100);
1142
1143    return nullptr;
1144}
1145```
1146
1147API declaration:
1148
1149```ts
1150// index.d.ts
1151export const wrapSendableWithSize: () => void;
1152```
1153
1154ArkTS code:
1155
1156```ts
1157import hilog from '@ohos.hilog';
1158import testNapi from 'libentry.so';
1159
1160testNapi.wrapSendableWithSize();
1161```
1162
1163#### napi_unwrap_sendable
1164
1165Call **napi_unwrap_sendable** to unwrap the native instance from an ArkTS object.
1166
1167CPP code:
1168
1169```cpp
1170#include "napi/native_api.h"
1171
1172static napi_value UnwrapSendable(napi_env env, napi_callback_info info) {
1173    napi_value val_true;
1174    napi_get_boolean(env, true, &val_true);
1175    napi_property_descriptor desc1[] = {
1176        {"x", nullptr, nullptr, nullptr, nullptr, val_true, napi_default_jsproperty, nullptr},
1177    };
1178    napi_value obj;
1179    napi_create_sendable_object_with_properties(env, 1, desc1, &obj);
1180
1181    const char* testStr = "test";
1182    napi_wrap_sendable(env, obj, (void*)testStr, [](napi_env env, void* data, void* hint) {}, nullptr);
1183
1184    char* tmpTestStr = nullptr;
1185    napi_unwrap_sendable(env, obj, (void**)&tmpTestStr);
1186    OH_LOG_INFO(LOG_APP, "native value is %{public}s", tmpTestStr);
1187
1188    return nullptr;
1189}
1190```
1191
1192API declaration:
1193
1194```ts
1195// index.d.ts
1196export const unwrapSendable: () => void;
1197```
1198
1199ArkTS code:
1200
1201```ts
1202import hilog from '@ohos.hilog';
1203import testNapi from 'libentry.so';
1204
1205testNapi.unwrapSendable();
1206```
1207
1208#### napi_remove_wrap_sendable
1209
1210Call **napi_remove_wrap_sendable** to remove the native instance from an ArkTS object.
1211
1212CPP code:
1213
1214```cpp
1215#include "napi/native_api.h"
1216
1217static napi_value RemoveWrapSendable(napi_env env, napi_callback_info info) {
1218    napi_value val_true;
1219    napi_get_boolean(env, true, &val_true);
1220    napi_property_descriptor desc1[] = {
1221        {"x", nullptr, nullptr, nullptr, nullptr, val_true, napi_default_jsproperty, nullptr},
1222    };
1223    napi_value obj;
1224    napi_create_sendable_object_with_properties(env, 1, desc1, &obj);
1225
1226    const char* testStr = "test";
1227    napi_wrap_sendable(env, obj, (void*)testStr, [](napi_env env, void* data, void* hint) {}, nullptr);
1228
1229    char* tmpTestStr = nullptr;
1230    napi_remove_wrap_sendable(env, obj, (void**)&tmpTestStr);
1231    OH_LOG_INFO(LOG_APP, "native value is %{public}s", tmpTestStr);
1232
1233    return nullptr;
1234}
1235```
1236
1237API declaration:
1238
1239```ts
1240// index.d.ts
1241export const removeWrapSendable: () => void;
1242```
1243
1244ArkTS code:
1245
1246```ts
1247import hilog from '@ohos.hilog';
1248import testNapi from 'libentry.so';
1249
1250testNapi.removeWrapSendable();
1251```
1252
1253To print logs in the native CPP, add the following information to the **CMakeLists.txt** file and add the header file by using **#include "hilog/log.h"**.
1254
1255```text
1256// CMakeLists.txt
1257add_definitions( "-DLOG_DOMAIN=0xd0d0" )
1258add_definitions( "-DLOG_TAG=\"testTag\"" )
1259target_link_libraries(entry PUBLIC libhilog_ndk.z.so)
1260```
1261
1262
1263## napi_wrap Enhancement
1264
1265### Available APIs
1266
1267| API| Description|
1268| -------- | -------- |
1269| napi_wrap_enhance | Wraps a Node-API instance into an ArkTS object and specifies the instance size. You can specify whether to execute the registered callback asynchronously (if asynchronous, it must be thread-safe).|
1270
1271### Example
1272
1273#### napi_wrap_enhance
1274
1275Call **napi_wrap_enhance** to wrap a Node-API instance into an ArkTS object and specify the instance size. You can specify whether to execute the registered callback asynchronously (if asynchronous, it must be thread-safe).
1276
1277CPP code:
1278
1279```cpp
1280#include "napi/native_api.h"
1281
1282static napi_value TestNapiWrapEnhance(napi_env env, napi_callback_info info)
1283{
1284    napi_value testClass = nullptr;
1285    napi_define_class(
1286        env, "TestClass", NAPI_AUTO_LENGTH,
1287        [](napi_env env, napi_callback_info info) -> napi_value {
1288            napi_value thisVar = nullptr;
1289            napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr);
1290            return thisVar;
1291        },
1292        nullptr, 0, nullptr, &testClass);
1293
1294    napi_value obj = nullptr;
1295    napi_new_instance(env, testClass, 0, nullptr, &obj);
1296    const char* testStr = "test";
1297    napi_ref wrappedRef = nullptr;
1298    napi_wrap_enhance(env, obj, (void*)testStr, [](napi_env env, void* data, void* hint) {}, false, nullptr, sizeof(testStr), &wrappedRef);
1299    return nullptr;
1300}
1301```
1302
1303API declaration:
1304
1305```ts
1306// index.d.ts
1307export const testNapiWrapEnhance: () => void;
1308```
1309
1310ArkTS code:
1311
1312```ts
1313import hilog from '@ohos.hilog';
1314import testNapi from 'libentry.so';
1315
1316testNapi.testNapiWrapEnhance();
1317```
1318