We use essential cookies for the website to function, as well as analytics cookies for analyzing and creating statistics of the website performance. To agree to the use of analytics cookies, click "Accept All". You can manage your preferences at any time by clicking "Cookie Settings" on the footer. More Information.

Only Essential Cookies
Accept All

Wrapping a Native Object in a Sendable ArkTS Object

Content overview

When to Use

You can call napi_wrap_sendable to bind an ArkTS Sendable object to a native C++ object. Then, call napi_unwrap_sendable to obtain the C++ object bound to the ArkTS object and perform operations on the C++ object.

Example

  1. Declare the APIs, configure compile settings, and register the module.

    Declare the APIs.

    Collapse
    Word wrap
    Dark theme
    Copy code
    1. // index.d.ets
    2. @Sendable
    3. export class MyObject {
    4. constructor(arg: number);
    5. plusOne(): number;
    6. public get value();
    7. public set value(newVal: number);
    8. }

    Configure compile settings.

    Collapse
    Word wrap
    Dark theme
    Copy code
    1. # the minimum version of CMake.
    2. cmake_minimum_required(VERSION 3.5.0)
    3. project(napi_wrap_sendable_demo)
    4. set(NATIVERENDER_ROOT_PATH ${CMAKE_CURRENT_SOURCE_DIR})
    5. if(DEFINED PACKAGE_FIND_FILE)
    6. include(${PACKAGE_FIND_FILE})
    7. endif()
    8. include_directories(${NATIVERENDER_ROOT_PATH}
    9. ${NATIVERENDER_ROOT_PATH}/include)
    10. add_definitions("-DLOG_DOMAIN=0x0000")
    11. add_definitions("-DLOG_TAG=\"testTag\"")
    12. add_library(entry SHARED napi_init.cpp)
    13. target_link_libraries(entry PUBLIC libace_napi.z.so libhilog_ndk.z.so)

    Register the module.

    Collapse
    Word wrap
    Dark theme
    Copy code
    1. // napi_init.cpp
    2. #include "napi/native_api.h"
    3. #include "hilog/log.h"
    4. // A native class. Its instance is wrapped in a Sendable ArkTS object.
    5. class MyObject {
    6. public:
    7. static napi_value Init(napi_env env, napi_value exports);
    8. static void Destructor(napi_env env, void *nativeObject, void *finalize_hint);
    9. private:
    10. explicit MyObject(double value_ = 0);
    11. ~MyObject();
    12. static napi_value New(napi_env env, napi_callback_info info);
    13. static napi_value GetValue(napi_env env, napi_callback_info info);
    14. static napi_value SetValue(napi_env env, napi_callback_info info);
    15. static napi_value PlusOne(napi_env env, napi_callback_info info);
    16. double value_;
    17. napi_env env_;
    18. };
    19. static thread_local napi_ref g_ref = nullptr;
    20. MyObject::MyObject(double value) : value_(value), env_(nullptr) {}
    21. MyObject::~MyObject() {}
    22. void MyObject::Destructor(napi_env env, void *nativeObject, [[maybe_unused]] void *finalize_hint) {
    23. OH_LOG_INFO(LOG_APP, "MyObject::Destructor called");
    24. reinterpret_cast<MyObject *>(nativeObject)->~MyObject();
    25. }
    26. napi_value MyObject::Init(napi_env env, napi_value exports) {
    27. napi_value num = nullptr;
    28. napi_status status = napi_create_double(env, 0, &num);
    29. if (status != napi_ok) {
    30. napi_throw_error(env, nullptr, "Node-API napi_create_double fail");
    31. return nullptr;
    32. }
    33. napi_property_descriptor properties[] = {
    34. {"value", nullptr, nullptr, GetValue, SetValue, nullptr, napi_default, nullptr},
    35. {"plusOne", nullptr, PlusOne, nullptr, nullptr, nullptr, napi_default, nullptr},
    36. };
    37. napi_value cons = nullptr;
    38. // Define a Sendable class MyObject.
    39. status = napi_define_sendable_class(env, "MyObject", NAPI_AUTO_LENGTH, New, nullptr,
    40. sizeof(properties) / sizeof(properties[0]), properties, nullptr, &cons);
    41. if (status != napi_ok) {
    42. napi_throw_error(env, nullptr, "Node-API napi_define_sendable_class fail");
    43. return nullptr;
    44. }
    45. status = napi_create_reference(env, cons, 1, &g_ref);
    46. if (status != napi_ok) {
    47. napi_throw_error(env, nullptr, "Node-API napi_create_reference fail");
    48. return nullptr;
    49. }
    50. // Mount the MyObject class to the exports object.
    51. status = napi_set_named_property(env, exports, "MyObject", cons);
    52. if (status != napi_ok) {
    53. napi_throw_error(env, nullptr, "Node-API napi_set_named_property fail");
    54. return nullptr;
    55. }
    56. return exports;
    57. }
    58. EXTERN_C_START
    59. // Initialize the module.
    60. static napi_value Init(napi_env env, napi_value exports) {
    61. MyObject::Init(env, exports);
    62. return exports;
    63. }
    64. EXTERN_C_END
    65. // Information about the module. Record information such as the Init() function and module name.
    66. static napi_module nativeModule = {
    67. .nm_version = 1,
    68. .nm_flags = 0,
    69. .nm_filename = nullptr,
    70. .nm_register_func = Init,
    71. .nm_modname = "entry",
    72. .nm_priv = nullptr,
    73. .reserved = {0},
    74. };
    75. // When the .so file is loaded, this function is automatically called to register the nativeModule module with the system.
    76. extern "C" __attribute__((constructor)) void RegisterObjectWrapModule() { napi_module_register(&nativeModule); }
  2. Wrap a C++ object in a Sendable ArkTS object in a constructor.

    Collapse
    Word wrap
    Dark theme
    Copy code
    1. napi_value MyObject::New(napi_env env, napi_callback_info info) {
    2. OH_LOG_INFO(LOG_APP, "MyObject::New called");
    3. napi_value newTarget = nullptr;
    4. napi_status status = napi_get_new_target(env, info, &newTarget);
    5. if (status != napi_ok) {
    6. napi_throw_error(env, nullptr, "Node-API napi_get_new_target fail");
    7. return nullptr;
    8. }
    9. if (newTarget != nullptr) {
    10. // Invoked as the constructor `new MyObject(...)`.
    11. size_t argc = 1;
    12. napi_value args[1] = { nullptr };
    13. napi_value jsThis = nullptr;
    14. status = napi_get_cb_info(env, info, &argc, args, &jsThis, nullptr);
    15. if (status != napi_ok) {
    16. napi_throw_error(env, nullptr, "Node-API napi_get_cb_info fail");
    17. return nullptr;
    18. }
    19. double value = 0.0;
    20. napi_valuetype valuetype = napi_undefined;
    21. status = napi_typeof(env, args[0], &valuetype);
    22. if (status != napi_ok) {
    23. napi_throw_error(env, nullptr, "Node-API napi_typeof fail");
    24. return nullptr;
    25. }
    26. if (valuetype != napi_undefined) {
    27. status = napi_get_value_double(env, args[0], &value);
    28. if (status != napi_ok) {
    29. napi_throw_error(env, nullptr, "Node-API napi_get_value_double fail");
    30. return nullptr;
    31. }
    32. }
    33. MyObject *obj = new MyObject(value);
    34. obj->env_ = env;
    35. // Use napi_wrap_sendable to wrap obj (the C++ object) in jsThis (the Sendable ArkTS object).
    36. status = napi_wrap_sendable(env, jsThis, reinterpret_cast<void *>(obj), MyObject::Destructor, nullptr);
    37. if (status != napi_ok) {
    38. napi_throw_error(env, nullptr, "Node-API napi_wrap_sendable fail");
    39. delete obj;
    40. return nullptr;
    41. }
    42. return jsThis;
    43. } else {
    44. // Invoked as the plain function `MyObject(...)`.
    45. size_t argc = 1;
    46. napi_value args[1] = { nullptr };
    47. status = napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
    48. if (status != napi_ok) {
    49. napi_throw_error(env, nullptr, "Node-API napi_get_cb_info fail");
    50. return nullptr;
    51. }
    52. napi_value cons = nullptr;
    53. status = napi_get_reference_value(env, g_ref, &cons);
    54. if (status != napi_ok) {
    55. napi_throw_error(env, nullptr, "Node-API napi_get_reference_value fail");
    56. return nullptr;
    57. }
    58. napi_value instance = nullptr;
    59. status = napi_new_instance(env, cons, argc, args, &instance);
    60. if (status != napi_ok) {
    61. napi_throw_error(env, nullptr, "Node-API napi_new_instance fail");
    62. return nullptr;
    63. }
    64. return instance;
    65. }
    66. }
  3. Retrieve the C++ object from the Sendable ArkTS object and perform subsequent operations on the C++ object.

    Collapse
    Word wrap
    Dark theme
    Copy code
    1. napi_value MyObject::GetValue(napi_env env, napi_callback_info info) {
    2. OH_LOG_INFO(LOG_APP, "MyObject::GetValue called");
    3. napi_value jsThis = nullptr;
    4. napi_status status = napi_get_cb_info(env, info, nullptr, nullptr, &jsThis, nullptr);
    5. if (status != napi_ok) {
    6. napi_throw_error(env, nullptr, "Node-API napi_get_cb_info fail");
    7. return nullptr;
    8. }
    9. MyObject *obj = nullptr;
    10. // Use napi_unwrap_sendable to retrieve obj (the C++ object) previously wrapped in jsThis (the Sendable ArkTS object), and perform subsequent operations.
    11. status = napi_unwrap_sendable(env, jsThis, reinterpret_cast<void **>(&obj));
    12. if (status != napi_ok) {
    13. napi_throw_error(env, nullptr, "Node-API napi_unwrap_sendable fail");
    14. return nullptr;
    15. }
    16. napi_value num = nullptr;
    17. status = napi_create_double(env, obj->value_, &num);
    18. if (status != napi_ok) {
    19. napi_throw_error(env, nullptr, "Node-API napi_create_double fail");
    20. return nullptr;
    21. }
    22. return num;
    23. }
    24. napi_value MyObject::SetValue(napi_env env, napi_callback_info info) {
    25. OH_LOG_INFO(LOG_APP, "MyObject::SetValue called");
    26. size_t argc = 1;
    27. napi_value value = nullptr;
    28. napi_value jsThis = nullptr;
    29. napi_status status = napi_get_cb_info(env, info, &argc, &value, &jsThis, nullptr);
    30. if (status != napi_ok) {
    31. napi_throw_error(env, nullptr, "Node-API napi_get_cb_info fail");
    32. return nullptr;
    33. }
    34. MyObject *obj = nullptr;
    35. // Use napi_unwrap_sendable to retrieve obj (the C++ object) previously wrapped in jsThis (the Sendable ArkTS object), and perform subsequent operations.
    36. status = napi_unwrap_sendable(env, jsThis, reinterpret_cast<void **>(&obj));
    37. if (status != napi_ok) {
    38. napi_throw_error(env, nullptr, "Node-API napi_unwrap_sendable fail");
    39. return nullptr;
    40. }
    41. status = napi_get_value_double(env, value, &obj->value_);
    42. if (status != napi_ok) {
    43. napi_throw_error(env, nullptr, "Node-API napi_get_value_double fail");
    44. return nullptr;
    45. }
    46. return nullptr;
    47. }
    48. napi_value MyObject::PlusOne(napi_env env, napi_callback_info info) {
    49. OH_LOG_INFO(LOG_APP, "MyObject::PlusOne called");
    50. napi_value jsThis = nullptr;
    51. napi_status status = napi_get_cb_info(env, info, nullptr, nullptr, &jsThis, nullptr);
    52. if (status != napi_ok) {
    53. napi_throw_error(env, nullptr, "Node-API napi_get_cb_info fail");
    54. return nullptr;
    55. }
    56. MyObject *obj = nullptr;
    57. // Use napi_unwrap_sendable to retrieve obj (the C++ object) previously wrapped in jsThis (the Sendable ArkTS object), and perform subsequent operations.
    58. status = napi_unwrap_sendable(env, jsThis, reinterpret_cast<void **>(&obj));
    59. if (status != napi_ok) {
    60. napi_throw_error(env, nullptr, "Node-API napi_unwrap_sendable fail");
    61. return nullptr;
    62. }
    63. obj->value_ += 1;
    64. napi_value num = nullptr;
    65. status = napi_create_double(env, obj->value_, &num);
    66. if (status != napi_ok) {
    67. napi_throw_error(env, nullptr, "Node-API napi_create_double fail");
    68. return nullptr;
    69. }
    70. return num;
    71. }
  4. ArkTS code:

    Collapse
    Word wrap
    Dark theme
    Copy code
    1. import { hilog } from '@kit.PerformanceAnalysisKit';
    2. import { MyObject } from 'libentry.so';
    3. try {
    4. let object : MyObject = new MyObject(0);
    5. object.value = 1023.1;
    6. hilog.info(0x0000, 'testTag', 'MyObject value after set: %{public}s', object.value.toString());
    7. hilog.info(0x0000, 'testTag', 'MyObject plusOne: %{public}s', object.plusOne().toString());
    8. } catch (error) {
    9. hilog.error(0x0000, 'testTag', 'Test Node-API error: %{public}s', error.message);
    10. }
Search in Guides
Enter a keyword.