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 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