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 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