• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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