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