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](../reference/apis-arkui/js-apis-arkui-NodeContent.md) 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. For the sample code, see [Example](#example).
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   #include "napi/native_api.h"
171   #include "NativeEntry.h"
172
173   EXTERN_C_START
174   static napi_value Init(napi_env env, napi_value exports) {
175       // Bind the native creation and destruction of components.
176       napi_property_descriptor desc[] = {
177           {"createNativeRoot", nullptr, NativeModule::CreateNativeRoot, nullptr, nullptr, nullptr, napi_default, nullptr},
178           {"destroyNativeRoot", nullptr, NativeModule::DestroyNativeRoot, nullptr, nullptr, nullptr, napi_default, nullptr}};
179       napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
180       return exports;
181   }
182   EXTERN_C_END
183
184   static napi_module demoModule = {
185       .nm_version = 1,
186       .nm_flags = 0,
187       .nm_filename = nullptr,
188       .nm_register_func = Init,
189       .nm_modname = "entry",
190       .nm_priv = ((void *)0),
191       .reserved = {0},
192   };
193
194   extern "C" __attribute__((constructor)) void RegisterEntryModule(void) { napi_module_register(&demoModule); }
195   ```
196
1973. Create the native page in the **NativeEntry.h** file.
198   ```c
199   // NativeEntry.h
200
201   #ifndef MYAPPLICATION_NATIVEENTRY_H
202   #define MYAPPLICATION_NATIVEENTRY_H
203
204   #include <js_native_api_types.h>
205
206   namespace NativeModule {
207
208   napi_value CreateNativeRoot(napi_env env, napi_callback_info info);
209
210   napi_value DestroyNativeRoot(napi_env env, napi_callback_info info);
211
212   // Manage the lifecycle and memory of the native component.
213   class NativeEntry {
214   public:
215       static NativeEntry *GetInstance() {
216           static NativeEntry nativeEntry;
217           return &nativeEntry;
218       }
219
220       void SetContentHandle(ArkUI_NodeContentHandle handle) {
221           handle_ = handle;
222       }
223
224       void SetRootNode(const std::shared_ptr<ArkUIBaseNode> &baseNode) {
225           root_ = baseNode;
226           // Add the native component to NodeContent for mounting and display.
227           OH_ArkUI_NodeContent_AddNode(handle_, root_->GetHandle());
228       }
229       void DisposeRootNode() {
230           // Unmount the component from NodeContent and destroy the native component.
231           OH_ArkUI_NodeContent_RemoveNode(handle_, root_->GetHandle());
232           root_.reset();
233       }
234
235   private:
236       std::shared_ptr<ArkUIBaseNode> root_;
237       ArkUI_NodeContentHandle handle_;
238   };
239
240   } // namespace NativeModule
241
242   #endif // MYAPPLICATION_NATIVEENTRY_H
243   ```
244
245   Corresponding implementation file:
246   ```cpp
247   // NativeEntry.cpp
248
249   #include <arkui/native_node_napi.h>
250   #include <hilog/log.h>
251   #include <js_native_api.h>
252   #include "NativeEntry.h"
253
254   namespace NativeModule {
255
256   napi_value CreateNativeRoot(napi_env env, napi_callback_info info) {
257       size_t argc = 1;
258       napi_value args[1] = {nullptr};
259
260       napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
261
262       // Obtain NodeContent.
263       ArkUI_NodeContentHandle contentHandle;
264       OH_ArkUI_GetNodeContentFromNapiValue(env, args[0], &contentHandle);
265       NativeEntry::GetInstance()->SetContentHandle(contentHandle);
266
267       // Create a text list.
268       auto list = CreateTextListExample();
269
270       // Keep the native side object in the management class to maintain its lifecycle.
271       NativeEntry::GetInstance()->SetRootNode(list);
272       return nullptr;
273   }
274
275   napi_value DestroyNativeRoot(napi_env env, napi_callback_info info) {
276       // Release the native side object from the management class.
277       NativeEntry::GetInstance()->DisposeRootNode();
278       return nullptr;
279   }
280
281   } // namespace NativeModule
282   ```
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   ```
288   target_link_libraries(entry PUBLIC libace_napi.z.so libace_ndk.z.so)
289   ```
290
2914. 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.
292
293   (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.
294
295   ```c
296   // NativeModule.h
297   // Provide encapsulated APIs for obtaining ArkUI modules on the native side.
298
299   #ifndef MYAPPLICATION_NATIVEMODULE_H
300   #define MYAPPLICATION_NATIVEMODULE_H
301
302   #include <arkui/native_node.h>
303   #include <functional>
304   #include <cassert>
305
306   #include <arkui/native_interface.h>
307
308   namespace NativeModule {
309
310   class NativeModuleInstance {
311   public:
312       static NativeModuleInstance *GetInstance() {
313           static NativeModuleInstance instance;
314           return &instance;
315       }
316
317       NativeModuleInstance() {
318           // Obtain the function pointer struct of the NDK API for subsequent operations.
319           OH_ArkUI_GetModuleInterface(ARKUI_NATIVE_NODE, ArkUI_NativeNodeAPI_1, arkUINativeNodeApi_);
320           assert(arkUINativeNodeApi_);
321       }
322       // Expose it for use by other modules.
323       ArkUI_NativeNodeAPI_1 *GetNativeNodeAPI() { return arkUINativeNodeApi_; }
324
325   private:
326       ArkUI_NativeNodeAPI_1 *arkUINativeNodeApi_ = nullptr;
327   };
328
329   } // namespace NativeModule
330
331   #endif // MYAPPLICATION_NATIVEMODULE_H
332   ```
333
334      (2) Provide base class objects for list and text components to encapsulate common properties and events.
335
336   ```c
337   // ArkUIBaseNode.h
338   // Provide a base class for component tree operations.
339
340   #ifndef MYAPPLICATION_ARKUIBASENODE_H
341   #define MYAPPLICATION_ARKUIBASENODE_H
342
343   #include <arkui/native_type.h>
344   #include <list>
345   #include <memory>
346
347   #include "NativeModule.h"
348
349   namespace NativeModule {
350
351   class ArkUIBaseNode {
352   public:
353       explicit ArkUIBaseNode(ArkUI_NodeHandle handle)
354           : handle_(handle), nativeModule_(NativeModuleInstance::GetInstance()->GetNativeNodeAPI()) {}
355
356       virtual ~ArkUIBaseNode() {
357           // Encapsulate the destructor to implement child node removal functionality.
358           if (!children_.empty()) {
359               for (const auto& child : children_) {
360                   nativeModule_->removeChild(handle_, child->GetHandle());
361               }
362               children_.clear();
363           }
364           // Encapsulate the destructor to uniformly recover node resources.
365           nativeModule_->disposeNode(handle_);
366       }
367
368       void AddChild(const std::shared_ptr<ArkUIBaseNode> &child) {
369           children_.emplace_back(child);
370           OnAddChild(child);
371       }
372
373       void RemoveChild(const std::shared_ptr<ArkUIBaseNode> &child) {
374           children_.remove(child);
375           OnRemoveChild(child);
376       }
377
378       void InsertChild(const std::shared_ptr<ArkUIBaseNode> &child, int32_t index) {
379           if (index >= children_.size()) {
380               AddChild(child);
381           } else {
382               auto iter = children_.begin();
383               std::advance(iter, index);
384               children_.insert(iter, child);
385               OnInsertChild(child, index);
386           }
387       }
388
389       ArkUI_NodeHandle GetHandle() const { return handle_; }
390
391   protected:
392       // Override the following functions in subclasses that act as parent containers to implement component mounting and unmounting.
393       virtual void OnAddChild(const std::shared_ptr<ArkUIBaseNode> &child) {}
394       virtual void OnRemoveChild(const std::shared_ptr<ArkUIBaseNode> &child) {}
395       virtual void OnInsertChild(const std::shared_ptr<ArkUIBaseNode> &child, int32_t index) {}
396
397       ArkUI_NodeHandle handle_;
398       ArkUI_NativeNodeAPI_1 *nativeModule_ = nullptr;
399
400   private:
401       std::list<std::shared_ptr<ArkUIBaseNode>> children_;
402   };
403   } // namespace NativeModule
404
405   #endif // MYAPPLICATION_ARKUIBASENODE_H
406   ```
407
408   ```c
409   // ArkUINode.h
410   // Provide encapsulation of common properties and events.
411
412   #ifndef MYAPPLICATION_ARKUINODE_H
413   #define MYAPPLICATION_ARKUINODE_H
414
415   #include "ArkUIBaseNode.h"
416   #include "NativeModule.h"
417   #include <arkui/native_node.h>
418   #include <arkui/native_type.h>
419
420   namespace NativeModule {
421
422   class ArkUINode : public ArkUIBaseNode {
423   public:
424       explicit ArkUINode(ArkUI_NodeHandle handle) : ArkUIBaseNode(handle) {}
425
426       ~ArkUINode() override {}
427
428       // Encapsulate the common property call related to the NDK.
429       void SetWidth(float width) {
430           assert(handle_);
431           ArkUI_NumberValue value[] = {{.f32 = width}};
432           ArkUI_AttributeItem item = {value, 1};
433           nativeModule_->setAttribute(handle_, NODE_WIDTH, &item);
434       }
435       void SetPercentWidth(float percent) {
436           assert(handle_);
437           ArkUI_NumberValue value[] = {{.f32 = percent}};
438           ArkUI_AttributeItem item = {value, 1};
439           nativeModule_->setAttribute(handle_, NODE_WIDTH_PERCENT, &item);
440       }
441       void SetHeight(float height) {
442           assert(handle_);
443           ArkUI_NumberValue value[] = {{.f32 = height}};
444           ArkUI_AttributeItem item = {value, 1};
445           nativeModule_->setAttribute(handle_, NODE_HEIGHT, &item);
446       }
447       void SetPercentHeight(float percent) {
448           assert(handle_);
449           ArkUI_NumberValue value[] = {{.f32 = percent}};
450           ArkUI_AttributeItem item = {value, 1};
451           nativeModule_->setAttribute(handle_, NODE_HEIGHT_PERCENT, &item);
452       }
453       void SetBackgroundColor(uint32_t color) {
454           assert(handle_);
455           ArkUI_NumberValue value[] = {{.u32 = color}};
456           ArkUI_AttributeItem item = {value, 1};
457           nativeModule_->setAttribute(handle_, NODE_BACKGROUND_COLOR, &item);
458       }
459
460   protected:
461       // Implement class docking for component tree operations.
462       void OnAddChild(const std::shared_ptr<ArkUIBaseNode> &child) override {
463           nativeModule_->addChild(handle_, child->GetHandle());
464       }
465       void OnRemoveChild(const std::shared_ptr<ArkUIBaseNode> &child) override {
466           nativeModule_->removeChild(handle_, child->GetHandle());
467       }
468       void OnInsertChild(const std::shared_ptr<ArkUIBaseNode> &child, int32_t index) override {
469           nativeModule_->insertChildAt(handle_, child->GetHandle(), index);
470       }
471   };
472   } // namespace NativeModule
473
474   #endif // MYAPPLICATION_ARKUINODE_H
475   ```
476
477      (3) Implement the list component.
478
479   ```c
480   // ArkUIListNode.h
481   // Provide encapsulation for the list component.
482
483   #ifndef MYAPPLICATION_ARKUILISTNODE_H
484   #define MYAPPLICATION_ARKUILISTNODE_H
485
486   #include "ArkUINode.h"
487
488   namespace NativeModule {
489   class ArkUIListNode : public ArkUINode {
490   public:
491       ArkUIListNode()
492           : ArkUINode((NativeModuleInstance::GetInstance()->GetNativeNodeAPI())->createNode(ARKUI_NODE_LIST)) {} // Create the ArkUI list component.
493
494       ~ArkUIListNode() override {}
495       // List component's NDK API encapsulation for properties.
496       void SetScrollBarState(bool isShow) {
497           assert(handle_);
498           ArkUI_ScrollBarDisplayMode displayMode =
499               isShow ? ARKUI_SCROLL_BAR_DISPLAY_MODE_ON : ARKUI_SCROLL_BAR_DISPLAY_MODE_OFF;
500           ArkUI_NumberValue value[] = {{.i32 = displayMode}};
501           ArkUI_AttributeItem item = {value, 1};
502           nativeModule_->setAttribute(handle_, NODE_SCROLL_BAR_DISPLAY_MODE, &item);
503       }
504   };
505   } // namespace NativeModule
506
507   #endif // MYAPPLICATION_ARKUILISTNODE_H
508   ```
509
510      (4) Implement the list item component.
511
512   ```c
513   // ArkUIListItemNode.h
514   // Provide an encapsulation class for list items
515
516   #ifndef MYAPPLICATION_ARKUISTACKNODE_H
517   #define MYAPPLICATION_ARKUISTACKNODE_H
518
519   #include "ArkUINode.h"
520
521   namespace NativeModule {
522   class ArkUIListItemNode : public ArkUINode {
523   public:
524       ArkUIListItemNode()
525           : ArkUINode((NativeModuleInstance::GetInstance()->GetNativeNodeAPI())->createNode(ARKUI_NODE_LIST_ITEM)) {}
526   };
527   } // namespace NativeModule
528
529   #endif // MYAPPLICATION_ARKUISTACKNODE_H
530   ```
531
532      (5) Implement the text component.
533
534   ```c
535   // ArkUITextNode.h
536   // Implement an encapsulation class for the text component.
537
538   #ifndef MYAPPLICATION_ARKUITEXTNODE_H
539   #define MYAPPLICATION_ARKUITEXTNODE_H
540
541   #include "ArkUINode.h"
542
543   #include <string>
544
545   namespace NativeModule {
546   class ArkUITextNode : public ArkUINode {
547   public:
548       ArkUITextNode()
549           : ArkUINode((NativeModuleInstance::GetInstance()->GetNativeNodeAPI())->createNode(ARKUI_NODE_TEXT)) {}
550       // Text component's NDK API encapsulation for properties.
551       void SetFontSize(float fontSize) {
552           assert(handle_);
553           ArkUI_NumberValue value[] = {{.f32 = fontSize}};
554           ArkUI_AttributeItem item = {value, 1};
555           nativeModule_->setAttribute(handle_, NODE_FONT_SIZE, &item);
556       }
557       void SetFontColor(uint32_t color) {
558           assert(handle_);
559           ArkUI_NumberValue value[] = {{.u32 = color}};
560           ArkUI_AttributeItem item = {value, 1};
561           nativeModule_->setAttribute(handle_, NODE_FONT_COLOR, &item);
562       }
563       void SetTextContent(const std::string &content) {
564           assert(handle_);
565           ArkUI_AttributeItem item = {nullptr, 0, content.c_str()};
566           nativeModule_->setAttribute(handle_, NODE_TEXT_CONTENT, &item);
567       }
568       void SetTextAlign(ArkUI_TextAlignment align) {
569           assert(handle_);
570           ArkUI_NumberValue value[] = {{.i32 = align}};
571           ArkUI_AttributeItem item = {value, 1};
572           nativeModule_->setAttribute(handle_, NODE_TEXT_ALIGN, &item);
573       }
574   };
575   } // namespace NativeModule
576
577   #endif // MYAPPLICATION_ARKUITEXTNODE_H
578   ```
579
5805. Complete the **CreateTextListExample** function from step 3 to create and mount the display of the native text list.
581   ```c
582   // NormalTextListExample.h
583   // Define custom NDK API entry functions.
584
585   #ifndef MYAPPLICATION_NORMALTEXTLISTEXAMPLE_H
586   #define MYAPPLICATION_NORMALTEXTLISTEXAMPLE_H
587
588   #include "ArkUIBaseNode.h"
589   #include "ArkUIListItemNode.h"
590   #include "ArkUIListNode.h"
591   #include "ArkUITextNode.h"
592   #include <hilog/log.h>
593
594   namespace NativeModule {
595
596   std::shared_ptr<ArkUIBaseNode> CreateTextListExample() {
597       // Create components and mount them.
598       // 1: Use smart pointers to create a List component.
599       auto list = std::make_shared<ArkUIListNode>();
600       list->SetPercentWidth(1);
601       list->SetPercentHeight(1);
602       // 2: Create a ListItem child component and mount it to the List component.
603       for (int32_t i = 0; i < 30; ++i) {
604           auto listItem = std::make_shared<ArkUIListItemNode>();
605           auto textNode = std::make_shared<ArkUITextNode>();
606           textNode->SetTextContent(std::to_string(i));
607           textNode->SetFontSize(16);
608           textNode->SetPercentWidth(1);
609           textNode->SetHeight(100);
610           textNode->SetBackgroundColor(0xFFfffacd);
611           textNode->SetTextAlign(ARKUI_TEXT_ALIGNMENT_CENTER);
612           listItem->AddChild(textNode);
613           list->AddChild(listItem);
614       }
615       return list;
616   }
617   } // namespace NativeModule
618
619   #endif // MYAPPLICATION_NORMALTEXTLISTEXAMPLE_H
620   ```
621