Frontend Development 14 min read

Optimizing HarmonyOS Cross‑Platform UI Rendering with a C Interface Integration

This article analyzes four major performance problems of UI rendering on HarmonyOS—excessive view hierarchy, long communication pipelines, poor list rendering, and secondary layout—and presents a C‑based native component solution with code examples to improve cross‑platform UI performance.

JD Tech Talk
JD Tech Talk
JD Tech Talk
Optimizing HarmonyOS Cross‑Platform UI Rendering with a C Interface Integration

Background

In the dynamic cross‑platform solution article for HarmonyOS, we described how dynamic adaptation is implemented. When UI rendering occurs on HarmonyOS, we use the system's components for recursive rendering. iOS and Android also rely on their respective system components, but HarmonyOS exhibits four serious issues:

1. Excessive UI hierarchy

For example, a "7‑day finance" block in a financial app's LEGO‑style page has 52 layers on HarmonyOS compared to 30 layers on iOS. Too many layers directly affect rendering performance, leading to frame drops and stutter when the hierarchy becomes deep.

2. Long communication pipeline

In the HarmonyOS cross‑platform solution, JavaScript runs in the built‑in V8 engine, communicates with C++ via JSI, and then bridges to ArkTS through Huawei's NAPI. This multi‑language communication incurs high overhead.

3. Poor list rendering performance

Long‑list rendering is a critical metric on iOS, Android, and HarmonyOS. Huawei has released multiple solutions to improve list performance, but third‑party frameworks still suffer from performance problems in complex business scenarios (e.g., community pages) due to ArkUI's design principles.

4. Secondary layout

After integrating with HarmonyOS system components, setting layout properties triggers an additional layout pass by the system.

New Solution Practice

1. Problem analysis

Excessive UI hierarchy: The root cause is that recursive rendering on HarmonyOS requires custom wrapper components (e.g., a Stack container) whereas iOS can directly map a component to a UIView . Each wrapper adds extra layers.

@Componentexport
struct RomaDiv {
build(){
Stack(){
// Use wrapBuilder for recursion
ForEach(this.childrenTags, (childrenTag) => {
RomaComponentFactory.builder() // WrappedBuilder provided by HarmonyOS
})
}
}
}

Long communication pipeline: JavaScript runs in V8, ArkTS runs in Huawei's ArkVM, and multiple threads (JS thread, C++ parser thread, ArkTS main thread) increase latency, plus data type conversions across languages.

Poor list rendering performance: HarmonyOS uses a reactive model similar to Vue's dependency collection. Although Huawei provides a cacheCount mechanism, data changes trigger recursive analysis and off‑screen node updates, causing significant performance drops.

Secondary layout: HarmonyOS integrates the Yoga layout library for cross‑platform use, performing layout calculations before setting component attributes, but the system does not recognize this pre‑layout, resulting in an extra layout pass.

2. New solution overview

After discussions with Huawei, HarmonyOS offers a C‑language imperative interface. The C component interface sits between the native UI implementation and the ArkTS bridge, bypassing state‑management‑driven updates and avoiding costly JS‑engine‑to‑C++ type conversions, thus delivering better performance.

Using the C interface, UI hierarchy aligns with iOS/Android, communication shortens to JS → C++ → C interface, data type conversions are reduced, list rendering can be controlled by the integrator (including pre‑rendering optimizations), and secondary layout is eliminated.

3. How to use

In a real dynamic HarmonyOS cross‑platform project, ArkTS components and C components may be nested (some low‑impact components can remain in ArkTS). The following demo shows complex nesting: ArkTS inserting C, ArkTS inserting ArkTS, C inserting C, and C inserting ArkTS.

3.1 ArkTS inserting C component example

The main steps are:

Create a NodeContent manager.

Place a ContentSlot placeholder in the build function.

Create the node via the C API.

import entry from 'libentry.so';
import { NodeContent } from '@ohos.arkui.node';
@Entry
@Component
struct CMixArkTS{
// 1. NodeContent manager creation
private divNodeContent: NodeContent = new NodeContent();
}
build(){
// 2. ContentSlot placeholder
ContentSlot(this.divNodeContent);
}
aboutToAppear(): void {
// 3. NodeContent node creation (C API)
entry.CreateNativeDivNode(this.divNodeContent);
}

The C implementation of CreateNativeDivNode is as follows:

// 1. C component – green border
static napi_value CreateNativeDivNode(napi_env env, napi_callback_info info) {
if ((env == nullptr) || (info == nullptr)) { return nullptr; }
napi_value returnVal = nullptr;
size_t argc = 1;
napi_value args[1] = {nullptr};
if (napi_get_cb_info(env, info, &argc, args, nullptr, nullptr) != napi_ok) {
OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "napi_init", "CreateNativeNode napi_get_cb_info failed");
}
if (argc != 1) { return nullptr; }
OH_ArkUI_GetNodeContentFromNapiValue(env, args[0], &nodeContentHandle_);
static ArkUI_NativeNodeAPI_1 *nodeAPI = nullptr;
if (nodeAPI == nullptr) {
nodeAPI = reinterpret_cast
(OH_ArkUI_QueryModuleInterfaceByName(ARKUI_NATIVE_NODE, "ArkUI_NativeNodeAPI_1"));
}
if (nodeAPI != nullptr && nodeAPI->createNode != nullptr && nodeAPI->addChild != nullptr) {
ArkUI_NodeHandle DivComponent = CreateDivNodeHandle();
OH_ArkUI_NodeContent_AddNode(nodeContentHandle_, DivComponent);
}
return returnVal;
}
static ArkUI_NodeHandle CreateDivNodeHandle() {
ArkUI_NodeHandle greenDivNodeHandle;
greenDivNodeHandle = CreateDivNodeHandleWithParam(200, 0xFF00FF00);
CAPIManager::GetInstance()->greenDivNodeHandle = greenDivNodeHandle;
return greenDivNodeHandle;
}

Through this process we see that creating and rendering a node via the C API is complex, but once the core steps are understood, development follows the documentation.

For comparison, the iOS equivalent implementation looks like:

- (UIView *) CreateNativeDivNode {
UIView* div = [UIView new];
div.backGroundColor = [UIColor greenColor];
div.frame = CGRectMake(0,0,width,height);
return div;
}

Although the procedure is intricate, it resolves the four problems introduced at the beginning, aligning UI hierarchy depth with other platforms and improving overall performance.

3.2 Other scenarios

The ArkTS‑to‑C component example already demonstrates a considerable amount of code; other scenarios can be explored by referring to the official documentation.

Scan the QR code to join the technical discussion group.

performanceCross‑PlatformUI renderingHarmonyOSArkTSC interface
JD Tech Talk
Written by

JD Tech Talk

Official JD Tech public account delivering best practices and technology innovation.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.