1# Integrating with ArkTS Pages
2
3
4## Placeholder Components
5
6When building a UI with NDK APIs, you need to create placeholder components in the ArkTS page for mounting components created by the NDK APIs. The placeholder component type is [ContentSlot](../reference/apis-arkui/arkui-ts/ts-components-contentSlot.md), which can bind a **NodeContent** object. This object can be passed to the native side through the Node-API for mounting and displaying native components.
7
8- The usage of placeholder components is the same as other built-in ArkTS components.
9  ```ts
10  import { NodeContent } from '@kit.ArkUI';
11  
12  @Entry
13  @Component
14  struct Index {
15    // Initialize the NodeContent object.
16    private rootSlot = new NodeContent();
17    @State @Watch('changeNativeFlag') showNative: boolean = false;
18  
19    changeNativeFlag(): void {
20      if (this.showNative) {
21        // Pass the NodeContent object for the native side to create component mounting and display.
22        nativeNode.createNativeRoot(this.rootSlot)
23      } else {
24        // Destroy the NativeModule component.
25        nativeNode.destroyNativeRoot()
26      }
27    }
28  
29    build() {
30      Column() {
31        Button(this.showNative ? "HideNativeUI" : "ShowNativeUI").onClick(() => {
32          this.showNative = !this.showNative
33        })
34        Row() {
35          // Bind the NodeContent and ContentSlot placeholder component.
36          ContentSlot(this.rootSlot)
37        }.layoutWeight(1)
38      }
39      .width('100%')
40      .height('100%')
41    }
42  }
43  ```
44
45- The placeholder component can be transformed into a mounting object on the native side through related APIs.
46  ```
47  ArkUI_NodeContentHandle contentHandle;
48  OH_ArkUI_GetNodeContentFromNapiValue(env, args[0], &contentHandle);
49  ```
50
51- The mounting object provides APIs for mounting and unmounting components.
52  ```
53  OH_ArkUI_NodeContent_AddNode(handle_, myNativeNode);
54  OH_ArkUI_NodeContent_RemoveNode(handle_, myNativeNode);
55  ```
56
57
58## NDK Component Module
59
60The UI component capabilities provided by the NDK, including component creation, tree operations, attribute setting, and event registration, are exposed using the function pointer structs (such as [ArkUI_NativeNodeAPI_1](../reference/apis-arkui/_ark_u_i___native_node_a_p_i__1.md)), which can be obtained through the [module query API](../reference/apis-arkui/_ark_u_i___native_module.md#oh_arkui_getmoduleinterface).
61
62```
63ArkUI_NativeNodeAPI_1* arkUINativeNodeApi = nullptr;
64OH_ArkUI_GetModuleInterface(ARKUI_NATIVE_NODE, ArkUI_NativeNodeAPI_1, arkUINativeNodeApi);
65```
66
67
68After obtaining a function pointer struct, use the functions within the struct to perform UI component operations.
69
70
71- Create and destroy components.
72  ```
73  auto listNode = arkUINativeNodeApi->createNode(ARKUI_NODE_LIST);
74  arkUINativeNodeApi->disposeNode(listNode);
75  ```
76
77  You can query the range of components supported by the NDK API through the [ArkUI_NodeType](../reference/apis-arkui/_ark_u_i___native_module.md#arkui_nodetype) API.
78
79- Perform component tree operations.
80  ```
81  auto parent = arkUINativeNodeApi->createNode(ARKUI_NODE_STACK);
82  auto child = arkUINativeNodeApi->createNode(ARKUI_NODE_STACK);
83  arkUINativeNodeApi->addChild(parent, child);
84  arkUINativeNodeApi->removeChild(parent, child);
85  ```
86
87- Set attributes.
88  ```
89  auto stack = arkUINativeNodeApi->createNode(ARKUI_NODE_STACK);
90  ArkUI_NumberValue value[] = {{.f32 = 100}};
91  ArkUI_AttributeItem item = {value, 1};
92  arkUINativeNodeApi->setAttribute(stack, NODE_WIDTH, &item);
93  ArkUI_NumberValue value[] = {{.u32 = 0xff112233}};
94  ArkUI_AttributeItem item = {value, 1};
95  arkUINativeNodeApi->setAttribute(stack, NODE_BACKGROUND_COLOR, &item);
96  ```
97
98  You can query the range of attributes supported by the NDK API through the[ArkUI_NodeAttributeType](../reference/apis-arkui/_ark_u_i___native_module.md#arkui_nodeattributetype) API.
99
100- Register events.
101  ```
102  auto stack = arkUINativeNodeApi->createNode(ARKUI_NODE_STACK);
103  arkUINativeNodeApi->addNodeEventReceiver(stack, [](ArkUI_NodeEvent* event){
104      // process event
105  });
106  arkUINativeNodeApi->registerNodeEvent(stack, NODE_ON_CLICK, 0, nullptr);
107  ```
108
109  You can query the range of events supported by the NDK API through the [ArkUI_NodeEventType](../reference/apis-arkui/_ark_u_i___native_module.md#arkui_nodeeventtype) API.
110
111
112## Example
113
114The following example demonstrates how to use **ContentSlot** to mount a native text list.
115
116**Figure 1** Native text list 
117
118![text_list](figures/text_list.gif)
119
1201. Declare a placeholder component for native page mounting on the ArkTS page, and notify the native side to create a text list when the page is created.
121   ```ts
122   import nativeNode from 'libentry.so';
123   import { NodeContent } from '@kit.ArkUI';
124   
125   @Entry
126   @Component
127   struct Index {
128     // Initialize the NodeContent object.
129     private rootSlot = new NodeContent();
130     @State @Watch('changeNativeFlag') showNative: boolean = false;
131   
132     changeNativeFlag(): void {
133       if (this.showNative) {
134         // Pass the NodeContent object for the native side to create component mounting and display.
135         nativeNode.createNativeRoot(this.rootSlot)
136       } else {
137         // Destroy the NativeModule component.
138         nativeNode.destroyNativeRoot()
139       }
140     }
141   
142     build() {
143       Column() {
144         Button(this.showNative ? "HideNativeUI" : "ShowNativeUI").onClick(() => {
145           this.showNative = !this.showNative
146         })
147         Row() {
148           // Bind the NodeContent and ContentSlot placeholder component.
149           ContentSlot(this.rootSlot)
150         }.layoutWeight(1)
151       }
152       .width('100%')
153       .height('100%')
154     }
155   }
156   ```
157
1582. Use the **Native** template to create a project, and provide a bridging method for the Node-API on the native side, implementing the **NativeNode** module APIs on the ArkTS side.
159   API declaration:
160   ```ts
161   // entry/src/main/cpp/types/libentry/Index.d.ts
162   
163   export const createNativeRoot: (content: Object) => void;
164   export const destroyNativeRoot: () => void;
165   ```
166
167   Native implementation:
168   ```cpp
169   // entry/src/main/cpp/napi_init.cpp
170   
171   #include "NativeEntry.h"
172   #include "napi/native_api.h"
173   
174   EXTERN_C_START
175   static napi_value Init(napi_env env, napi_value exports) {
176       // Bind the native creation and destruction of components.
177       napi_property_descriptor desc[] = {
178           {"createNativeRoot", nullptr, NativeModule::CreateNativeRoot, nullptr, nullptr, nullptr, napi_default, nullptr},
179           {"destroyNativeRoot", nullptr, NativeModule::DestroyNativeRoot, nullptr, nullptr, nullptr, napi_default, nullptr}};
180       napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
181       return exports;
182   }
183   EXTERN_C_END
184   
185   static napi_module demoModule = {
186       .nm_version = 1,
187       .nm_flags = 0,
188       .nm_filename = nullptr,
189       .nm_register_func = Init,
190       .nm_modname = "entry",
191       .nm_priv = ((void *)0),
192       .reserved = {0},
193   };
194   
195   extern "C" __attribute__((constructor)) void RegisterEntryModule(void) { napi_module_register(&demoModule); }
196   ```
197
1983. Create the native page in the **NativeEntry.h** file.
199   ```c
200   // NativeEntry.h
201   
202   #ifndef MYAPPLICATION_NATIVEENTRY_H
203   #define MYAPPLICATION_NATIVEENTRY_H
204   
205   #include <js_native_api_types.h>
206   
207   namespace NativeModule {
208   
209   napi_value CreateNativeRoot(napi_env env, napi_callback_info info);
210   
211   napi_value DestroyNativeRoot(napi_env env, napi_callback_info info);
212   
213   // Manage the lifecycle and memory of the native component.
214   class NativeEntry {
215   public:
216       static NativeEntry *GetInstance() {
217           static NativeEntry nativeEntry;
218           return &nativeEntry;
219       }
220   
221       void SetContentHandle(ArkUI_NodeContentHandle handle) {
222           handle_ = handle;
223       }
224   
225       void SetRootNode(const std::shared_ptr<ArkUIBaseNode> &baseNode) {
226           root_ = baseNode;
227           // Add the native component to NodeContent for mounting and display.
228           OH_ArkUI_NodeContent_AddNode(handle_, root_->GetHandle());
229       }
230       void DisposeRootNode() {
231           // Unmount the component from NodeContent and destroy the native component.
232           OH_ArkUI_NodeContent_RemoveNode(handle_, root_->GetHandle());
233           root_.reset();
234       }
235   
236   private:
237       std::shared_ptr<ArkUIBaseNode> root_;
238       ArkUI_NodeContentHandle handle_;
239   };
240   
241   } // namespace NativeModule
242   
243   #endif // MYAPPLICATION_NATIVEENTRY_H
244   ```
245
246   Corresponding implementation file:
247   ```cpp
248   // NativeEntry.cpp
249   #include "NativeEntry.h"
250
251   #include <arkui/native_node_napi.h>
252   #include <hilog/log.h>
253   #include <js_native_api.h>
254   
255   namespace NativeModule {
256   
257   napi_value CreateNativeRoot(napi_env env, napi_callback_info info) {
258       size_t argc = 1;
259       napi_value args[1] = {nullptr};
260   
261       napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
262   
263       // Obtain NodeContent.
264       ArkUI_NodeContentHandle contentHandle;
265       OH_ArkUI_GetNodeContentFromNapiValue(env, args[0], &contentHandle);
266       NativeEntry::GetInstance()->SetContentHandle(contentHandle);
267   
268       // Create a text list.
269       auto list = CreateTextListExample();
270   
271       // Keep the native side object in the management class to maintain its lifecycle.
272       NativeEntry::GetInstance()->SetRootNode(list);
273       return nullptr;
274   }
275   
276   napi_value DestroyNativeRoot(napi_env env, napi_callback_info info) {
277       // Release the native side object from the management class.
278       NativeEntry::GetInstance()->DisposeRootNode();
279       return nullptr;
280   }
281   
282   } // namespace NativeModule
283   ```
284
285   When using the C APIs provided by the NDK, you need to add a reference to **libace_ndk.z.so** in the **CMakeLists.txt** file, as shown below. Here, **entry** is the name of the dynamic library exported by the project, such as the default name **libentry.so** used in this example.
286   ```
287   target_link_libraries(entry PUBLIC libace_napi.z.so libace_ndk.z.so)
288   ```
289
2904. Since the NDK provides C APIs, to simplify programming and project management in an object-oriented manner, it is recommended that you use C++ for secondary encapsulation. The following example shows the encapsulation classes required for the list and text components on the example page.
291   (1) Obtain the entry module of ArkUI in the NDK API [ArkUI_NativeNodeAPI_1](../reference/apis-arkui/_ark_u_i___native_node_a_p_i__1.md), which provides a series of function pointers for component creation, tree construction, attribute setting, and event registration.
292   ```c
293   // NativeModule.h
294   // Provide encapsulated APIs for obtaining ArkUI modules on the native side.
295   
296   #ifndef MYAPPLICATION_NATIVEMODULE_H
297   #define MYAPPLICATION_NATIVEMODULE_H
298   
299   #include <arkui/native_node.h>
300   #include <functional>
301   #include <cassert>
302   
303   #include <arkui/native_interface.h>
304   
305   namespace NativeModule {
306   
307   class NativeModuleInstance {
308   public:
309       static NativeModuleInstance *GetInstance() {
310           static NativeModuleInstance instance;
311           return &instance;
312       }
313   
314       NativeModuleInstance() {
315           // Obtain the function pointer struct of the NDK API for subsequent operations.
316           OH_ArkUI_GetModuleInterface(ARKUI_NATIVE_NODE, ArkUI_NativeNodeAPI_1, arkUINativeNodeApi_);
317           assert(arkUINativeNodeApi_);
318       }
319       // Expose it for use by other modules.
320       ArkUI_NativeNodeAPI_1 *GetNativeNodeAPI() { return arkUINativeNodeApi_; }
321   
322   private:
323       ArkUI_NativeNodeAPI_1 *arkUINativeNodeApi_ = nullptr;
324   };
325   
326   } // namespace NativeModule
327   
328   #endif // MYAPPLICATION_NATIVEMODULE_H
329   ```
330
331   (2) Provide base class objects for list and text components to encapsulate common properties and events.
332
333   ```c
334   // ArkUIBaseNode.h
335   // Provide a base class for component tree operations.
336   
337   #ifndef MYAPPLICATION_ARKUIBASENODE_H
338   #define MYAPPLICATION_ARKUIBASENODE_H
339   
340   #include <arkui/native_type.h>
341   #include <list>
342   #include <memory>
343   
344   #include "NativeModule.h"
345   
346   namespace NativeModule {
347   
348   class ArkUIBaseNode {
349   public:
350       explicit ArkUIBaseNode(ArkUI_NodeHandle handle)
351           : handle_(handle), nativeModule_(NativeModuleInstance::GetInstance()->GetNativeNodeAPI()) {}
352   
353       virtual ~ArkUIBaseNode() {
354           // Encapsulate the destructor to implement child node removal functionality.
355           if (!children_.empty()) {
356               for (const auto& child : children_) {
357                   nativeModule_->removeChild(handle_, child->GetHandle());
358               }
359               children_.clear();
360           }
361           // Encapsulate the destructor to uniformly recover node resources.
362           nativeModule_->disposeNode(handle_);
363       }
364   
365       void AddChild(const std::shared_ptr<ArkUIBaseNode> &child) {
366           children_.emplace_back(child);
367           OnAddChild(child);
368       }
369   
370       void RemoveChild(const std::shared_ptr<ArkUIBaseNode> &child) {
371           children_.remove(child);
372           OnRemoveChild(child);
373       }
374   
375       void InsertChild(const std::shared_ptr<ArkUIBaseNode> &child, int32_t index) {
376           if (index >= children_.size()) {
377               AddChild(child);
378           } else {
379               auto iter = children_.begin();
380               std::advance(iter, index);
381               children_.insert(iter, child);
382               OnInsertChild(child, index);
383           }
384       }
385   
386       ArkUI_NodeHandle GetHandle() const { return handle_; }
387   
388   protected:
389       // Override the following functions in subclasses that act as parent containers to implement component mounting and unmounting.
390       virtual void OnAddChild(const std::shared_ptr<ArkUIBaseNode> &child) {}
391       virtual void OnRemoveChild(const std::shared_ptr<ArkUIBaseNode> &child) {}
392       virtual void OnInsertChild(const std::shared_ptr<ArkUIBaseNode> &child, int32_t index) {}
393   
394       ArkUI_NodeHandle handle_;
395       ArkUI_NativeNodeAPI_1 *nativeModule_ = nullptr;
396   
397   private:
398       std::list<std::shared_ptr<ArkUIBaseNode>> children_;
399   };
400   } // namespace NativeModule
401   
402   #endif // MYAPPLICATION_ARKUIBASENODE_H
403   ```
404
405   ```c
406   // ArkUINode.h
407   // Provide encapsulation of common properties and events.
408   
409   #ifndef MYAPPLICATION_ARKUINODE_H
410   #define MYAPPLICATION_ARKUINODE_H
411   
412   #include "ArkUIBaseNode.h"
413   #include "NativeModule.h"
414   #include <arkui/native_node.h>
415   #include <arkui/native_type.h>
416   
417   namespace NativeModule {
418   
419   class ArkUINode : public ArkUIBaseNode {
420   public:
421       explicit ArkUINode(ArkUI_NodeHandle handle) : ArkUIBaseNode(handle) {}
422   
423       ~ArkUINode() override {}
424   
425       // Encapsulate the common property call related to the NDK.
426       void SetWidth(float width) {
427           assert(handle_);
428           ArkUI_NumberValue value[] = {{.f32 = width}};
429           ArkUI_AttributeItem item = {value, 1};
430           nativeModule_->setAttribute(handle_, NODE_WIDTH, &item);
431       }
432       void SetPercentWidth(float percent) {
433           assert(handle_);
434           ArkUI_NumberValue value[] = {{.f32 = percent}};
435           ArkUI_AttributeItem item = {value, 1};
436           nativeModule_->setAttribute(handle_, NODE_WIDTH_PERCENT, &item);
437       }
438       void SetHeight(float height) {
439           assert(handle_);
440           ArkUI_NumberValue value[] = {{.f32 = height}};
441           ArkUI_AttributeItem item = {value, 1};
442           nativeModule_->setAttribute(handle_, NODE_HEIGHT, &item);
443       }
444       void SetPercentHeight(float percent) {
445           assert(handle_);
446           ArkUI_NumberValue value[] = {{.f32 = percent}};
447           ArkUI_AttributeItem item = {value, 1};
448           nativeModule_->setAttribute(handle_, NODE_HEIGHT_PERCENT, &item);
449       }
450       void SetBackgroundColor(uint32_t color) {
451           assert(handle_);
452           ArkUI_NumberValue value[] = {{.u32 = color}};
453           ArkUI_AttributeItem item = {value, 1};
454           nativeModule_->setAttribute(handle_, NODE_BACKGROUND_COLOR, &item);
455       }
456   
457   protected:
458       // Implement class docking for component tree operations.
459       void OnAddChild(const std::shared_ptr<ArkUIBaseNode> &child) override {
460           nativeModule_->addChild(handle_, child->GetHandle());
461       }
462       void OnRemoveChild(const std::shared_ptr<ArkUIBaseNode> &child) override {
463           nativeModule_->removeChild(handle_, child->GetHandle());
464       }
465       void OnInsertChild(const std::shared_ptr<ArkUIBaseNode> &child, int32_t index) override {
466           nativeModule_->insertChildAt(handle_, child->GetHandle(), index);
467       }
468   };
469   } // namespace NativeModule
470   
471   #endif // MYAPPLICATION_ARKUINODE_H
472   ```
473
474   (3) Implement the list component.
475
476   ```c
477   // ArkUIListNode.h
478   // Provide encapsulation for the list component. 
479   
480   #ifndef MYAPPLICATION_ARKUILISTNODE_H
481   #define MYAPPLICATION_ARKUILISTNODE_H
482   
483   #include "ArkUINode.h"
484   
485   namespace NativeModule {
486   class ArkUIListNode : public ArkUINode {
487   public:
488       ArkUIListNode()
489           : ArkUINode((NativeModuleInstance::GetInstance()->GetNativeNodeAPI())->createNode(ARKUI_NODE_LIST)) {} // Create the ArkUI list component.
490   
491       ~ArkUIListNode() override {} 
492       // List component's NDK API encapsulation for properties.
493       void SetScrollBarState(bool isShow) {
494           assert(handle_);
495           ArkUI_ScrollBarDisplayMode displayMode =
496               isShow ? ARKUI_SCROLL_BAR_DISPLAY_MODE_ON : ARKUI_SCROLL_BAR_DISPLAY_MODE_OFF;
497           ArkUI_NumberValue value[] = {{.i32 = displayMode}};
498           ArkUI_AttributeItem item = {value, 1};
499           nativeModule_->setAttribute(handle_, NODE_SCROLL_BAR_DISPLAY_MODE, &item);
500       }
501   };
502   } // namespace NativeModule
503   
504   #endif // MYAPPLICATION_ARKUILISTNODE_H
505   ```
506
507   (4) Implement the list item component.
508
509   ```c
510   // ArkUIListItemNode.h
511   // Provide an encapsulation class for list items
512   
513   #ifndef MYAPPLICATION_ARKUISTACKNODE_H
514   #define MYAPPLICATION_ARKUISTACKNODE_H
515   
516   #include "ArkUINode.h"
517   
518   namespace NativeModule {
519   class ArkUIListItemNode : public ArkUINode {
520   public:
521       ArkUIListItemNode()
522           : ArkUINode((NativeModuleInstance::GetInstance()->GetNativeNodeAPI())->createNode(ARKUI_NODE_LIST_ITEM)) {}
523   };
524   } // namespace NativeModule
525   
526   #endif // MYAPPLICATION_ARKUISTACKNODE_H
527   ```
528
529   (5) Implement the text component.
530
531   ```c
532   // ArkUITextNode.h
533   // Implement an encapsulation class for the text component.
534   
535   #ifndef MYAPPLICATION_ARKUITEXTNODE_H
536   #define MYAPPLICATION_ARKUITEXTNODE_H
537   
538   #include "ArkUINode.h"
539   
540   #include <string>
541   
542   namespace NativeModule {
543   class ArkUITextNode : public ArkUINode {
544   public:
545       ArkUITextNode()
546           : ArkUINode((NativeModuleInstance::GetInstance()->GetNativeNodeAPI())->createNode(ARKUI_NODE_TEXT)) {}
547       // Text component's NDK API encapsulation for properties.
548       void SetFontSize(float fontSize) {
549           assert(handle_);
550           ArkUI_NumberValue value[] = {{.f32 = fontSize}};
551           ArkUI_AttributeItem item = {value, 1};
552           nativeModule_->setAttribute(handle_, NODE_FONT_SIZE, &item);
553       }
554       void SetFontColor(uint32_t color) {
555           assert(handle_);
556           ArkUI_NumberValue value[] = {{.u32 = color}};
557           ArkUI_AttributeItem item = {value, 1};
558           nativeModule_->setAttribute(handle_, NODE_FONT_COLOR, &item);
559       }
560       void SetTextContent(const std::string &content) {
561           assert(handle_);
562           ArkUI_AttributeItem item = {nullptr, 0, content.c_str()};
563           nativeModule_->setAttribute(handle_, NODE_TEXT_CONTENT, &item);
564       }
565       void SetTextAlign(ArkUI_TextAlignment align) {
566           assert(handle_);
567           ArkUI_NumberValue value[] = {{.i32 = align}};
568           ArkUI_AttributeItem item = {value, 1};
569           nativeModule_->setAttribute(handle_, NODE_TEXT_ALIGN, &item);
570       }
571   };
572   } // namespace NativeModule
573   
574   #endif // MYAPPLICATION_ARKUITEXTNODE_H
575   ```
576
5775. Complete the **CreateTextListExample** function from step 3 to create and mount the display of the native text list.
578   ```c
579   // NativeEntry.h
580   // Define custom NDK API entry functions.
581   
582   #ifndef MYAPPLICATION_NORMALTEXTLISTEXAMPLE_H
583   #define MYAPPLICATION_NORMALTEXTLISTEXAMPLE_H
584   
585   #include "ArkUIBaseNode.h"
586   #include "ArkUIListItemNode.h"
587   #include "ArkUIListNode.h"
588   #include "ArkUITextNode.h"
589   #include <hilog/log.h>
590   
591   namespace NativeModule {
592   
593   std::shared_ptr<ArkUIBaseNode> CreateTextListExample() {
594       // Create components and mount them.
595       // 1: Use smart pointers to create a List component.
596       auto list = std::make_shared<ArkUIListNode>();
597       list->SetPercentWidth(1);
598       list->SetPercentHeight(1);
599       // 2: Create a ListItem child component and mount it to the List component.
600       for (int32_t i = 0; i < 30; ++i) {
601           auto listItem = std::make_shared<ArkUIListItemNode>();
602           auto textNode = std::make_shared<ArkUITextNode>();
603           textNode->SetTextContent(std::to_string(i));
604           textNode->SetFontSize(16);
605           textNode->SetPercentWidth(1);
606           textNode->SetHeight(100);
607           textNode->SetBackgroundColor(0xFFfffacd);
608           textNode->SetTextAlign(ARKUI_TEXT_ALIGNMENT_CENTER);
609           listItem->AddChild(textNode);
610           list->AddChild(listItem);
611       }
612       return list;
613   }
614   } // namespace NativeModule
615   
616   #endif // MYAPPLICATION_NORMALTEXTLISTEXAMPLE_H
617   ```
618