harmony 鸿蒙Wrapping a Native Object in an ArkTS Object

  • 2025-06-12
  • 浏览 (3)

Wrapping a Native Object in an ArkTS Object

When to Use

You can use napi_wrap to wrap a C++ object in an ArkTS object, and use napi_unwrap to retrieve the C++ object previously wrapped in the ArkTS object for subsequent operations.

Example

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

Declare the APIs.

   // index.d.ts
   export class MyObject {
      constructor(arg: number);
      plusOne: () => number;

      public get value();
      public set value(newVal: number);
   }

Configure compile settings.

   # Minimum version of CMake.
   cmake_minimum_required(VERSION 3.5.0)
   project(napi_wrap_demo)

   set(NATIVERENDER_ROOT_PATH ${CMAKE_CURRENT_SOURCE_DIR})

   if(DEFINED PACKAGE_FIND_FILE)
       include(${PACKAGE_FIND_FILE})
   endif()

   include_directories(${NATIVERENDER_ROOT_PATH}
                       ${NATIVERENDER_ROOT_PATH}/include)

   add_definitions("-DLOG_DOMAIN=0x0000")
   add_definitions("-DLOG_TAG=\"testTag\"")

   add_library(entry SHARED napi_init.cpp)
   target_link_libraries(entry PUBLIC libace_napi.z.so libhilog_ndk.z.so)

