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