• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# 嵌入ArkTS组件
2<!--Kit: ArkUI-->
3<!--Subsystem: ArkUI-->
4<!--Owner: @xiang-shouxing-->
5<!--Designer: @xiang-shouxing-->
6<!--Tester: @sally__-->
7<!--Adviser: @HelloCrease-->
8
9ArkUI在Native侧提供的能力作为ArkTS的子集,部分能力不会在Native侧提供,如声明式UI语法,自定义struct组件,UI高级组件。
10
11
12针对需要使用ArkTS侧独立能力的场景,ArkUI开发框架提供了Native侧嵌入ArkTS组件的能力,该能力依赖[ComponentContent](../reference/apis-arkui/js-apis-arkui-ComponentContent.md)机制,通过ComponentContent完成对ArkTS组件的封装,然后将封装对象转递到Native侧,通过Native侧的[OH_ArkUI_GetNodeHandleFromNapiValue](../reference/apis-arkui/capi-native-node-napi-h.md#oh_arkui_getnodehandlefromnapivalue)接口转化为ArkUI_NodeHandle对象用于Native侧组件挂载使用。
13
14
15> **说明:**
16>
17> - 通过OH_ArkUI_GetNodeHandleFromNapiValue接口获得的ArkUI_NodeHandle对象只能作为子组件参数使用,如[addChild](../reference/apis-arkui/capi-arkui-nativemodule-arkui-nativenodeapi-1.md#addchild)接口的第二个参数,将该对象使用在其他场景下,如[setAttribute](../reference/apis-arkui/capi-arkui-nativemodule-arkui-nativenodeapi-1.md#setattribute)设置属性将不生效并返回错误码。
18>
19> - 针对Native侧修改ArkTS组件的场景,需要在Native侧通过Node-API方式构建ArkTS侧的更新数据,再通过ComponentContent的[update](../reference/apis-arkui/js-apis-arkui-ComponentContent.md#update)接口更新。
20>
21> - [构建自定义组件](ndk-build-custom-components.md)时,相关函数如measureNode等无法对ArkTS模块内部的组件进行调用。
22
23
24以下示例代码在[接入ArkTS页面](ndk-access-the-arkts-page.md)章节基础上引入ArkTS的Refresh组件。
25
26
27**图1** Refresh组件挂载文本列表
28
29![refresh_text_list](figures/refresh_text_list.gif)
30
31
321. 注册ArkTS组件创建函数给Native侧,以便Native侧调用,创建函数使用ComponentContent能力进行封装。
33   ```ts
34   // MixedModule.ets
35   // 使用ComponentContent能力创建ArkTS组件
36
37   import { NodeContent,  UIContext, RefreshModifier, ComponentContent } from '@kit.ArkUI';
38
39   // 定义Native侧和ArkTS进行交互的数据对象。
40   interface NativeRefreshAttribute {
41     isRefreshing: boolean;
42     width?: number;
43     height?: number;
44     backgroundColor?: number;
45     refreshOffset?: number;
46     pullToRefresh?: boolean
47     onRefreshing?: () => void;
48     onOffsetChange?: (offset: number) => void;
49   }
50
51   // 定义@Builder函数的入参格式。
52   interface RefreshAttribute {
53     isRefreshing: boolean;
54     // 属性设置通过Modifier优化性能
55     modifier?: RefreshModifier;
56     slot?: NodeContent;
57     onRefreshing?: () => void;
58     onOffsetChange?: (offset: number) => void;
59   }
60
61   // ComponentContent封装ArkTS组件依赖全局@Builder函数,涉及复杂自定义组件场景,可以在@Builder函数中嵌套@Component自定义组件。
62   // @Builder函数提供入参方式,方便后续通过ComponentContent的update接口进行参数更新。
63   @Builder
64   function mixedRefresh(attribute: RefreshAttribute) {
65     Refresh({ refreshing: attribute.isRefreshing }) {
66       // Refresh作为容器组件,需要使用ContentSlot机制预留子组件占位
67       ContentSlot(attribute.slot)
68     }.attributeModifier(attribute.modifier)
69     .onRefreshing(() => {
70       console.info("on onRefreshing");
71       if (attribute.onRefreshing) {
72         console.info("on native onRefreshing");
73         attribute.onRefreshing();
74       }
75     })
76     .onOffsetChange((value: number) => {
77       console.info("on offset change: " + value);
78       if (attribute.onOffsetChange) {
79         console.info("on native onOffsetChange");
80         attribute.onOffsetChange(value);
81       }
82     })
83   }
84
85   // 定义创建函数的返回值,用于ArkTS侧和Native侧的交互。
86   interface MixedModuleResult {
87     // 定义针对Refresh构建函数的封装对象,用于Native侧转化为ArkUI_NodeHandle对象。
88     content?: ComponentContent<RefreshAttribute>;
89     // Refresh作为容器组件,需要使用ContentSlot机制挂载Native侧的子组件。
90     childSlot?: NodeContent;
91   }
92
93   // 提供创建ArkTS组件的入口函数。
94   export function createMixedRefresh(value: NativeRefreshAttribute): MixedModuleResult {
95     console.info("createMixedRefresh");
96     // 通过AppStorage对象在Ability启动的时候保持UI上下文对象。
97     let uiContent = AppStorage.get<UIContext>("context");
98     let modifier = new RefreshModifier();
99     if (value.width) {
100       modifier.width(value.width)
101     }
102     if (value.height) {
103       modifier.height(value.height)
104     }
105     if (value.backgroundColor) {
106       modifier.backgroundColor(value.backgroundColor)
107     }
108     if (value.pullToRefresh) {
109       modifier.pullToRefresh(value.pullToRefresh)
110     }
111     if (value.refreshOffset) {
112       modifier.refreshOffset(value.refreshOffset)
113     }
114     // 创建NodeContent插槽对象用于Refresh子组件挂载。
115     let nodeSlot = new NodeContent();
116     // 通过ComponentContent创建Refresh组件并将它封装起来。
117     let content = new ComponentContent<RefreshAttribute>(uiContent!, wrapBuilder<[RefreshAttribute]>(mixedRefresh),
118       {
119         isRefreshing: value.isRefreshing,
120         modifier: modifier,
121         slot: nodeSlot,
122         onRefreshing: value.onRefreshing,
123         onOffsetChange: value.onOffsetChange
124       });
125     // 将Refresh组件的封装对象及其子组件插槽对象传递给Native侧。
126     return { content: content, childSlot: nodeSlot };
127   }
128
129   // 定义Refresh组件的更新函数,用于Native侧更新。
130   // 在更新场景下,需要将Refresh组件的封装对象及其子组件插槽对象返回,防止组件重新创建。
131   export function updateMixedRefresh(refresh: ComponentContent<RefreshAttribute>, childSlot: NodeContent,
132     value: NativeRefreshAttribute): void {
133     let modifier = new RefreshModifier();
134     if (value.width) {
135       modifier.width(value.width)
136     }
137     if (value.height) {
138       modifier.height(value.height)
139     }
140     if (value.backgroundColor) {
141       modifier.backgroundColor(value.backgroundColor)
142     }
143     if (value.pullToRefresh) {
144       modifier.pullToRefresh(value.pullToRefresh)
145     }
146     if (value.refreshOffset) {
147       modifier.refreshOffset(value.refreshOffset)
148     }
149     // 调用ComponentContent的update接口进行更新。
150     refresh.update({
151       isRefreshing: value.isRefreshing,
152       modifier: modifier,
153       slot: childSlot,
154       onRefreshing: value.onRefreshing,
155       onOffsetChange: value.onOffsetChange
156     })
157   }
158
159   ```
160
1612. 将创建和更新函数注册给Native侧。
162   ```ts
163   // Index.ets
164   import nativeNode from 'libentry.so';
165   import { NodeContent } from '@kit.ArkUI';
166   import { createMixedRefresh, updateMixedRefresh } from './MixedModule'
167
168   @Entry
169   @Component
170   struct Index {
171     private rootSlot = new NodeContent();
172     @State @Watch('changeNativeFlag') showNative: boolean = false;
173
174     aboutToAppear(): void {
175       // 设置uiContext;
176       AppStorage.setOrCreate<UIContext>("context", this.getUIContext());
177       // 设置混合模式下的builder函数。
178       nativeNode.registerCreateMixedRefreshNode(createMixedRefresh);
179       nativeNode.registerUpdateMixedRefreshNode(updateMixedRefresh);
180     }
181
182     changeNativeFlag(): void {
183       if (this.showNative) {
184         // 创建NativeModule组件挂载
185         nativeNode.createNativeRoot(this.rootSlot)
186       } else {
187         // 销毁NativeModule组件
188         nativeNode.destroyNativeRoot()
189       }
190     }
191
192     build() {
193       Column() {
194         Button(this.showNative ? "HideNativeUI" : "ShowNativeUI").onClick(() => {
195           this.showNative = !this.showNative
196         })
197         Row() {
198           // ArkTS插入Native组件。
199           ContentSlot(this.rootSlot)
200         }.layoutWeight(1)
201       }
202       .width('100%')
203       .height('100%')
204     }
205   }
206   ```
207
208   ```cpp
209   // native_init.cpp
210   #include "napi/native_api.h"
211   #include "ArkUIMixedRefresh.h"
212   #include "NativeEntry.h"
213
214   EXTERN_C_START
215   static napi_value Init(napi_env env, napi_value exports) {
216       napi_property_descriptor desc[] = {
217           // 注册NDK根节点。
218           {"createNativeRoot", nullptr, NativeModule::CreateNativeRoot, nullptr, nullptr, nullptr, napi_default, nullptr},
219           // 注册混合模式创建和更新方法。
220           {"registerCreateMixedRefreshNode", nullptr, NativeModule::ArkUIMixedRefresh::RegisterCreateAndUpdateRefresh, nullptr,
221            nullptr, nullptr, napi_default, nullptr},
222           // 销毁NDK根节点。
223           {"destroyNativeRoot", nullptr, NativeModule::DestroyNativeRoot, nullptr, nullptr, nullptr, napi_default,
224            nullptr}};
225       napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
226       return exports;
227   }
228   EXTERN_C_END
229
230   static napi_module demoModule = {
231       .nm_version = 1,
232       .nm_flags = 0,
233       .nm_filename = nullptr,
234       .nm_register_func = Init,
235       .nm_modname = "entry",
236       .nm_priv = ((void *)0),
237       .reserved = {0},
238   };
239
240   extern "C" __attribute__((constructor)) void RegisterEntryModule(void) { napi_module_register(&demoModule); }
241   ```
242
2433. Native侧通过Node-API保存创建和更新函数,用于后续调用。
244   ```c
245   // ArkUIMixedRefresh.h
246   // 混合模式交互类。
247
248   #ifndef MYAPPLICATION_ARKUIMIXEDREFRESH_H
249   #define MYAPPLICATION_ARKUIMIXEDREFRESH_H
250
251   #include "ArkUIMixedNode.h"
252
253   #include <optional>
254
255   #include <arkui/native_node_napi.h>
256   #include <js_native_api_types.h>
257
258   namespace NativeModule {
259
260   class ArkUIMixedRefresh : public ArkUIMixedNode {
261   public:
262       static napi_value RegisterCreateAndUpdateRefresh(napi_env env, napi_callback_info info);
263   };
264
265   } // namespace NativeModule
266
267   #endif // MYAPPLICATION_ARKUIMIXEDREFRESH_H
268   ```
269
270   ```cpp
271   // ArkUIMixedRefresh.cpp
272   // 混合模式交互类。
273
274   #include "ArkUIMixedRefresh.h"
275
276   namespace NativeModule {
277   namespace {
278   napi_env g_env;
279   napi_ref g_createRefresh;
280   napi_ref g_updateRefresh;
281   } // namespace
282
283   napi_value ArkUIMixedRefresh::RegisterCreateAndUpdateRefresh(napi_env env, napi_callback_info info) {
284       size_t argc = 1;
285       napi_value args[1] = {nullptr};
286
287       napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
288
289       g_env = env;
290       napi_ref refer;
291       // 创建引用之后保存,防止释放。
292       napi_create_reference(env, args[0], 1, &refer);
293
294       g_createRefresh = refer;
295       return nullptr;
296   }
297
298   } // namespace NativeModule
299   ```
300
301   ```cpp
302   // CMakeLists.txt
303   // optional依赖C++17
304
305   # the minimum version of CMake.
306   cmake_minimum_required(VERSION 3.4.1)
307   project(testndk)
308
309   set(CMAKE_CXX_STANDARD 17)
310   set(NATIVERENDER_ROOT_PATH ${CMAKE_CURRENT_SOURCE_DIR})
311
312   include_directories(${NATIVERENDER_ROOT_PATH}
313                        ${NATIVERENDER_ROOT_PATH}/include)
314
315   add_library(nativeNode SHARED container.cpp manager.cpp init.cpp)
316   # target_link_libraries(entry PUBLIC libace_napi.z.so, libace_ndk.z.so, libhilog_ndk.z.so)
317
318   find_library(
319        # Sets the name of the path variable.
320        hilog-lib
321        # Specifies the name of the NDK library that
322        # you want CMake to locate.
323        hilog_ndk.z
324    )
325
326   find_library(
327        # Sets the name of the path variable.
328        libace-lib
329        # Specifies the name of the NDK library that
330        # you want CMake to locate.
331        ace_ndk.z
332    )
333
334   find_library(
335        # Sets the name of the path variable.
336        libnapi-lib
337        # Specifies the name of the NDK library that
338        # you want CMake to locate.
339        ace_napi.z
340    )
341
342   target_link_libraries(nativeNode PUBLIC
343        ${hilog-lib} ${libace-lib} ${libnapi-lib} )
344   ```
345
3464. 抽象混合模式下组件的基类,用于通用逻辑管理。
347   ```c
348   // ArkUIMixedNode.h
349   // 混合模式基类。
350
351   #ifndef MYAPPLICATION_ARKUIMIXEDNODE_H
352   #define MYAPPLICATION_ARKUIMIXEDNODE_H
353
354   #include <js_native_api.h>
355   #include <js_native_api_types.h>
356
357   #include "ArkUIBaseNode.h"
358   #include "NativeModule.h"
359
360   namespace NativeModule {
361
362   // Wrap ArkTS Node
363   class ArkUIMixedNode : public ArkUIBaseNode {
364   public:
365       ArkUIMixedNode(ArkUI_NodeHandle handle, napi_env env, napi_ref componentContent)
366           : ArkUIBaseNode(handle), env_(env), componentContent_(componentContent) {}
367
368       // 在基类析构的时候需要把混合模式在ArkTS侧的对象释放掉。
369       ~ArkUIMixedNode() override { napi_delete_reference(env_, componentContent_); }
370
371   protected:
372       napi_env env_;
373       napi_ref componentContent_;
374   };
375
376   } // namespace NativeModule
377
378   #endif // MYAPPLICATION_ARKUIMIXEDNODE_H
379   ```
380
3815. 实现Refresh组件的混合模式封装对象。
382   ```c
383   // ArkUIMixedRefresh.h
384   // Refresh混合模式在Native侧的封装对象。
385
386   #ifndef MYAPPLICATION_ARKUIMIXEDREFRESH_H
387   #define MYAPPLICATION_ARKUIMIXEDREFRESH_H
388
389   #include "ArkUIMixedNode.h"
390   #include "ArkUIBaseNode.h"
391
392   #include <optional>
393
394   #include <arkui/native_node_napi.h>
395   #include <js_native_api_types.h>
396
397   namespace NativeModule {
398
399   // 定义Native侧和ArkTS侧的交互数据结构。
400   struct NativeRefreshAttribute {
401       std::optional<bool> isRefreshing;
402       std::optional<float> width;
403       std::optional<float> height;
404       std::optional<uint32_t> backgroundColor;
405       std::optional<float> refreshOffset;
406       std::optional<bool> pullToRefresh;
407       std::function<void()> onRefreshing;
408       std::function<void(float)> onOffsetChange;
409   };
410
411   class ArkUIMixedRefresh : public ArkUIMixedNode {
412   public:
413       // 调用ArkTS的方法创建Refresh组件。
414       static const std::shared_ptr<ArkUIMixedRefresh> Create(const NativeRefreshAttribute &attribute);
415
416       ArkUIMixedRefresh(ArkUI_NodeHandle handle, ArkUI_NodeContentHandle contentHandle, napi_env env,
417                         napi_ref componentContent, napi_ref nodeContent)
418           : ArkUIMixedNode(handle, env, componentContent), contentHandle_(contentHandle), nodeContent_(nodeContent) {}
419
420       ArkUIMixedRefresh() : ArkUIMixedNode(nullptr, nullptr, nullptr) {}
421
422       ~ArkUIMixedRefresh() override { napi_delete_reference(env_, nodeContent_); } // 释放子节点占位组件插槽对象。
423
424       void SetWidth(float width) { attribute_.width = width; }
425
426       void SetHeight(float height) { attribute_.height = height; }
427
428       void SetBackgroundColor(uint32_t color) { attribute_.backgroundColor = color; }
429
430       void SetRefreshState(bool isRefreshing) { attribute_.isRefreshing = isRefreshing; }
431
432       void SetPullToRefresh(bool pullToRefresh) { attribute_.pullToRefresh = pullToRefresh; }
433
434       void SetRefreshOffset(float offset) { attribute_.refreshOffset = offset; }
435
436       void SetRefreshCallback(const std::function<void()> &callback) { attribute_.onRefreshing = callback; }
437
438       void SetOnOffsetChange(const std::function<void(float)> &callback) { attribute_.onOffsetChange = callback; }
439
440       // 避免频繁跨语言,在Native侧缓存属性事件,批量通知。
441       void FlushMixedModeCmd();
442
443       static napi_value RegisterCreateAndUpdateRefresh(napi_env env, napi_callback_info info);
444
445   protected:
446       void OnAddChild(const std::shared_ptr<ArkUIBaseNode> &child) override {
447           assert(contentHandle_);
448           // 使用NodeContent挂载组件(可以使用ArkTS在Native侧通过ComponentContent的转化对象,也可以是纯Native组件)到ArkTS组件下面。
449           OH_ArkUI_NodeContent_AddNode(contentHandle_, child->GetHandle());
450       }
451
452       void OnRemoveChild(const std::shared_ptr<ArkUIBaseNode> &child) override {
453           assert(contentHandle_);
454           // 使用NodeContent卸载组件。
455           OH_ArkUI_NodeContent_RemoveNode(contentHandle_, child->GetHandle());
456       }
457
458       void OnInsertChild(const std::shared_ptr<ArkUIBaseNode> &child, int32_t index) override {
459           assert(contentHandle_);
460           // 使用NodeContent插入组件。
461           OH_ArkUI_NodeContent_InsertNode(contentHandle_, child->GetHandle(), index);
462       }
463
464   private:
465       // 使用napi接口创建ArkTS侧的数据结构。
466       static napi_value CreateRefreshAttribute(const NativeRefreshAttribute &attribute, void *userData);
467
468       ArkUI_NodeContentHandle contentHandle_;
469       napi_ref nodeContent_;
470       NativeRefreshAttribute attribute_;
471   };
472
473   } // namespace NativeModule
474
475   #endif // MYAPPLICATION_ARKUIMIXEDREFRESH_H
476   ```
477
478   相关实现类说明:
479
480   ```c
481   // ArkUIMixedRefresh.cpp
482
483   #include "ArkUIMixedRefresh.h"
484   #include <hilog/log.h>
485
486   namespace NativeModule {
487   namespace {
488   napi_env g_env;
489   napi_ref g_createRefresh;
490   napi_ref g_updateRefresh;
491   } // namespace
492
493   // 使用Napi接口创建与ArkTS侧交互的数据结构,用于Refresh组件的创建和更新。
494   napi_value ArkUIMixedRefresh::CreateRefreshAttribute(const NativeRefreshAttribute &attribute, void *userData) {
495       napi_property_descriptor desc[] = {
496           {"width", nullptr, nullptr, nullptr, nullptr, nullptr, napi_default, userData},
497           {"height", nullptr, nullptr, nullptr, nullptr, nullptr, napi_default, userData},
498           {"backgroundColor", nullptr, nullptr, nullptr, nullptr, nullptr, napi_default, userData},
499           {"pullToRefresh", nullptr, nullptr, nullptr, nullptr, nullptr, napi_default, userData},
500           {"isRefreshing", nullptr, nullptr, nullptr, nullptr, nullptr, napi_default, userData},
501           {"refreshOffset", nullptr, nullptr, nullptr, nullptr, nullptr, napi_default, userData},
502           {"onRefreshing", nullptr, nullptr, nullptr, nullptr, nullptr, napi_default, userData},
503           {"onOffsetChange", nullptr, nullptr, nullptr, nullptr, nullptr, napi_default, userData},
504       };
505       if (attribute.width) {
506           napi_value width;
507           napi_create_double(g_env, attribute.width.value(), &width);
508           desc[0].value = width;
509       }
510       if (attribute.height) {
511           napi_value height;
512           napi_create_double(g_env, attribute.height.value(), &height);
513           desc[1].value = height;
514       }
515       if (attribute.backgroundColor) {
516           napi_value backgroundColor;
517           napi_create_uint32(g_env, attribute.backgroundColor.value(), &backgroundColor);
518           desc[2].value = backgroundColor;
519       }
520       if (attribute.pullToRefresh) {
521           napi_value pullToRefresh;
522           napi_create_int32(g_env, attribute.pullToRefresh.value(), &pullToRefresh);
523           desc[3].value = pullToRefresh;
524       }
525       if (attribute.isRefreshing) {
526           napi_value isRefreshing;
527           napi_create_int32(g_env, attribute.isRefreshing.value(), &isRefreshing);
528           desc[4].value = isRefreshing;
529       }
530       if (attribute.refreshOffset) {
531           napi_value refreshOffset;
532           napi_create_double(g_env, attribute.refreshOffset.value(), &refreshOffset);
533           desc[5].value = refreshOffset;
534       }
535       if (attribute.onRefreshing) {
536           OH_LOG_INFO(LOG_APP, "onRefreshing start");
537           desc[6].method = [](napi_env env, napi_callback_info info) -> napi_value {
538               OH_LOG_INFO(LOG_APP, "onRefreshing callback");
539               size_t argc = 0;
540               napi_value args[0];
541               void *data;
542               napi_get_cb_info(env, info, &argc, args, nullptr, &data);
543               auto refresh = reinterpret_cast<ArkUIMixedRefresh *>(data);
544               if (refresh && refresh->attribute_.onRefreshing) {
545                   refresh->attribute_.onRefreshing();
546               }
547               return nullptr;
548           };
549       }
550       if (attribute.onOffsetChange) {
551           OH_LOG_INFO(LOG_APP, "onOffsetChange start");
552           desc[7].method = [](napi_env env, napi_callback_info info) -> napi_value {
553               OH_LOG_INFO(LOG_APP, "onOffsetChange callback");
554               size_t argc = 1;
555               napi_value args[1] = {nullptr};
556               void *data;
557               napi_get_cb_info(env, info, &argc, args, nullptr, &data);
558               double offset = 0.0;
559               napi_get_value_double(env, args[0], &offset);
560               auto refresh = reinterpret_cast<ArkUIMixedRefresh *>(data);
561               if (refresh && refresh->attribute_.onOffsetChange) {
562                   refresh->attribute_.onOffsetChange(offset);
563               }
564               return nullptr;
565           };
566       }
567       napi_value refreshAttribute = nullptr;
568       auto result = napi_create_object_with_properties(g_env, &refreshAttribute, sizeof(desc) / sizeof(desc[0]), desc);
569       if (result != napi_ok) {
570           return nullptr;
571       }
572       return refreshAttribute;
573   }
574
575   // 创建ArkTS侧的组件并保存在Native侧的封装对象中。
576   const std::shared_ptr<ArkUIMixedRefresh> ArkUIMixedRefresh::Create(const NativeRefreshAttribute &attribute) {
577       napi_handle_scope scope;
578       napi_open_handle_scope(g_env, &scope);
579       auto refresh = std::make_shared<ArkUIMixedRefresh>();
580       auto refreshAttribute = CreateRefreshAttribute(attribute, refresh.get());
581       if (refreshAttribute == nullptr) {
582           napi_close_handle_scope(g_env, scope);
583           return nullptr;
584       }
585       napi_value result = nullptr;
586       napi_value argv[1] = {refreshAttribute};
587       napi_value createRefresh = nullptr;
588       napi_get_reference_value(g_env, g_createRefresh, &createRefresh);
589       // 调用ArkTS的Create函数创建ArkTS的ComponentContent。
590       napi_call_function(g_env, nullptr, createRefresh, 1, argv, &result);
591
592       // 获取ArkTS的Refresh组件。
593       napi_value componentContent = nullptr;
594       napi_get_named_property(g_env, result, "content", &componentContent);
595       ArkUI_NodeHandle handle;
596       OH_ArkUI_GetNodeHandleFromNapiValue(g_env, componentContent, &handle);
597       assert(handle);
598       // 获取ArkTS的Refresh组件的子组件插槽。
599       napi_value nodeContent = nullptr;
600       napi_get_named_property(g_env, result, "childSlot", &nodeContent);
601       ArkUI_NodeContentHandle contentHandle;
602       OH_ArkUI_GetNodeContentFromNapiValue(g_env, nodeContent, &contentHandle);
603       assert(contentHandle);
604       // 保存ArkTS的ComponentContent用于防止ArkTS侧对象释放以及后续的更新。
605       napi_ref componentContentRef;
606       napi_create_reference(g_env, componentContent, 1, &componentContentRef);
607       // 保存ArkTS的NodeContent用于防止ArkTS侧对象释放以及后续的更新。
608       napi_ref nodeContentRef;
609       napi_create_reference(g_env, nodeContent, 1, &nodeContentRef);
610       // 更新Refresh组件相关参数。
611       refresh->handle_ = handle;
612       refresh->env_ = g_env;
613       refresh->componentContent_ = componentContentRef;
614       refresh->nodeContent_ = nodeContentRef;
615       refresh->contentHandle_ = contentHandle;
616       refresh->attribute_ = attribute;
617       return refresh;
618   }
619   // 更新函数实现。
620   void ArkUIMixedRefresh::FlushMixedModeCmd() {
621       napi_handle_scope scope;
622       napi_open_handle_scope(g_env, &scope);
623       // 创建调用ArkTS接口入参。
624       auto refreshAttribute = CreateRefreshAttribute(attribute_, this);
625       if (refreshAttribute == nullptr) {
626           napi_close_handle_scope(g_env, scope);
627           return;
628       }
629       // 获取更新接口的剩余两个接口参数。
630       napi_value componentContent = nullptr;
631       napi_get_reference_value(g_env, componentContent_, &componentContent);
632       napi_value nodeContent = nullptr;
633       napi_get_reference_value(g_env, nodeContent_, &nodeContent);
634
635       napi_value argv[3] = {componentContent, nodeContent, refreshAttribute};
636       napi_value updateRefresh = nullptr;
637       napi_get_reference_value(g_env, g_updateRefresh, &updateRefresh);
638       // 调用ArkTS的Update函数进行更新。
639       napi_value result = nullptr;
640       napi_call_function(g_env, nullptr, updateRefresh, 3, argv, &result);
641   }
642
643   napi_value ArkUIMixedRefresh::RegisterCreateAndUpdateRefresh(napi_env env, napi_callback_info info) {
644       size_t argc = 1;
645       napi_value args[1] = {nullptr};
646
647       napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
648
649       g_env = env;
650       napi_ref refer;
651       napi_create_reference(env, args[0], 1, &refer);
652
653       g_createRefresh = refer;
654       return nullptr;
655   }
656
657   } // namespace NativeModule
658
659   ```
660
6616. 定时器模块相关简单实现。
662   ```c
663   // UITimer.h
664   // 定时器模块。
665
666   #ifndef MYAPPLICATION_UITIMER_H
667   #define MYAPPLICATION_UITIMER_H
668
669   #include <hilog/log.h>
670   #include <js_native_api.h>
671   #include <js_native_api_types.h>
672   #include <node_api.h>
673   #include <node_api_types.h>
674   #include <string>
675   #include <thread>
676   #include <uv.h>
677
678   namespace NativeModule {
679
680   struct UIData {
681       void *userData = nullptr;
682       int32_t count = 0;
683       int32_t totalCount = 0;
684       void (*func)(void *userData, int32_t count) = nullptr;
685   };
686
687   napi_threadsafe_function threadSafeFunction = nullptr;
688
689   void CreateNativeTimer(napi_env env, void *userData, int32_t totalCount, void (*func)(void *userData, int32_t count)) {
690       napi_value name;
691       std::string str = "UICallback";
692       napi_create_string_utf8(env, str.c_str(), str.size(), &name);
693       // UI主线程回调函数。
694       napi_create_threadsafe_function(
695           env, nullptr, nullptr, name, 0, 1, nullptr, nullptr, nullptr,
696           [](napi_env env, napi_value value, void *context, void *data) {
697               auto userdata = reinterpret_cast<UIData *>(data);
698               userdata->func(userdata->userData, userdata->count);
699               delete userdata;
700           },
701           &threadSafeFunction);
702       // 启动定时器,模拟数据变化。
703       std::thread timerThread([data = userData, totalCount, func]() {
704           uv_loop_t *loop = uv_loop_new();
705           uv_timer_t *timer = new uv_timer_t();
706           uv_timer_init(loop, timer);
707           timer->data = new UIData{data, 0, totalCount, func};
708           uv_timer_start(
709               timer,
710               [](uv_timer_t *handle) {
711                   OH_LOG_INFO(LOG_APP, "on timeout");
712                   napi_acquire_threadsafe_function(threadSafeFunction);
713                   auto *customData = reinterpret_cast<UIData *>(handle->data);
714                   // 创建回调数据。
715                   auto *callbackData =
716                       new UIData{customData->userData, customData->count, customData->totalCount, customData->func};
717                   napi_call_threadsafe_function(threadSafeFunction, callbackData, napi_tsfn_blocking);
718                   customData->count++;
719                   if (customData->count > customData->totalCount) {
720                       uv_timer_stop(handle);
721                       delete handle;
722                       delete customData;
723                   }
724                   delete callbackData;
725               },
726               4000, 4000);
727           uv_run(loop, UV_RUN_DEFAULT);
728           uv_loop_delete(loop);
729       });
730       timerThread.detach();
731   }
732   } // namespace NativeModule
733
734   #endif // MYAPPLICATION_UITIMER_H
735   ```
736
7377. 使用[接入ArkTS页面](ndk-access-the-arkts-page.md)章节的页面结构,并沿用[定时器模块相关简单实现](ndk-embed-arkts-components.md),将Refresh组件作为文本列表的父组件。
738   ```c
739   // MixedRefreshExample.h
740   // 混合模式示例代码。
741
742   #ifndef MYAPPLICATION_MIXEDREFRESHEXAMPLE_H
743   #define MYAPPLICATION_MIXEDREFRESHEXAMPLE_H
744
745   #include "ArkUIBaseNode.h"
746   #include "ArkUIMixedRefresh.h"
747   #include "NormalTextListExample.h"
748   #include "UITimer.h"
749
750   #include <js_native_api_types.h>
751
752   namespace NativeModule {
753
754   std::shared_ptr<ArkUIBaseNode> CreateMixedRefreshList(napi_env env) {
755       auto list = CreateTextListExample();
756       // 混合模式创建Refresh组件并挂载List组件。
757       NativeRefreshAttribute nativeRefreshAttribute{
758           .backgroundColor = 0xFF89CFF0, .refreshOffset = 64, .pullToRefresh = true};
759       auto refresh = ArkUIMixedRefresh::Create(nativeRefreshAttribute);
760       refresh->AddChild(list);
761
762       // 设置混合模式下的事件。
763       refresh->SetOnOffsetChange(
764           [](float offset) { OH_LOG_INFO(LOG_APP, "on refresh offset changed: %{public}f", offset); });
765       refresh->SetRefreshCallback([refreshPtr = refresh.get(), env]() {
766           OH_LOG_INFO(LOG_APP, "on refreshing");
767           // 启动定时器,模拟数据获取。
768           CreateNativeTimer(env, refreshPtr, 1, [](void *userData, int32_t count) {
769               // 数据获取后关闭刷新。
770               auto refresh = reinterpret_cast<ArkUIMixedRefresh *>(userData);
771               refresh->SetRefreshState(false);
772               refresh->FlushMixedModeCmd();
773           });
774       });
775
776       // 更新事件到ArkTS侧。
777       refresh->FlushMixedModeCmd();
778       return refresh;
779   }
780
781   } // namespace NativeModule
782
783   #endif // MYAPPLICATION_MIXEDREFRESHEXAMPLE_H
784   ```
785
786   替换入口组件创建为下拉刷新文本列表。
787
788   ```c
789   // NativeEntry.cpp
790
791   #include "NativeEntry.h"
792
793   #include "ArkUIMixedRefresh.h"
794   #include "MixedRefreshExample.h"
795   #include "NormalTextListExample.h"
796
797   #include <arkui/native_node_napi.h>
798   #include <arkui/native_type.h>
799   #include <js_native_api.h>
800   #include <uv.h>
801
802   namespace NativeModule {
803
804   napi_value CreateNativeRoot(napi_env env, napi_callback_info info) {
805       size_t argc = 1;
806       napi_value args[1] = {nullptr};
807
808       napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
809
810       // 获取NodeContent
811       ArkUI_NodeContentHandle contentHandle;
812       OH_ArkUI_GetNodeContentFromNapiValue(env, args[0], &contentHandle);
813       NativeEntry::GetInstance()->SetContentHandle(contentHandle);
814
815       // 创建Refresh文本列表
816       auto refresh = CreateMixedRefreshList(env);
817
818       // 保持Native侧对象到管理类中,维护生命周期。
819       NativeEntry::GetInstance()->SetRootNode(refresh);
820       return nullptr;
821   }
822
823   napi_value DestroyNativeRoot(napi_env env, napi_callback_info info) {
824       // 从管理类中释放Native侧对象。
825       NativeEntry::GetInstance()->DisposeRootNode();
826       return nullptr;
827   }
828
829   } // namespace NativeModule
830
831   ```
832
833