The Cross-Platform Story Isn't New
Cross-platform development has been around as long as mobile apps have. In the PC era, you typed a URL and got a page. Then the iPhone arrived, and native apps became the way to deliver mobile experiences. Apple built the App Store, and that little icon on the home screen changed everything—developers suddenly had a direct channel to users.
Then Android came along. Now you had to support Web, Android, and iOS. That meant multiple codebases, multiple teams, and multiplied costs. Developers started dreaming of "write once, run anywhere" again.
Facebook tried first with React Native. It worked, but performance suffered as apps grew. Meanwhile, Google's Chrome engineers were wrestling with a different problem: Chrome on mobile was sluggish. The architecture built for beefy desktop CPUs didn't translate well to phones. Long lists scrolled okay, but blank screens kept popping up. That's a bug on mobile, not a quirk.
So they rebuilt the rendering pipeline from scratch. The goal shifted from concurrency to immediacy—get pixels on screen fast, don't make users wait. That's how Flutter was born. It was also a strategic move for Google, a way to court developers ahead of the AI and IoT wave. And it aimed to unify UI across platforms, which is why it caught fire in China.
From Unified UI to Shared Logic
Flutter's core trick is self-rendering. Write Dart once, run on Android, iOS, Web. Later, Impeller replaced Skia for better GPU performance. But Dart never gained widespread adoption in China, so teams like Tencent built MXFlutter to swap in TypeScript-like languages. Some even argued Flutter would be perfect if it just used JavaScript.
Flutter's approach has a ceiling. Self-rendering gives consistency, but it also isolates you from native performance. And calling native features requires Platform Channels—lots of boilerplate code that can get slow with heavy serialization.
KMP takes a different route. Instead of unifying UI, it shares business logic. The key is the Expect/Actual mechanism: declare an interface in common code, then provide platform-specific implementations. You can share as much or as little as you want, down to individual functions. And because KMP compiles to native binaries, it can call C interfaces directly. That can be several times faster, sometimes nearly two orders of magnitude.
Why Chinese Giants Are Betting on KMP
KMP wasn't huge overseas, but in China, it's getting serious attention. The reason? HarmonyOS. When you have to support Android, iOS, and HarmonyOS, you can't just hire three full teams for each. You need a way to share logic across all three.
Think of a big mobile app as three zones:
- Performance domain—critical paths like shopping checkout. Needs speed and stability. Traditionally native-only.
- Dynamic domain—content pages that change daily. Can use lighter frameworks like Lynx or Weex.
- Open domain—mini-programs that let third parties into your ecosystem.
For the performance domain, there was no good cross-platform option. C++ is memory-unsafe, Rust has a steep learning curve, JavaScript and Dart hit performance limits. Kotlin showed promise, but its iOS and HarmonyOS support was rough. HarmonyOS's own Cangjie language was fast but had no ecosystem.
One major app planned to raise its cross-platform share from 45% to 75% in two years. But without logic sharing, they had to run two tracks: improving JS framework performance while piloting KMP and Cangjie. Logic sharing has gone from a nice-to-have to a necessity.
There's also a power shift. With iOS, developers have to follow Apple's rules. HarmonyOS is the newcomer, so it has to be more open. To support KMP, HarmonyOS exposed C APIs. When React Native's bridge to ArkTS was too slow, HarmonyOS rushed out C APIs for better performance.
The Cost of Cross-Platform
Efficiency comes with trade-offs. Flutter typically boosts productivity 1.5x; with HarmonyOS, it's roughly two people doing the work of three. But you pay in three ways.
Performance and experience. Generic frameworks can't deeply optimize for each platform. Flutter apps face larger package sizes, higher memory usage, slower startup, and awkward native interactions. Every cross-language call adds overhead. Multi-language runtimes can cause tricky object lifecycle issues—React Native and Android native code can reference each other in cycles, preventing garbage collection. Teams need to understand both sides deeply.
Ecosystem fragmentation. Many Chinese companies fork open-source frameworks. When HarmonyOS fixes a Flutter bug, it can't easily push that fix to every vendor's private fork.
Technical complexity. Bugs can span business code, the framework, and the OS. Engineers must understand the whole chain. And there's the leaky abstraction problem: frameworks try to hide platform differences, but you still end up with platform-specific if/else in your business code. Cross-platform frameworks don't eliminate complexity; they just move it from the business layer to the framework layer.
How Flutter Got Optimized for HarmonyOS
HarmonyOS had to adapt Flutter's runtime, UI, cross-language calls, third-party libraries, and command-line tools. The libraries were the biggest lift—thousands of packages, with the top 30 rushed into shape by 2025.
Then came rendering. Impeller precompiles shaders, avoiding the 100-200ms runtime compilation that caused jank on first frames. It also uses Vulkan for better GPU parallelism. HarmonyOS was an early adopter, and tests showed higher frame rates, better GPU utilization, and lower CPU load.
Another clever fix: shared memory for external textures. When the camera or a video player produces frames, they need to cross between Flutter's rendering pipeline and the platform's. Copying buffers through GPU-CPU-GPU is expensive. HarmonyOS introduced shared memory so both pipelines use the same buffers, nearly eliminating the copy cost. That solved jank in WeChat video and VoIP calls.
But Flutter still has hard limits. A single 1080P Flutter page adds about 70MB of memory. Ten pages? That's potentially 700MB. And Dart's concurrency model restricts shared memory across threads. So Flutter can't always match native performance.
Flutter is pushing into AI with GenUI and natural language UI generation, but the core challenges remain.
KMP's Three Key Upgrades on HarmonyOS
HarmonyOS started working with partners on KMP in 2025. Early feedback was brutal: cross-language communication, memory, debugging, package size, compile time—all rough. The first public version shipped in June 2026, with more fixes planned by September.
From Self-Rendering to Semi-Self-Drawing
Flutter's self-rendering causes memory bloat and mixing issues. If you want to "cut a hole" in the Flutter view to show native content underneath, you run into transparency and layer alignment problems.
The new approach: "semi-self-drawing." Components and text still generate drawing commands, but they go through the native rendering pipeline instead of a separate GPU context. That saves memory (no need for multiple buffers per instance), speeds up startup, and makes native mixing natural. Compose, for example, might create five buffers per instance. Ten instances? 500MB of overhead. Reusing the native pipeline cuts that drastically.
It also enables deeper OS integration. If only a small node moves, you can just transform that node instead of redrawing the whole page.
CMC: Taming GC Pauses
In 2025, KMP on HarmonyOS and iOS still used a GC algorithm similar to early CMS. It caused long pauses and memory fragmentation. The GC couldn't always tell whether a value was a pointer or plain data, so objects couldn't be safely moved. Over time, the heap became a patchwork of holes. Eventually, the system had to stop everything and compact memory—a pause that could last hundreds of milliseconds.
HarmonyOS built CMC to fix this. First, it divides memory into regions, each managed by its own thread, boosting concurrency. Second, it uses Stack Maps to track object references precisely, allowing objects to move during normal GC cycles. That's like cleaning your room regularly instead of waiting until it's unusable and doing a massive cleanup.
Parallel Compilation: 2-4x Faster Builds
KMP compilation used to take all Kotlin files, compile them into one giant LLVM IR, optimize globally, and produce a single .so file. No parallelism. HarmonyOS split the giant IR into multiple modules and compiled them in parallel.
But that caused two problems. Package size grew because modules exported more symbols. And performance dropped because some global optimizations were disabled. The fix: record which symbols are actually needed before splitting, clean up unused ones after, and cache global variable info so each module can still optimize globally. Result: 2-4x faster builds.
AI Coding and the Future of Cross-Platform
HarmonyOS is also using AI to help migrate and generate code. A2K (Android to KMP) and D2C (Design to Compose) are two examples.
AI coding faces three big challenges in large projects: huge codebases, unpredictable code quality, and private enterprise knowledge. A2K reuses existing test cases to help the model understand behavior, and it extracts base modules from the source so generated code actually fits into the real environment. That got adoption rates to about 60%.
D2C initially tried to convert Figma designs directly to Compose, but the model messed up layer relationships and fixed offsets caused layout issues on other screen sizes. The fix? Insert React as an intermediate representation. React and Compose are structurally similar, and there are tons of Figma-to-React tools. Splitting the problem into two steps—Figma to React, then React to Compose—improved scores by about 10 points on a 100-point scale. Plus, you can debug the intermediate React in Chrome before generating Compose code.
AI doesn't mean fewer steps is better. A good intermediate representation turns one unstable problem into two verifiable ones.
Which Framework Should You Choose Now?
AI changes the calculus. React Native's biggest selling point was letting web developers build mobile apps. But AI can generate native code now, so that advantage fades. React Native still has dynamic capabilities, but H5 can cover many of those. And Meta itself is using it less. Be cautious with React Native for new projects.
Flutter still wins when you need consistent UI across platforms and don't require pixel-perfect native interactions or minimal package size.
KMP is the strategic pick for the Android-iOS-HarmonyOS trio. It reuses logic, leverages existing Kotlin code, and compiles to native binaries for near-native performance.
But AI doesn't kill cross-platform frameworks. If AI generates three separate codebases, you still have to debug three tech stacks. Cross-platform frameworks reduce that burden. They also centralize compatibility fixes—Android's fragmentation shouldn't be solved by every business team separately.
The real question has shifted from "how to write multi-platform code faster" to "how to make AI generate high-quality, testable, reusable multi-platform code." That requires frameworks with clear abstractions, solid test assets, stable toolchains, and a developer ecosystem that AI can understand.
The Hybrid Workflow: Shared Logic, Native UI, and AI
Looking ahead, the winning formula for large apps might be shared logic plus native UI. Flutter and Compose Multiplatform can't fully replicate iOS's native transitions or Android's ripple effects. Native UI still matters.
So the pattern for the next few years: native UI for platform-specific experience, KMP for shared business logic, and AI to amplify development and migration speed. Cross-platform frameworks won't disappear because AI can write code. They'll evolve to give both humans and AI a unified, reliable foundation to work on.
Comments (0)
Please sign in to post a comment.
Don't have an account? Create one
No comments yet. Be the first to comment!