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
23Use **napi_load_module** to [load a module in the main thread](use-napi-load-module.md).
24
25#### napi_load_module_with_info
26
27Use **napi_load_module_with_info** to [load a module](use-napi-load-module-with-info.md).
28
29#### napi_module_register
30
31Use **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 valueLift;
49    double valueRight;
50    napi_get_value_double(env, args[0], &valueLift);
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, valueLift + 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
120Use **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
166Use **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## Runing 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
226Use **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
298Use **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
316Use **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 <mutex>
323#include <unordered_set>
324#include <uv.h>
325#include "napi/native_api.h"
326
327class Object {
328public:
329    Object() = default;
330    ~Object() = default;
331
332    static Object* GetInstance()
333    {
334        Object* instance = new Object();
335        return instance;
336    }
337
338    static napi_value GetAddress(napi_env env, napi_callback_info info)
339    {
340        napi_value thisVar = nullptr;
341        napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr);
342        if (thisVar == nullptr) {
343            return nullptr;
344        }
345        void* object = nullptr;
346        napi_unwrap(env, thisVar, &object);
347        if (object == nullptr) {
348            return nullptr;
349        }
350        uint64_t addressVal = reinterpret_cast<uint64_t>(object);
351        napi_value address = nullptr;
352        napi_create_bigint_uint64(env, addressVal, &address);
353        return address;
354    }
355
356    // Obtain the array size.
357    static napi_value GetSetSize(napi_env env, napi_callback_info info)
358    {
359        napi_value thisVar = nullptr;
360        napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr);
361        if (thisVar == nullptr) {
362            return nullptr;
363        }
364        void* object = nullptr;
365        napi_unwrap(env, thisVar, &object);
366        if (object == nullptr) {
367            return nullptr;
368        }
369        std::lock_guard<std::mutex> lock(reinterpret_cast<Object*>(object)->numberSetMutex_);
370        uint32_t setSize = reinterpret_cast<Object*>(object)->numberSet_.size();
371        napi_value napiSize = nullptr;
372        napi_create_uint32(env, setSize, &napiSize);
373        return napiSize;
374    }
375
376    // Insert an element into the array.
377    static napi_value Store(napi_env env, napi_callback_info info)
378    {
379        size_t argc = 1;
380        napi_value args[1] = {nullptr};
381        napi_value thisVar = nullptr;
382        napi_get_cb_info(env, info, &argc, args, &thisVar, nullptr);
383        if (argc != 1) {
384            napi_throw_error(env, nullptr, "Store args number must be one.");
385            return nullptr;
386        }
387        napi_valuetype type = napi_undefined;
388        napi_typeof(env, args[0], &type);
389        if (type != napi_number) {
390            napi_throw_error(env, nullptr, "Store args is not number.");
391            return nullptr;
392        }
393        if (thisVar == nullptr) {
394            return nullptr;
395        }
396        uint32_t value = 0;
397        napi_get_value_uint32(env, args[0], &value);
398        void* object = nullptr;
399        napi_unwrap(env, thisVar, &object);
400        if (object == nullptr) {
401            return nullptr;
402        }
403        std::lock_guard<std::mutex> lock(reinterpret_cast<Object*>(object)->numberSetMutex_);
404        reinterpret_cast<Object *>(object)-> numberSet_.insert(value);
405        return nullptr;
406    }
407
408    // Delete an element from the array.
409    static napi_value Erase(napi_env env, napi_callback_info info)
410    {
411        size_t argc = 1;
412        napi_value args[1] = {nullptr};
413        napi_value thisVar = nullptr;
414        napi_get_cb_info(env, info, &argc, args, &thisVar, nullptr);
415        if (argc != 1) {
416            napi_throw_error(env, nullptr, "Erase args number must be one.");
417            return nullptr;
418        }
419        napi_valuetype type = napi_undefined;
420        napi_typeof(env, args[0], &type);
421        if (type != napi_number) {
422            napi_throw_error(env, nullptr, "Erase args is not number.");
423            return nullptr;
424        }
425        if (thisVar == nullptr) {
426            return nullptr;
427        }
428        uint32_t value = 0;
429        napi_get_value_uint32(env, args[0], &value);
430        void* object = nullptr;
431        napi_unwrap(env, thisVar, &object);
432        if (object == nullptr) {
433            return nullptr;
434        }
435        std::lock_guard<std::mutex> lock(reinterpret_cast<Object*>(object)->numberSetMutex_);
436        reinterpret_cast<Object *>(object)->numberSet_.erase(value);
437        return nullptr;
438    }
439
440    // Clear the array.
441    static napi_value Clear(napi_env env, napi_callback_info info)
442    {
443        napi_value thisVar = nullptr;
444        napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr);
445        if (thisVar == nullptr) {
446            return nullptr;
447        }
448        void* object = nullptr;
449        napi_unwrap(env, thisVar, &object);
450        if (object == nullptr) {
451            return nullptr;
452        }
453        std::lock_guard<std::mutex> lock(reinterpret_cast<Object*>(object)->numberSetMutex_);
454        reinterpret_cast<Object *>(object)->numberSet_.clear();
455        return nullptr;
456    }
457
458private:
459    Object(const Object &) = delete;
460    Object &operator=(const Object &) = delete;
461
462    std::unordered_set<uint32_t> numberSet_{};
463    std::mutex numberSetMutex_{};
464};
465
466void FinializeCallback(napi_env env, void *data, void *hint)
467{
468    return;
469}
470
471// Detach a callback. Generally, it is called in serialization to perform cleanup operations when the object is detached.
472void* DetachCallback(napi_env env, void *value, void *hint)
473{
474    return value;
475}
476
477// Attach the callback, which is called during deserialization.
478napi_value AttachCallback(napi_env env, void* value, void* hint)
479{
480    napi_value object = nullptr;
481    napi_create_object(env, &object);
482    napi_property_descriptor desc[] = {
483        {"getAddress", nullptr, Object::GetAddress, nullptr, nullptr, nullptr, napi_default, nullptr},
484        {"getSetSize", nullptr, Object::GetSetSize, nullptr, nullptr, nullptr, napi_default, nullptr},
485        {"store", nullptr, Object::Store, nullptr, nullptr, nullptr, napi_default, nullptr},
486        {"erase", nullptr, Object::Erase, nullptr, nullptr, nullptr, napi_default, nullptr},
487        {"clear", nullptr, Object::Clear, nullptr, nullptr, nullptr, napi_default, nullptr}};
488    napi_define_properties(env, object, sizeof(desc) / sizeof(desc[0]), desc);
489    // Bind the ArkTS object named object to the lifecycle of the native object named value.
490    napi_wrap(env, object, value, FinializeCallback, nullptr, nullptr);
491    // Enable the ArkTS object to carry native information.
492    napi_coerce_to_native_binding_object(env, object, DetachCallback, AttachCallback, value, hint);
493    return object;
494}
495
496EXTERN_C_START
497static napi_value Init(napi_env env, napi_value exports)
498{
499    napi_property_descriptor desc[] = {
500        {"getAddress", nullptr, Object::GetAddress, nullptr, nullptr, nullptr, napi_default, nullptr},
501        {"getSetSize", nullptr, Object::GetSetSize, nullptr, nullptr, nullptr, napi_default, nullptr},
502        {"store", nullptr, Object::Store, nullptr, nullptr, nullptr, napi_default, nullptr},
503        {"erase", nullptr, Object::Erase, nullptr, nullptr, nullptr, napi_default, nullptr},
504        {"clear", nullptr, Object::Clear, nullptr, nullptr, nullptr, napi_default, nullptr}};
505    napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
506    auto object = Object::GetInstance();
507    napi_wrap(env, exports, reinterpret_cast<void*>(object), FinializeCallback, nullptr, nullptr);
508    napi_coerce_to_native_binding_object(env, exports, DetachCallback, AttachCallback, reinterpret_cast<void*>(object),
509                                         nullptr);
510    return exports;
511}
512EXTERN_C_END
513
514static napi_module demoModule = {
515    .nm_version = 1,
516    .nm_flags = 0,
517    .nm_filename = nullptr,
518    .nm_register_func = Init,
519    .nm_modname = "entry",
520    .nm_priv = ((void*)0),
521    .reserved = { 0 },
522};
523
524extern "C" __attribute__((constructor)) void RegisterEntryModule(void)
525{
526    napi_module_register(&demoModule);
527}
528```
529
530API declaration:
531
532```ts
533// index.d.ts
534export const getAddress: () => number;
535export const getSetSize: () => number;
536export const store: (a: number) => void;
537export const erase: (a: number) => void;
538export const clear: () => void;
539```
540
541ArkTS code:
542
543```ts
544// index.ets
545import testNapi from 'libentry.so';
546import taskpool from '@ohos.taskpool';
547
548@Concurrent
549function getAddress() {
550  let address: number = testNapi.getAddress();
551  console.info("taskpool:: address is " + address);
552}
553
554@Concurrent
555function store(a:number, b:number, c:number) {
556  let size:number = testNapi.getSetSize();
557  console.info("set size is " + size + " before store");
558  testNapi.store(a);
559  testNapi.store(b);
560  testNapi.store(c);
561  size = testNapi.getSetSize();
562  console.info("set size is " + size + " after store");
563}
564
565@Concurrent
566function erase(a:number) {
567  let size:number = testNapi.getSetSize();
568  console.info("set size is " + size + " before erase");
569  testNapi.erase(a);
570  size = testNapi.getSetSize();
571  console.info("set size is " + size + " after erase");
572}
573
574@Concurrent
575function clear() {
576  let size:number = testNapi.getSetSize();
577  console.info("set size is " + size + " before clear");
578  testNapi.clear();
579  size = testNapi.getSetSize();
580  console.info("set size is " + size + " after clear");
581}
582
583let address:number = testNapi.getAddress();
584console.info("host thread address is " + address);
585
586let task1 = new taskpool.Task(getAddress);
587await taskpool.execute(task1);
588
589let task2 = new taskpool.Task(store, 1, 2, 3);
590await taskpool.execute(task2);
591
592let task3 = new taskpool.Task(store, 4, 5, 6);
593await taskpool.execute(task3);
594
595let task4 = new taskpool.Task(erase, 3);
596await taskpool.execute(task4);
597
598let task5 = new taskpool.Task(erase, 5);
599await taskpool.execute(task5);
600
601let task6 = new taskpool.Task(clear);
602await taskpool.execute(task6);
603```
604
605**NOTE**
606
607Call **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.
608![napi_coerce_to_native_binding_object](figures/napi_coerce_to_native_binding_object.png)
609
610## Event Loop
611
612### Available APIs
613
614| API| Description|
615| -------- | -------- |
616| napi_run_event_loop | Runs an underlying event loop.|
617| napi_stop_event_loop | Stops an underlying event loop.|
618
619### Example
620
621#### napi_run_event_loop, napi_stop_event_loop
622
623See [Running or Stopping an Event Loop in an Asynchronous Thread Using Node-API Extensions](use-napi-event-loop.md)
624
625## ArkTS Runtime Environment
626
627### Available APIs
628
629| API| Description|
630| -------- | -------- |
631| napi_create_ark_runtime | Creates an ArkTS runtime environment.|
632| napi_destroy_ark_runtime | Destroys the ArkTS runtime environment.|
633
634### Example
635
636#### napi_create_ark_runtime, napi_destroy_ark_runtime
637
638See [Creating an ArkTs Runtime Environment Using Node-API](use-napi-ark-runtime.md).
639
640## Serialization and Deserialization
641
642### Available APIs
643
644| API| Description|
645| -------- | -------- |
646| 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.|
647| 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.|
648| napi_delete_serialization_data | Deletes serialized data.|
649
650### Example
651
652#### napi_serialize, napi_deserialize, napi_delete_serialization_data
653
654Use **napi_serialize** to convert an ArkTS object into native data; use **napi_deserialize** to convert native data into an ArkTS object; use **napi_delete_serialization_data** to delete serialized data.
655
656CPP code:
657
658```cpp
659#include "napi/native_api.h"
660
661static napi_value AboutSerialize(napi_env env, napi_callback_info info)
662{
663    // Obtain an ArkTS object as a parameter.
664    size_t argc = 1;
665    napi_value args[1] = {nullptr};
666    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
667    napi_value undefined = nullptr;
668    // Construct the parameters required by the napi_serialize method.
669    napi_get_undefined(env, &undefined);
670    void *data = nullptr;
671    // Call napi_serialize to convert the ArkTS object into native data.
672    napi_status status = napi_serialize(env, args[0], undefined, undefined, &data);
673    if (status != napi_ok ||data == nullptr) {
674        napi_throw_error(env, nullptr, "Node-API napi_serialize fail");
675        return nullptr;
676    }
677    // Construct data of the napi_value type to hold the ArkTS object converted from the native data.
678    napi_value result = nullptr;
679    napi_deserialize(env, data, &result);
680    napi_value number = nullptr;
681    // Obtain the value of the numKey property in the ArkTS object converted from native data.
682    napi_get_named_property(env, result, "numKey", &number);
683    // Check whether the obtained property value is of the number type.
684    napi_valuetype valuetype;
685    napi_typeof(env, number, &valuetype);
686    if (valuetype != napi_number) {
687        napi_throw_error(env, nullptr, "Node-API Wrong type of argment. Expects a number.");
688        return nullptr;
689    }
690    // Call napi_delete_serialization_data to delete the serialized data.
691    napi_delete_serialization_data(env, data);
692    // Return the obtained property value.
693    return number;
694}
695```
696
697API declaration:
698
699```ts
700// index.d.ts
701export const aboutSerialize: (obj: Object) => number;
702```
703
704ArkTS code:
705
706```ts
707import hilog from '@ohos.hilog'
708import testNapi from 'libentry.so'
709class Obj {
710  numKey:number = 0;
711}
712let obj: Obj = { numKey: 500 };
713hilog.info(0x0000, 'testTag', ' Node-API aboutSerialize: %{public}d', testNapi.aboutSerialize(obj));
714```
715
716## Passing a Task from an Asynchronous Thread to an ArkTS Thread
717
718### Available APIs
719
720| API| Description|
721| -------- | -------- |
722| napi_call_threadsafe_function_with_priority | Calls a task with the specified priority and enqueuing mode into the ArkTS main thread.|
723
724### Example
725
726#### napi_call_threadsafe_function_with_priority
727
728See [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).
729
730## Sendable-related Operations
731
732### Available APIs
733
734| API                      | Description                              |
735| -------------------------- | ---------------------------------- |
736| napi_is_sendable           | Checks whether an ArkTS value is sendable.|
737| napi_define_sendable_class | Creates a sendable class.              |
738| napi_create_sendable_object_with_properties | Creates a sendable object with the given **napi_property_descriptor**.|
739| napi_create_sendable_array | Creates a sendable array.|
740| napi_create_sendable_array_with_length | Creates a sendable array of the specified length.|
741| napi_create_sendable_arraybuffer | Creates a sendable **ArrayBuffer**.|
742| napi_create_sendable_typedarray | Creates a sendable **TypedArray**.|
743| napi_wrap_sendable | Wraps a native instance into an ArkTS object.|
744| napi_wrap_sendable_with_size | Wraps a native instance of the specified size into an ArkTS object.|
745| napi_unwrap_sendable | Unwraps the native instance from an ArkTS object.|
746| napi_remove_wrap_sendable | Removes the native instance from an ArkTS object.|
747
748### Example
749
750#### napi_is_sendable
751
752Use **napi_is_sendable** to check whether an ArkTS value is sendable.
753
754CPP code:
755
756```cpp
757#include "napi/native_api.h"
758
759static napi_value IsSendable(napi_env env, napi_callback_info info) {
760    size_t argc = 1;
761    napi_value args[1] = {nullptr};
762    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
763    bool isSendable = false;
764    napi_is_sendable(env, args[0], &isSendable);
765    napi_value result;
766    napi_get_boolean(env, isSendable, &result);
767    return result;
768}
769```
770
771API declaration:
772
773```ts
774// index.d.ts
775export const isSendable: <T>(a: T) => boolean;
776```
777
778ArkTS code:
779
780```ts
781import hilog from '@ohos.hilog'
782import testNapi from 'libentry.so'
783
784let value = testNapi.isSendable('createObject');
785hilog.info(0x0000, 'testTag', 'Node-API napi_is_sendable: %{public}s', JSON.stringify(value));
786```
787
788#### napi_define_sendable_class
789
790Use **napi_define_sendable_class** to create a sendable class.
791
792CPP code:
793
794```cpp
795#include "napi/native_api.h"
796
797static napi_value func(napi_env env, napi_callback_info info) {
798    napi_value val;
799    napi_create_string_utf8(env, "func result", NAPI_AUTO_LENGTH, &val);
800    return val;
801}
802
803static napi_value DefineSendableClass(napi_env env) {
804    napi_value str;
805    napi_create_string_utf8(env, "str", NAPI_AUTO_LENGTH, &str);
806
807    napi_property_descriptor props[] = {
808        {"staticStr", nullptr, nullptr, nullptr, nullptr, str,
809         static_cast<napi_property_attributes>(napi_static | napi_writable), nullptr},
810        {"staticFunc", nullptr, func, nullptr, nullptr, nullptr, napi_static, nullptr},
811        {"str", nullptr, nullptr, nullptr, nullptr, str, static_cast<napi_property_attributes>(1 << 9 | napi_writable),
812         nullptr},
813        {"func", nullptr, nullptr, nullptr, nullptr, nullptr,
814         static_cast<napi_property_attributes>(1 << 11 | napi_writable), nullptr},
815    };
816
817    napi_value sendableClass = nullptr;
818    napi_define_sendable_class(
819        env, "SendableClass", NAPI_AUTO_LENGTH,
820        [](napi_env env, napi_callback_info info) -> napi_value {
821            napi_value thisVar = nullptr;
822            napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr);
823            napi_value str;
824            napi_create_string_utf8(env, "instance str", NAPI_AUTO_LENGTH, &str);
825            napi_property_descriptor props[] = {
826                {"str", nullptr, nullptr, nullptr, nullptr, str, napi_default, nullptr},
827                {"func", nullptr, func, nullptr, nullptr, nullptr, napi_default, nullptr},
828            };
829            napi_define_properties(env, thisVar, sizeof(props) / sizeof(props[0]), props);
830            return thisVar;
831        },
832        nullptr, sizeof(props) / sizeof(props[0]), props, nullptr, &sendableClass);
833
834    return sendableClass;
835}
836```
837
838API declaration:
839
840```ts
841// index.d.ts
842@Sendable
843export class SendableClass {
844  static staticStr: string;
845  static staticFunc(): string;
846  str: string;
847  func(): string;
848}
849```
850
851ArkTS code:
852
853```ts
854import hilog from '@ohos.hilog'
855import testNapi from 'libentry.so'
856
857let value = new testNapi.SendableClass();
858hilog.info(0x0000, 'testTag', 'Node-API napi_define_sendable_class: %{public}s', value.str);
859```
860
861#### napi_create_sendable_object_with_properties
862
863Use **napi_create_sendable_object_with_properties** to create a sendable object with the given **napi_property_descriptor**.
864
865CPP code:
866
867```cpp
868#include "napi/native_api.h"
869
870static napi_value GetSendableObject(napi_env env, napi_callback_info info) {
871    napi_value val_true;
872    napi_get_boolean(env, true, &val_true);
873    napi_property_descriptor desc1[] = {
874        {"x", nullptr, nullptr, nullptr, nullptr, val_true, napi_default_jsproperty, nullptr},
875    };
876    napi_value obj;
877    napi_create_sendable_object_with_properties(env, 1, desc1, &obj);
878    return obj;
879}
880```
881
882API declaration:
883
884```ts
885// index.d.ts
886export const getSendableObject: () => { x: true };
887```
888
889ArkTS code:
890
891```ts
892import hilog from '@ohos.hilog'
893import testNapi from 'libentry.so'
894
895let value = testNapi.getSendableObject();
896hilog.info(0x0000, 'testTag', 'Node-API napi_create_sendable_object_with_properties: %{public}s', JSON.stringify(value));
897```
898
899#### napi_create_sendable_array
900
901Use **napi_create_sendable_array** to create a sendable array.
902
903CPP code:
904
905```cpp
906#include "napi/native_api.h"
907
908static napi_value GetSendableArray(napi_env env, napi_callback_info info) {
909    napi_value result = nullptr;
910    napi_create_sendable_array(env, &result);
911    return result;
912}
913```
914
915API declaration:
916
917```ts
918// index.d.ts
919export const getSendableArray: () => [];
920```
921
922ArkTS code:
923
924```ts
925import hilog from '@ohos.hilog'
926import testNapi from 'libentry.so'
927
928let value = testNapi.getSendableArray();
929hilog.info(0x0000, 'testTag', 'Node-API napi_create_sendable_array: %{public}s', JSON.stringify(value));
930```
931
932#### napi_create_sendable_array_with_length
933
934Use **napi_create_sendable_array_with_length** to create a sendable array of the specified length.
935
936CPP code:
937
938```cpp
939static napi_value GetSendableArrayWithLength(napi_env env, napi_callback_info info) {
940    napi_value result = nullptr;
941    napi_create_sendable_array_with_length(env, 1, &result);
942    return result;
943}
944```
945
946API declaration:
947
948```ts
949// index.d.ts
950export const getSendableArrayWithLength: () => [];
951```
952
953ArkTS code:
954
955```ts
956import hilog from '@ohos.hilog'
957import testNapi from 'libentry.so'
958
959let value = testNapi.getSendableArrayWithLength();
960hilog.info(0x0000, 'testTag', 'Node-API napi_create_sendable_array_with_length: %{public}s', JSON.stringify(value.length));
961```
962
963#### napi_create_sendable_arraybuffer
964
965Use **napi_create_sendable_arraybuffer** to create a sendable **ArrayBuffer**.
966
967CPP code:
968
969```cpp
970#include "napi/native_api.h"
971#include "hilog/log.h"
972
973static napi_value GetSendableArrayBuffer(napi_env env, napi_callback_info info) {
974    static size_t LENGTH = 1024;
975    void *data;
976    napi_value result = nullptr;
977    napi_create_sendable_arraybuffer(env, LENGTH, &data, &result);
978    bool isArrayBuffer = false;
979    napi_is_arraybuffer(env, result, &isArrayBuffer);
980    OH_LOG_INFO(LOG_APP, "isArrayBuffer: %{public}d", isArrayBuffer);
981    return result;
982}
983```
984
985API declaration:
986
987```ts
988// index.d.ts
989export const getSendableArrayBuffer: () => void;
990```
991
992ArkTS code:
993
994```ts
995import hilog from '@ohos.hilog'
996import testNapi from 'libentry.so'
997
998testNapi.getSendableArrayBuffer();
999```
1000
1001#### napi_create_sendable_typedarray
1002
1003Use **napi_create_sendable_typedarray** to create a sendable **TypedArray**.
1004
1005CPP code:
1006
1007```cpp
1008#include "napi/native_api.h"
1009#include "hilog/log.h"
1010
1011static napi_value GetSendableTypedArray(napi_env env, napi_callback_info info) {
1012    static size_t LENGTH = 1024;
1013    static size_t OFFSET = 0;
1014    void *data;
1015    napi_value arraybuffer = nullptr;
1016    napi_create_sendable_arraybuffer(env, LENGTH, &data, &arraybuffer);
1017
1018    napi_value result = nullptr;
1019    napi_create_sendable_typedarray(env, napi_uint8_array, LENGTH, arraybuffer, OFFSET, &result);
1020    bool isTypedArray = false;
1021    napi_is_typedarray(env, result, &isTypedArray);
1022    OH_LOG_INFO(LOG_APP, "isTypedArray: %{public}d", isTypedArray);
1023    return result;
1024}
1025```
1026
1027API declaration:
1028
1029```ts
1030// index.d.ts
1031export const getSendableTypedArray: () => void;
1032```
1033
1034ArkTS code:
1035
1036```ts
1037import hilog from '@ohos.hilog'
1038import testNapi from 'libentry.so'
1039
1040testNapi.getSendableTypedArray();
1041```
1042
1043#### napi_wrap_sendable
1044
1045Use **napi_wrap_sendable** to wrap a native instance into an ArkTS object.
1046
1047CPP code:
1048
1049```cpp
1050#include "napi/native_api.h"
1051
1052static napi_value WrapSendable(napi_env env, napi_callback_info info) {
1053    napi_value val_true;
1054    napi_get_boolean(env, true, &val_true);
1055    napi_property_descriptor desc1[] = {
1056        {"x", nullptr, nullptr, nullptr, nullptr, val_true, napi_default_jsproperty, nullptr},
1057    };
1058    napi_value obj;
1059    napi_create_sendable_object_with_properties(env, 1, desc1, &obj);
1060
1061    const char* testStr = "test";
1062    napi_wrap_sendable(env, obj, (void*)testStr, [](napi_env env, void* data, void* hint) {}, nullptr);
1063
1064    return nullptr;
1065}
1066```
1067
1068API declaration:
1069
1070```ts
1071// index.d.ts
1072export const wrapSendable: () => void;
1073```
1074
1075ArkTS code:
1076
1077```ts
1078import hilog from '@ohos.hilog'
1079import testNapi from 'libentry.so'
1080
1081testNapi.wrapSendable();
1082```
1083
1084#### napi_wrap_sendable_with_size
1085
1086Use **napi_wrap_sendable_with_size** to wrap a native instance of the specified size into an ArkTS object.
1087
1088CPP code:
1089
1090```cpp
1091#include "napi/native_api.h"
1092
1093static napi_value WrapSendableWithSize(napi_env env, napi_callback_info info) {
1094    napi_value val_true;
1095    napi_get_boolean(env, true, &val_true);
1096    napi_property_descriptor desc1[] = {
1097        {"x", nullptr, nullptr, nullptr, nullptr, val_true, napi_default_jsproperty, nullptr},
1098    };
1099    napi_value obj;
1100    napi_create_sendable_object_with_properties(env, 1, desc1, &obj);
1101
1102    const char* testStr = "test";
1103    napi_wrap_sendable_with_size(env, obj, (void*)testStr, [](napi_env env, void* data, void* hint) {}, nullptr, 100);
1104
1105    return nullptr;
1106}
1107```
1108
1109API declaration:
1110
1111```ts
1112// index.d.ts
1113export const wrapSendableWithSize: () => void;
1114```
1115
1116ArkTS code:
1117
1118```ts
1119import hilog from '@ohos.hilog'
1120import testNapi from 'libentry.so'
1121
1122testNapi.wrapSendableWithSize();
1123```
1124
1125#### napi_unwrap_sendable
1126
1127Use **napi_unwrap_sendable** to unwrap the native instance from an ArkTS object.
1128
1129CPP code:
1130
1131```cpp
1132#include "napi/native_api.h"
1133
1134static napi_value UnwrapSendable(napi_env env, napi_callback_info info) {
1135    napi_value val_true;
1136    napi_get_boolean(env, true, &val_true);
1137    napi_property_descriptor desc1[] = {
1138        {"x", nullptr, nullptr, nullptr, nullptr, val_true, napi_default_jsproperty, nullptr},
1139    };
1140    napi_value obj;
1141    napi_create_sendable_object_with_properties(env, 1, desc1, &obj);
1142
1143    const char* testStr = "test";
1144    napi_wrap_sendable(env, obj, (void*)testStr, [](napi_env env, void* data, void* hint) {}, nullptr);
1145
1146    char* tmpTestStr = nullptr;
1147    napi_unwrap_sendable(env, obj, (void**)&tmpTestStr);
1148    OH_LOG_INFO(LOG_APP, "native value is %{public}s", tmpTestStr);
1149
1150    return nullptr;
1151}
1152```
1153
1154API declaration:
1155
1156```ts
1157// index.d.ts
1158export const unwrapSendable: () => void;
1159```
1160
1161ArkTS code:
1162
1163```ts
1164import hilog from '@ohos.hilog'
1165import testNapi from 'libentry.so'
1166
1167testNapi.unwrapSendable();
1168```
1169
1170#### napi_remove_wrap_sendable
1171
1172Use **napi_remove_wrap_sendable** to remove the native instance from an ArkTS object.
1173
1174CPP code:
1175
1176```cpp
1177#include "napi/native_api.h"
1178
1179static napi_value RemoveWrapSendable(napi_env env, napi_callback_info info) {
1180    napi_value val_true;
1181    napi_get_boolean(env, true, &val_true);
1182    napi_property_descriptor desc1[] = {
1183        {"x", nullptr, nullptr, nullptr, nullptr, val_true, napi_default_jsproperty, nullptr},
1184    };
1185    napi_value obj;
1186    napi_create_sendable_object_with_properties(env, 1, desc1, &obj);
1187
1188    const char* testStr = "test";
1189    napi_wrap_sendable(env, obj, (void*)testStr, [](napi_env env, void* data, void* hint) {}, nullptr);
1190
1191    char* tmpTestStr = nullptr;
1192    napi_remove_wrap_sendable(env, obj, (void**)&tmpTestStr);
1193    OH_LOG_INFO(LOG_APP, "native value is %{public}s", tmpTestStr);
1194
1195    return nullptr;
1196}
1197```
1198
1199API declaration:
1200
1201```ts
1202// index.d.ts
1203export const removeWrapSendable: () => void;
1204```
1205
1206ArkTS code:
1207
1208```ts
1209import hilog from '@ohos.hilog'
1210import testNapi from 'libentry.so'
1211
1212testNapi.removeWrapSendable();
1213```
1214
1215To 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"**.
1216
1217```text
1218// CMakeLists.txt
1219add_definitions( "-DLOG_DOMAIN=0xd0d0" )
1220add_definitions( "-DLOG_TAG=\"testTag\"" )
1221target_link_libraries(entry PUBLIC libhilog_ndk.z.so)
1222```
1223