Mobile Development 12 min read

How Alipay’s MyTab Mastered Three‑Platform One‑Code Refactor Using KMP

This article details Alipay’s technical journey of refactoring the MyTab feature across Android, iOS, and HarmonyOS using Kotlin Multiplatform, covering architectural shifts, performance bottlenecks, stability fixes, and the resulting gains in code reuse and development efficiency.

Alipay Experience Technology
Alipay Experience Technology
Alipay Experience Technology
How Alipay’s MyTab Mastered Three‑Platform One‑Code Refactor Using KMP

Background and Motivation

HarmonyOS introduced a three‑platform mobile ecosystem (Android, iOS, HarmonyOS). To simplify cross‑platform maintenance, Alipay’s terminal technology team selected Kotlin Multiplatform (KMP) as a single‑code solution for the MyTab feature and began a pilot migration.

Project Refactor Overview

The team adopted Jetpack Compose as the UI framework. Compose’s state‑driven, strong MVVM paradigm aligns with developers familiar with Vue, Flutter, or SwiftUI, but required a shift from the legacy MVC codebase.

Business Logic Analysis

MyTab’s functionality consists of two tightly coupled concerns: product shape (business rules) and visual presentation. Over many releases, the code accumulated version‑specific skin logic, large‑font adaptations, and interference between old and new UI paths.

Skin logic added special cases for particular versions.

Merchant version introduced large‑font adaptations.

Legacy and new UI logic overlapped, causing mutual interference.

Design‑Pattern Refactor

The original MVC layers had blurred boundaries, reducing maintainability. Switching to Compose’s state‑driven MVVM provided two key benefits:

Strict data‑UI separation: UI components render only from immutable State objects, preventing accidental use of model state.

State‑driven UI: The UI is a deterministic visual mapping of the current state, guaranteeing consistent rendering regardless of navigation path.

Compose Business‑Model Abstraction

A dedicated ViewModel layer was introduced to host shared view logic. Version‑specific adaptations were moved to the Model layer (business logic) and the View layer (UI specifics). This decoupling shifted most core logic into ViewModel, dramatically improving maintainability.

Challenges and Solutions

1. Frame‑Rate Drop

iPhone devices support a 120 Hz ProMotion refresh rate, while the KMP build initially rendered at 60 Hz, causing noticeable lag. Enabling the high‑refresh mode restored smooth scrolling.

Performance degradation was also caused by excessive recomposition of large @Composable functions. Two mitigation strategies were applied:

Split monolithic @Composable functions into smaller units, especially extracting code that does not depend on ScrollableState.

Prevent hidden over‑recomposition by ensuring only the composables that observe mutable State are recomposed.

Example illustrating a subtle over‑recomposition problem:

class MyModel() {
    var field1: Int = 0;
}

@Composable
fun Greeting(name: String, modifier: Modifier = Modifier) {
    Text(text = "Hello $name!", modifier = modifier)
    val model = remember { MyModel() }
    val count = remember { mutableStateOf(0) }
    Column(modifier = Modifier.padding(top = 100.dp)) {
        Button(onClick = { count.value++ }) { Text("Button") }
        SubItem(lambdaParam = { print("$model") })
        SubItem1(count.value)
    }
}

Observations: SubItem1 recomposes normally because it reads the changing count state. SubItem also recomposes even though it does not read count; its lambda captures an unstable variable, causing hidden recomposition.

2. Stability Issues

Snapshot Exception : Occurred when background threads modified State during a recomposition cycle. The fix was to confine all State updates to the main thread and audit asynchronous writes.

Platform‑API ANR on HarmonyOS : A deadlock arose from Kotlin‑Native’s global lock on Companion object initialization combined with JS‑runtime calls via runBlocking. The lock chain caused circular waiting, freezing the main thread.

Resolution steps:

Avoid invoking platform APIs during Companion object initialization.

Wrap all platform calls in suspend functions and never use runBlocking on background threads.

Refactor Benefits

After addressing the above challenges, the three‑platform KMP version of MyTab was fully released, deprecating the legacy codebase. A single shared codebase now powers Android, iOS, and HarmonyOS, delivering higher development efficiency, consistent business logic, and improved code quality.

Future Outlook

Remaining issues such as occasional rendering failures on specific ROMs and rare Metal pipeline blocks indicate further polishing is required before the framework can be considered a “super‑app” development platform. The team plans to expand KMP adoption and share the learned practices with the broader community.

References

Android official documentation on Compose stability: https://developer.android.com/develop/ui/compose/performance/stability

mobile developmentCross‑platformState ManagementKMPCompose UI
Alipay Experience Technology
Written by

Alipay Experience Technology

Exploring ultimate user experience and best engineering practices

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.