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