1# Native与Sendable ArkTS对象绑定 2 3## 场景介绍 4 5通过`napi_wrap_sendable`将Sendable ArkTS对象与Native的C++对象绑定,后续操作时再通过`napi_unwrap_sendable`将ArkTS对象绑定的C++对象取出,并对其进行操作。 6 7## 使用示例 8 91. 接口声明、编译配置以及模块注册 10 11 **接口声明** 12 13 ```ts 14 // index.d.ets 15 @Sendable 16 export class MyObject { 17 constructor(arg: number); 18 plusOne(): number; 19 20 public get value(); 21 public set value(newVal: number); 22 } 23 ``` 24 25 **编译配置** 26 27 ```cmake 28 # the minimum version of CMake. 29 cmake_minimum_required(VERSION 3.5.0) 30 project(napi_wrap_sendable_demo) 31 32 set(NATIVERENDER_ROOT_PATH ${CMAKE_CURRENT_SOURCE_DIR}) 33 34 if(DEFINED PACKAGE_FIND_FILE) 35 include(${PACKAGE_FIND_FILE}) 36 endif() 37 38 include_directories(${NATIVERENDER_ROOT_PATH} 39 ${NATIVERENDER_ROOT_PATH}/include) 40 41 add_definitions("-DLOG_DOMAIN=0x0000") 42 add_definitions("-DLOG_TAG=\"testTag\"") 43 44 add_library(entry SHARED napi_init.cpp) 45 target_link_libraries(entry PUBLIC libace_napi.z.so libhilog_ndk.z.so) 46 ``` 47 48 **模块注册** 49 50 ```cpp 51 // napi_init.cpp 52 #include "napi/native_api.h" 53 #include "hilog/log.h" 54 55 // 一个native类,它的实例在下面会包装在Sendable ArkTS对象中 56 class MyObject { 57 public: 58 static napi_value Init(napi_env env, napi_value exports); 59 static void Destructor(napi_env env, void *nativeObject, void *finalize_hint); 60 61 private: 62 explicit MyObject(double value_ = 0); 63 ~MyObject(); 64 65 static napi_value New(napi_env env, napi_callback_info info); 66 static napi_value GetValue(napi_env env, napi_callback_info info); 67 static napi_value SetValue(napi_env env, napi_callback_info info); 68 static napi_value PlusOne(napi_env env, napi_callback_info info); 69 70 double value_; 71 napi_env env_; 72 }; 73 74 static thread_local napi_ref g_ref = nullptr; 75 76 MyObject::MyObject(double value) : value_(value), env_(nullptr) {} 77 78 MyObject::~MyObject() {} 79 80 void MyObject::Destructor(napi_env env, void *nativeObject, [[maybe_unused]] void *finalize_hint) { 81 OH_LOG_INFO(LOG_APP, "MyObject::Destructor called"); 82 reinterpret_cast<MyObject *>(nativeObject)->~MyObject(); 83 } 84 85 napi_value MyObject::Init(napi_env env, napi_value exports) { 86 napi_value num; 87 napi_create_double(env, 0, &num); 88 napi_property_descriptor properties[] = { 89 {"value", nullptr, nullptr, GetValue, SetValue, nullptr, napi_default, nullptr}, 90 {"plusOne", nullptr, PlusOne, nullptr, nullptr, nullptr, napi_default, nullptr}, 91 }; 92 93 napi_value cons; 94 // 定义一个Sendable class MyObject 95 napi_define_sendable_class(env, "MyObject", NAPI_AUTO_LENGTH, New, nullptr, 96 sizeof(properties) / sizeof(properties[0]), properties, nullptr, &cons); 97 98 napi_create_reference(env, cons, 1, &g_ref); 99 // 在exports对象上挂载MyObject类 100 napi_set_named_property(env, exports, "MyObject", cons); 101 return exports; 102 } 103 104 EXTERN_C_START 105 // 模块初始化 106 static napi_value Init(napi_env env, napi_value exports) { 107 MyObject::Init(env, exports); 108 return exports; 109 } 110 EXTERN_C_END 111 112 // 准备模块加载相关信息,将上述Init函数与本模块名等信息记录下来。 113 static napi_module nativeModule = { 114 .nm_version = 1, 115 .nm_flags = 0, 116 .nm_filename = nullptr, 117 .nm_register_func = Init, 118 .nm_modname = "entry", 119 .nm_priv = nullptr, 120 .reserved = {0}, 121 }; 122 123 // 加载so时,该函数会自动被调用,将上述nativeModule模块注册到系统中。 124 extern "C" __attribute__((constructor)) void RegisterObjectWrapModule() { napi_module_register(&nativeModule); } 125 ``` 126 1272. 在构造函数中绑定Sendable ArkTS与C++对象 128 129 ```cpp 130 napi_value MyObject::New(napi_env env, napi_callback_info info) { 131 OH_LOG_INFO(LOG_APP, "MyObject::New called"); 132 133 napi_value newTarget; 134 napi_get_new_target(env, info, &newTarget); 135 if (newTarget != nullptr) { 136 // 使用`new MyObject(...)`调用方式 137 size_t argc = 1; 138 napi_value args[1]; 139 napi_value jsThis; 140 napi_get_cb_info(env, info, &argc, args, &jsThis, nullptr); 141 142 double value = 0.0; 143 napi_valuetype valuetype; 144 napi_typeof(env, args[0], &valuetype); 145 if (valuetype != napi_undefined) { 146 napi_get_value_double(env, args[0], &value); 147 } 148 149 MyObject *obj = new MyObject(value); 150 151 obj->env_ = env; 152 // 通过napi_wrap_sendable将Sendable ArkTS对象jsThis与C++对象obj绑定 153 napi_wrap_sendable(env, jsThis, reinterpret_cast<void *>(obj), MyObject::Destructor, nullptr); 154 155 return jsThis; 156 } else { 157 // 使用`MyObject(...)`调用方式 158 size_t argc = 1; 159 napi_value args[1]; 160 napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); 161 162 napi_value cons; 163 napi_get_reference_value(env, g_ref, &cons); 164 napi_value instance; 165 napi_new_instance(env, cons, argc, args, &instance); 166 167 return instance; 168 } 169 } 170 ``` 171 1723. 将Sendable ArkTS对象之前绑定的C++对象取出,并对其进行操作 173 174 ```cpp 175 napi_value MyObject::GetValue(napi_env env, napi_callback_info info) { 176 OH_LOG_INFO(LOG_APP, "MyObject::GetValue called"); 177 178 napi_value jsThis; 179 napi_get_cb_info(env, info, nullptr, nullptr, &jsThis, nullptr); 180 181 MyObject *obj; 182 // 通过napi_unwrap_sendable将jsThis之前绑定的C++对象取出,并对其进行操作 183 napi_unwrap_sendable(env, jsThis, reinterpret_cast<void **>(&obj)); 184 napi_value num; 185 napi_create_double(env, obj->value_, &num); 186 187 return num; 188 } 189 190 napi_value MyObject::SetValue(napi_env env, napi_callback_info info) { 191 OH_LOG_INFO(LOG_APP, "MyObject::SetValue called"); 192 193 size_t argc = 1; 194 napi_value value; 195 napi_value jsThis; 196 197 napi_get_cb_info(env, info, &argc, &value, &jsThis, nullptr); 198 199 MyObject *obj; 200 // 通过napi_unwrap_sendable将jsThis之前绑定的C++对象取出,并对其进行操作 201 napi_unwrap_sendable(env, jsThis, reinterpret_cast<void **>(&obj)); 202 napi_get_value_double(env, value, &obj->value_); 203 204 return nullptr; 205 } 206 207 napi_value MyObject::PlusOne(napi_env env, napi_callback_info info) { 208 OH_LOG_INFO(LOG_APP, "MyObject::PlusOne called"); 209 210 napi_value jsThis; 211 napi_get_cb_info(env, info, nullptr, nullptr, &jsThis, nullptr); 212 213 MyObject *obj; 214 // 通过napi_unwrap_sendable将jsThis之前绑定的C++对象取出,并对其进行操作 215 napi_unwrap_sendable(env, jsThis, reinterpret_cast<void **>(&obj)); 216 obj->value_ += 1; 217 napi_value num; 218 napi_create_double(env, obj->value_, &num); 219 220 return num; 221 } 222 ``` 223 2244. ArkTS侧示例代码 225 226 ```ts 227 import hilog from '@ohos.hilog'; 228 import { MyObject } from 'libentry.so'; 229 230 let object : MyObject = new MyObject(0); 231 object.value = 1023; 232 hilog.info(0x0000, 'testTag', 'MyObject value after set: %{public}d', object.value); 233 hilog.info(0x0000, 'testTag', 'MyObject plusOne: %{public}d', object.plusOne()); 234 ``` 235