Mobile Development 16 min read

How ArkUI‑X Bridges ArkTS to Android & iOS: Architecture and Clipboard Integration

This article explores the ArkUI‑X cross‑platform framework, detailing its relationship with ArkTS and ArkUI, step‑by‑step environment setup, project creation, the compilation pipeline that generates ViewPU classes, and the intricate bridge that connects ArkTS code to Android and iOS system services such as the clipboard.

Sohu Tech Products
Sohu Tech Products
Sohu Tech Products
How ArkUI‑X Bridges ArkTS to Android & iOS: Architecture and Clipboard Integration

Introduction

ArkUI‑X is a cross‑platform UI framework that extends Huawei's ArkUI to OpenHarmony, HarmonyOS, Android and iOS. It allows developers to write a single ArkTS/ArkUI codebase and run it on multiple OSes.

Relation of ArkTS, ArkUI and ArkUI‑X

ArkTS – a TypeScript‑based language with static typing for Harmony application development.

ArkUI – a declarative UI framework providing components, state management and layout.

ArkUI‑X – an extension that adapts ArkUI descriptions to Android, iOS and OpenHarmony.

Quick Start

Environment setup

Install DevEco Studio ≥ 4.0.0, then download the HarmonyOS SDK and the ArkUI‑X package (or the OpenHarmony SDK for non‑partner developers).

Install Android Studio and set the ANDROID_HOME environment variable to the Android SDK path.

Install Xcode for iOS packaging.

Download links (illustrated):

OpenHarmony SDK download
OpenHarmony SDK download
ArkUI‑X demo download
ArkUI‑X demo download

Create a project

Use the ArkUI‑X basic template. The generated structure is:

entry/                # shared ArkTS source and resources
.arkui‑x/android/     # standard Android project (generated after Build App/Hap)
.arkui‑x/ios/         # standard iOS project (contains project.pbxproj)

Running Build App/Hap creates a .hap file for HarmonyOS and copies the compiled assets into the Android and iOS projects.

Rendering process

Example component (Index.ets):

@Entry
@Component
struct Index {
  @State message: string = '今天星期五'

  build() {
    Row() {
      Column() {
        Text(this.message)
          .fontSize(50)
          .fontWeight(FontWeight.Bold)
      }
      .width('100%')
    }
    .height('100%')
  }
}

After compilation the .hap is unpacked to modules.abc. The compiler generates a JavaScript‑like class extending ViewPU:

class Index extends ViewPU {
  constructor(parent, params, __localStorage, elmtId = -1, paramsLambda = undefined, extraInfo) {
    super(parent, __localStorage, elmtId, extraInfo);
    this.__message = new ObservedPropertySimplePU('今天星期五', this, "message");
    this.setInitiallyProvidedValue(params);
  }
  // ... omitted for brevity ...
  initialRender() {
    Row.create(); Row.height('100%');
    Column.create(); Column.width('100%');
    Text.create(this.message);
    Text.fontSize(50);
    Text.fontWeight(FontWeight.Bold);
    Text.pop(); Column.pop(); Row.pop();
  }
}

The class resides in the arkui_ace_engine repository (e.g.,

frameworks/bridge/declarative_frontend/state_mgmt/src/lib/partial_update/pu_view.ts

) and inherits from PUV2ViewBaseNativeViewPartialUpdate. UI updates are finally performed in C++ via NAPI/JNI bridges.

Architecture overview

ViewPU – base class for all UI components; manages element IDs, local storage and state subscriptions.

PUV2ViewBase – adds partial‑update capabilities.

NativeViewPartialUpdate – C++ class implementing markNeedUpdate() to trigger a repaint in the rendering engine (OpenGL ES / Skia).

Update flow:

Component state change invokes viewPropertyHasChanged in the generated ViewPU.

The @Watch decorator logic runs. markNeedUpdate() is called, which eventually calls ComposedElement::MarkDirty() in the pipeline.

The C++ engine repaints the affected region.

Android implementation

After building for Android the compiled bytecode and resources are placed under src/main/assets/arkui‑x:

src/main/assets/arkui-x
├── entry
│   ├── ets
│   │   ├── modules.abc
│   │   └── sourceMaps.map
│   ├── resources.index
│   ├── resources
│   └── module.json
└── systemres

Native libraries required at runtime are located in libs:

libs
├── armabi-v7a
│   ├── libarkui_android.so
│   └── libhilog.so
└── arkui_android_adapter.jar
libarkui_android.so

bundles arkui_ace_engine, arkui_napi, foundation/appframework and arkui_for_android. The arkui_android_adapter.jar provides Java bridge classes such as StageApplication and StageActivity, mapping Android Activity lifecycles to Harmony Ability lifecycles and exposing system services.

Interaction chain:

ArkTS → NAPI → C++ → JNI → Java

Clipboard integration example:

import pasteboard from '@ohos.pasteboard';
Button('Copy to clipboard')
  .onClick(() => {
    let pasteData = pasteboard.createData(pasteboard.MIMETYPE_TEXT_PLAIN, '明天星期六');
    let systemPasteboard = pasteboard.getSystemPasteboard();
    systemPasteboard.setData(pasteData);
  });

Key native interfaces (C++):

// Clipboard interface
namespace OHOS::Ace {
class Clipboard : public AceType {
public:
  virtual void SetData(const std::string& data,
                       CopyOptions copyOption = CopyOptions::InApp,
                       bool isDragData = false) = 0;
};
}
// Android implementation
void ClipboardImpl::SetData(const std::string& data, CopyOptions copyOption, bool isDragData) {
  taskExecutor_->PostTask([data] { ClipboardJni::SetData(data); },
                         TaskExecutor::TaskType::PLATFORM,
                         "ArkUI‑XClipboardImplSetData");
}
// JNI bridge
bool ClipboardJni::SetData(const std::string& data) {
  auto env = JniEnvironment::GetInstance().GetJniEnv();
  jstring jData = env->NewStringUTF(data.c_str());
  env->CallVoidMethod(g_clipboardObj.get(), g_pluginMethods.setData, jData);
  env->DeleteLocalRef(jData);
  return true;
}
// Java plugin
public class ClipboardPluginAosp extends ClipboardPluginBase {
  private final ClipboardManager clipManager;
  public ClipboardPluginAosp(Context context) {
    this.clipManager = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);
    nativeInit();
  }
  @Override
  public void setData(String data) {
    if (clipManager != null) {
      ClipData clip = ClipData.newPlainText(null, data);
      clipManager.setPrimaryClip(clip);
    }
  }
}

The iOS implementation follows the same pattern using Objective‑C/Swift bridges.

References

ArkUI‑X repository: https://gitee.com/arkui-x

arkui_ace_engine repository: https://gitee.com/openharmony/arkui_ace_engine

Deep dive into arkui_ace_engine (Juejin): https://juejin.cn/post/7305235970286485515

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

mobile developmentCross-platformui-renderingarkTSArkUI-XClipboard Integration
Sohu Tech Products
Written by

Sohu Tech Products

A knowledge-sharing platform for Sohu's technology products. As a leading Chinese internet brand with media, video, search, and gaming services and over 700 million users, Sohu continuously drives tech innovation and practice. We’ll share practical insights and tech news here.

0 followers
Reader feedback

How this landed with the community

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.