# Migrating Android Apps to Kotlin Multiplatform: UI and Tooling Challenges

Lessons on sharing UI layers while maintaining robust screenshot testing and resource management.

- **Source:** [ProAndroidDev - Medium](https://brifing.si/source/d9553fa9-7b72-4b9b-bc73-c6bf9a40dd5f)
- **Published:** 2026-11-09
- **Topic:** [technology](https://brifing.si/c/technology)
- **Original article:** <https://proandroiddev.com/migrating-a-real-android-app-to-kotlin-multiplatform-3-4-sharing-the-ui-without-losing-safety-net-f74a6bf408ae?source=rss----c72404660798---4>
- **On Brifing:** https://brifing.si/s/ba249842-aa12-4a75-b29d-89e635ed4372

## UI Migration Reality Check

Migrating the UI layer to Kotlin Multiplatform proved surprisingly straightforward compared to the surrounding ecosystem. While composables moved easily into commonMain, the build plugins, resource systems, and screenshot testing tools were tightly coupled to Android library assumptions. The application code was ready for sharing, but the supporting tooling required significant adaptation.

## Decoupling UI Logic First

The author utilized a unidirectional-data-flow library to abstract ViewModels, ensuring UI logic remained in testable Kotlin classes. By removing dependencies on androidx.lifecycle before the migration, the team avoided complex platform-specific unpicking. This architectural decision allowed the presentation layer to remain platform-agnostic, making the transition to multiplatform significantly smoother and more efficient.

## The Myth of Platform Code

Initial estimates suggested 12% of the codebase was Android-specific, but this was misleading. Analysis revealed that 70% of that code consisted of @Preview functions for Android Studio. Once these tooling artifacts were excluded, genuine platform-specific code accounted for less than 4% of the total, reframing the migration as a tooling challenge.

## Managing Platform Seams

After removing previews, only a few platform-specific seams remained, such as BackHandler and PlatformWebView. These were managed using expect/actual patterns within core modules. External interactions, like browser navigation or notification settings, were routed through a single ExternalNavigator interface, ensuring that individual feature modules remained entirely free of platform-specific implementation details.

## Centralized Resource Management

All resources were centralized into a single core:res module using commonMain. While this eliminated duplicate keys and simplified management, it introduced a dependency bottleneck. Because the Compose Multiplatform resources plugin lacked a stable API for library modules, the author implemented a reflective workaround to ensure generated assets were accessible to downstream modules.

## Maintaining Visual Regression Safety

To maintain a safety net, the project uses Roborazzi running under Robolectric within the androidHostTest source set. A custom convention plugin automates the process across 40 modules. This setup ensures that UI components are tested in both light and dark modes, providing consistent visual verification without relying on platform-specific emulator dependencies.

## Resource Syncing Workarounds

Because Robolectric reads resources from test assets, the team had to chain two workarounds to bridge the gap. The first created a stable output location for resources, while the second used a Sync task to copy these assets into the host test environment. This complex orchestration was necessary to ensure screenshot tests functioned.

## Trade-offs and Limitations

This migration strategy currently only validates UI stability on Android via Skia-based rendering. It does not guarantee identical behavior on iOS or web targets. Furthermore, storing 55 MB of PNGs in the repository is a significant cost, mitigated only by recording at half scale to keep the visual regression suite manageable.

## Strategic Migration Lessons

Developers should audit their tooling before changing module types, as swapping library definitions has long-term consequences for tests and previews. Keeping platform code out of the presentation layer is a best practice regardless of multiplatform goals. Proper planning for the ecosystem surrounding the code is ultimately cheaper than discovering integration failures later.

## Sources covering this story

- https://proandroiddev.com/migrating-a-real-android-app-to-kotlin-multiplatform-3-4-sharing-the-ui-without-losing-safety-net-f74a6bf408ae?source=rss----c72404660798---4 — 

---

_Summary written by Brifing from the original reporting. Copyright in the original article belongs to its publisher; read the full piece at the link above._
