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