Register modules.

   // napi_init.cpp
   #include "napi/native_api.h"
   #include "hilog/log.h"

   class MyObject {
    public:
     static napi_value Init(napi_env env, napi_value exports);
     static void Destructor(napi_env env, void* nativeObject, void* finalize_hint);

    private:
     explicit MyObject(double value_ = 0);
     ~MyObject();

     static napi_value New(napi_env env, napi_callback_info info);
     static napi_value GetValue(napi_env env, napi_callback_info info);
     static napi_value SetValue(napi_env env, napi_callback_info info);
     static napi_value PlusOne(napi_env env, napi_callback_info info);

     double value_;
     napi_env env_;
     napi_ref wrapper_;
   };

   static thread_local napi_ref g_ref = nullptr;

   MyObject::MyObject(double value)
       : value_(value), env_(nullptr), wrapper_(nullptr) {}

   MyObject::~MyObject()
   {
     napi_delete_reference(env_, wrapper_);
   }

   void MyObject::Destructor(napi_env env,
                             void* nativeObject,
                             [[maybe_unused]] void* finalize_hint)
   {
     OH_LOG_INFO(LOG_APP, "MyObject::Destructor called");
     delete reinterpret_cast<MyObject*>(nativeObject);
   }

   napi_value MyObject::Init(napi_env env, napi_value exports)
   {
     napi_property_descriptor properties[] = {
         { "value", 0, 0, GetValue, SetValue, 0, napi_default, 0 },
         { "plusOne", nullptr, PlusOne, nullptr, nullptr, nullptr, napi_default, nullptr }
     };

     napi_value cons;
     napi_define_class(env, "MyObject", NAPI_AUTO_LENGTH, New, nullptr, 2,
                              properties, &cons);

     napi_create_reference(env, cons, 1, &g_ref);
     napi_set_named_property(env, exports, "MyObject", cons);
     return exports;
   }

   EXTERN_C_START
   static napi_value Init(napi_env env, napi_value exports)
   {
       MyObject::Init(env, exports);
       return exports;
   }
   EXTERN_C_END

   static napi_module nativeModule = {
       .nm_version = 1,
       .nm_flags = 0,
       .nm_filename = nullptr,
       .nm_register_func = Init,
       .nm_modname = "entry",
       .nm_priv = nullptr,
       .reserved = { 0 },
   };

   extern "C" __attribute__((constructor)) void RegisterObjectWrapModule()
   {
       napi_module_register(&nativeModule);
   }
  1. Wrap a C++ object in an ArkTS object in a constructor.
   napi_value MyObject::New(napi_env env, napi_callback_info info)
   {
     OH_LOG_INFO(LOG_APP, "MyObject::New called");

     napi_value newTarget;
     napi_get_new_target(env, info, &newTarget);
     if (newTarget != nullptr) {
       // Invoked as the constructor `new MyObject(...)`.
       size_t argc = 1;
       napi_value args[1];
       napi_value jsThis;
       napi_get_cb_info(env, info, &argc, args, &jsThis, nullptr);

       double value = 0.0;
       napi_valuetype valuetype;
       napi_typeof(env, args[0], &valuetype);
       if (valuetype != napi_undefined) {
         napi_get_value_double(env, args[0], &value);
       }

       MyObject* obj = new MyObject(value);

       obj->env_ = env;
       // Use napi_wrap to wrap the C++ object obj in the ArkTS object jsThis.
       napi_status status = napi_wrap(env,
                                      jsThis,
                                      reinterpret_cast<void*>(obj),
                                      MyObject::Destructor,
                                      nullptr,  // finalize_hint
                                      &obj->wrapper_);
       // If napi_wrap fails, the allocated memory must be manually released to prevent memory leaks.
       if (status != napi_ok) {
         OH_LOG_INFO(LOG_APP, "Failed to bind native object to js object"
                     ", return code: %{public}d", status);
         delete obj;
         return jsThis;
       }
       // Obtain the napi_ref behavior from result of napi_wrap() to create a strong reference to jsThis.
       // If you do not want to manage the lifecycle of jsThis, pass nullptr in the last parameter of napi_wrap
       // or call napi_reference_unref to convert napi_ref to a weak reference.
       uint32_t refCount = 0;
       napi_reference_unref(env, obj->wrapper_, &refCount);

       return jsThis;
     } else {
       // Invoked as the plain function `MyObject(...)`.
       size_t argc = 1;
       napi_value args[1];
       napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);

       napi_value cons;
       napi_get_reference_value(env, g_ref, &cons);
       napi_value instance;
       napi_new_instance(env, cons, argc, args, &instance);

       return instance;
     }
   }
  1. Retrieve the C++ object from the ArkTS object and perform subsequent operations on the C++ object.
   napi_value MyObject::GetValue(napi_env env, napi_callback_info info)
   {
     OH_LOG_INFO(LOG_APP, "MyObject::GetValue called");

     napi_value jsThis;
     napi_get_cb_info(env, info, nullptr, nullptr, &jsThis, nullptr);

     MyObject* obj;
     // Use napi_unwrap to retrieve obj (the C++ object) previously wrapped in jsThis (the ArkTS object), and perform subsequent operations.
     napi_unwrap(env, jsThis, reinterpret_cast<void**>(&obj));
     napi_value num;
     napi_create_double(env, obj->value_, &num);

     return num;
   }

   napi_value MyObject::SetValue(napi_env env, napi_callback_info info)
   {
     OH_LOG_INFO(LOG_APP, "MyObject::SetValue called");

     size_t argc = 1;
     napi_value value;
     napi_value jsThis;

     napi_get_cb_info(env, info, &argc, &value, &jsThis, nullptr);

     MyObject* obj;
     // Use napi_unwrap to retrieve obj (the C++ object) previously wrapped in jsThis (the ArkTS object), and perform subsequent operations.
     napi_unwrap(env, jsThis, reinterpret_cast<void**>(&obj));
     napi_get_value_double(env, value, &obj->value_);

     return nullptr;
   }

   napi_value MyObject::PlusOne(napi_env env, napi_callback_info info)
   {
     OH_LOG_INFO(LOG_APP, "MyObject::PlusOne called");

     napi_value jsThis;
     napi_get_cb_info(env, info, nullptr, nullptr, &jsThis, nullptr);

     MyObject* obj;
     // Use napi_unwrap to retrieve obj (the C++ object) previously wrapped in jsThis (the ArkTS object), and perform subsequent operations.
     napi_unwrap(env, jsThis, reinterpret_cast<void**>(&obj));
     obj->value_ += 1;
     napi_value num;
     napi_create_double(env, obj->value_, &num);

     return num;
   }
  1. The following provides the sample ArkTS code.
   import hilog from '@ohos.hilog';
   import { MyObject } from 'libentry.so';

   let object : MyObject = new MyObject(0);
   object.value = 1023;
   hilog.info(0x0000, 'testTag', 'MyObject value after set: %{public}d', object.value);
   hilog.info(0x0000, 'testTag', 'MyObject plusOne: %{public}d', object.plusOne());

你可能感兴趣的鸿蒙文章

harmony 鸿蒙Node-API

harmony 鸿蒙Building an NDK Project with CMake

harmony 鸿蒙Building an NDK Project with the DevEco Studio Template

harmony 鸿蒙NDK Project Building Overview

harmony 鸿蒙Building an NDK Project with Prebuilt Libraries

harmony 鸿蒙C/C++ Library Mechanisms

harmony 鸿蒙CPU Features

harmony 鸿蒙Creating an NDK Project

harmony 鸿蒙C/C++ Memory Error Detection

harmony 鸿蒙Debugging in DevEco Studio

0  赞