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