• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Native与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`将ArkTS对象与Native的C++对象绑定,后续操作时再通过`napi_unwrap`将ArkTS对象绑定的C++对象取出,并对其进行操作。
12
13## 使用示例
14
151. 接口声明、编译配置以及模块注册
16
17   **接口声明**
18
19   ```ts
20   // index.d.ts
21   export class MyObject {
22      constructor(arg: number);
23      plusOne: () => number;
24
25      public get value();
26      public set value(newVal: number);
27   }
28   ```
29
30   **编译配置**
31
32   ```
33   # the minimum version of CMake.
34   cmake_minimum_required(VERSION 3.5.0)
35   project(napi_wrap_demo)
36
37   set(NATIVERENDER_ROOT_PATH ${CMAKE_CURRENT_SOURCE_DIR})
38
39   if(DEFINED PACKAGE_FIND_FILE)
40       include(${PACKAGE_FIND_FILE})
41   endif()
42
43   include_directories(${NATIVERENDER_ROOT_PATH}
44                       ${NATIVERENDER_ROOT_PATH}/include)
45
46   add_definitions("-DLOG_DOMAIN=0x0000")
47   add_definitions("-DLOG_TAG=\"testTag\"")
48
49   add_library(entry SHARED napi_init.cpp)
50   target_link_libraries(entry PUBLIC libace_napi.z.so libhilog_ndk.z.so)
51   ```
52
53   **模块注册**
54
55   ```cpp
56   // napi_init.cpp
57   #include "napi/native_api.h"
58   #include "hilog/log.h"
59
60   class MyObject {
61    public:
62     static napi_value Init(napi_env env, napi_value exports);
63     static void Destructor(napi_env env, void* nativeObject, void* finalize_hint);
64
65    private:
66     explicit MyObject(double value_ = 0);
67     ~MyObject();
68
69     static napi_value New(napi_env env, napi_callback_info info);
70     static napi_value GetValue(napi_env env, napi_callback_info info);
71     static napi_value SetValue(napi_env env, napi_callback_info info);
72     static napi_value PlusOne(napi_env env, napi_callback_info info);
73
74     double value_;
75     napi_env env_;
76     napi_ref wrapper_;
77   };
78
79   static thread_local napi_ref g_ref = nullptr;
80
81   MyObject::MyObject(double value)
82       : value_(value), env_(nullptr), wrapper_(nullptr) {}
83
84   MyObject::~MyObject()
85   {
86     napi_delete_reference(env_, wrapper_);
87   }
88
89   void MyObject::Destructor(napi_env env,
90                             void* nativeObject,
91                             [[maybe_unused]] void* finalize_hint)
92   {
93     OH_LOG_INFO(LOG_APP, "MyObject::Destructor called");
94     delete reinterpret_cast<MyObject*>(nativeObject);
95   }
96
97   napi_value MyObject::Init(napi_env env, napi_value exports)
98   {
99     napi_property_descriptor properties[] = {
100         { "value", 0, 0, GetValue, SetValue, 0, napi_default, 0 },
101         { "plusOne", nullptr, PlusOne, nullptr, nullptr, nullptr, napi_default, nullptr }
102     };
103
104     napi_value cons;
105     napi_define_class(env, "MyObject", NAPI_AUTO_LENGTH, New, nullptr, 2,
106                              properties, &cons);
107
108     napi_create_reference(env, cons, 1, &g_ref);
109     napi_set_named_property(env, exports, "MyObject", cons);
110     return exports;
111   }
112
113   EXTERN_C_START
114   static napi_value Init(napi_env env, napi_value exports)
115   {
116       MyObject::Init(env, exports);
117       return exports;
118   }
119   EXTERN_C_END
120
121   static napi_module nativeModule = {
122       .nm_version = 1,
123       .nm_flags = 0,
124       .nm_filename = nullptr,
125       .nm_register_func = Init,
126       .nm_modname = "entry",
127       .nm_priv = nullptr,
128       .reserved = { 0 },
129   };
130
131   extern "C" __attribute__((constructor)) void RegisterObjectWrapModule()
132   {
133       napi_module_register(&nativeModule);
134   }
135   ```
136
1372. 在构造函数中绑定ArkTS与C++对象
138
139   ```cpp
140   napi_value MyObject::New(napi_env env, napi_callback_info info)
141   {
142     OH_LOG_INFO(LOG_APP, "MyObject::New called");
143
144     napi_value newTarget;
145     napi_get_new_target(env, info, &newTarget);
146     if (newTarget != nullptr) {
147       // 使用`new MyObject(...)`调用方式
148       size_t argc = 1;
149       napi_value args[1];
150       napi_value jsThis;
151       napi_get_cb_info(env, info, &argc, args, &jsThis, nullptr);
152
153       double value = 0.0;
154       napi_valuetype valuetype;
155       napi_typeof(env, args[0], &valuetype);
156       if (valuetype != napi_undefined) {
157         napi_get_value_double(env, args[0], &value);
158       }
159
160       MyObject* obj = new MyObject(value);
161
162       obj->env_ = env;
163       // 通过napi_wrap将ArkTS对象jsThis与C++对象obj绑定
164       napi_status status = napi_wrap(env,
165                                      jsThis,
166                                      reinterpret_cast<void*>(obj),
167                                      MyObject::Destructor,
168                                      nullptr,  // finalize_hint
169                                      &obj->wrapper_);
170       // napi_wrap失败时,必须手动释放已分配的内存,以防止内存泄漏
171       if (status != napi_ok) {
172         OH_LOG_INFO(LOG_APP, "Failed to bind native object to js object"
173                     ", return code: %{public}d", status);
174         delete obj;
175         return jsThis;
176       }
177       // 从napi_wrap接口的result获取napi_ref的行为,将会为jsThis创建强引用,
178       // 若开发者不需要主动管理jsThis的生命周期,可直接在napi_wrap最后一个参数中传入nullptr,
179       // 或者使用napi_reference_unref方法将napi_ref转为弱引用。
180       uint32_t refCount = 0;
181       napi_reference_unref(env, obj->wrapper_, &refCount);
182
183       return jsThis;
184     } else {
185       // 使用`MyObject(...)`调用方式
186       size_t argc = 1;
187       napi_value args[1];
188       napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
189
190       napi_value cons;
191       napi_get_reference_value(env, g_ref, &cons);
192       napi_value instance;
193       napi_new_instance(env, cons, argc, args, &instance);
194
195       return instance;
196     }
197   }
198   ```
199
2003. 将ArkTS对象之前绑定的C++对象取出,并对其进行操作
201
202   ```cpp
203   napi_value MyObject::GetValue(napi_env env, napi_callback_info info)
204   {
205     OH_LOG_INFO(LOG_APP, "MyObject::GetValue called");
206
207     napi_value jsThis;
208     napi_get_cb_info(env, info, nullptr, nullptr, &jsThis, nullptr);
209
210     MyObject* obj;
211     // 通过napi_unwrap将jsThis之前绑定的C++对象取出,并对其进行操作
212     napi_unwrap(env, jsThis, reinterpret_cast<void**>(&obj));
213     napi_value num;
214     napi_create_double(env, obj->value_, &num);
215
216     return num;
217   }
218
219   napi_value MyObject::SetValue(napi_env env, napi_callback_info info)
220   {
221     OH_LOG_INFO(LOG_APP, "MyObject::SetValue called");
222
223     size_t argc = 1;
224     napi_value value;
225     napi_value jsThis;
226
227     napi_get_cb_info(env, info, &argc, &value, &jsThis, nullptr);
228
229     MyObject* obj;
230     // 通过napi_unwrap将jsThis之前绑定的C++对象取出,并对其进行操作
231     napi_unwrap(env, jsThis, reinterpret_cast<void**>(&obj));
232     napi_get_value_double(env, value, &obj->value_);
233
234     return nullptr;
235   }
236
237   napi_value MyObject::PlusOne(napi_env env, napi_callback_info info)
238   {
239     OH_LOG_INFO(LOG_APP, "MyObject::PlusOne called");
240
241     napi_value jsThis;
242     napi_get_cb_info(env, info, nullptr, nullptr, &jsThis, nullptr);
243
244     MyObject* obj;
245     // 通过napi_unwrap将jsThis之前绑定的C++对象取出,并对其进行操作
246     napi_unwrap(env, jsThis, reinterpret_cast<void**>(&obj));
247     obj->value_ += 1;
248     napi_value num;
249     napi_create_double(env, obj->value_, &num);
250
251     return num;
252   }
253   ```
254
2554. ArkTS侧示例代码
256
257   ```ts
258   import { hilog } from '@kit.PerformanceAnalysisKit';
259   import { MyObject } from 'libentry.so';
260
261   let object : MyObject = new MyObject(0);
262   object.value = 1023;
263   hilog.info(0x0000, 'testTag', 'MyObject value after set: %{public}d', object.value);
264   hilog.info(0x0000, 'testTag', 'MyObject plusOne: %{public}d', object.plusOne());
265   ```
266