Kotlin Multiplatform on AGP 9: 7 Migration Traps
Résumé
Pixel shares a practical guide to moving a Compose game from Android to Kotlin Multiplatform with AGP 9. It covers seven migration traps, including module separation, enabling host tests, configuring Compose Resources, and handling escaped apostrophes—checks that can help developers avoid silent test gaps and broken UI.
DEV Community
Moving an Android App to Kotlin Multiplatform With AGP 9: Seven Traps
I moved a small Compose game to Kotlin Multiplatform so it could also run on iPhone. The Kotlin part was easy, the build setup was not. These are the seven traps I hit with Android Gradle Plugin 9 and Compose Multiplatform, in the order I hit them, and the checks that told me nothing else had changed. 1. The application plugin and the multiplatform plugin no longer share a module With Android Gradle Plugin 9 the Kotlin Multiplatform plugin cannot be applied to a module that also uses the Android application plugin. The shared code needs its own library module that uses the new Android library plugin for multiplatform. The app module stays a normal Android application and depends on it. The Kotlin migration guide also asks for a recent Gradle, 9.1 or newer. 2. Unit tests that quietly stop running I moved the game rules and their ten unit tests into the shared module, ran the build and got a green result. Then I looked at the log: the Android test task of the shared module said there was nothing to run. With the new plugin the Android host test is off until you switch it on. Declaring a host test in the Android part of the module fixed it, and the results file then showed ten tests run and none failed. The lesson is to count tests after a migration, not just to look for green. 3. Compose Resources need Android resources enabled Texts and fonts moved into the shared module as Compose Resources. My screenshot tests then failed with a missing resource error that pointed at a compiled strings file. Adding a preview configuration call in the tests did not help. What fixed it was enabling Android resources in the shared module's Android block, together with including Android resources for the host test. 4. A backslash that survived the move Android string files escape an apostrophe with a backslash. Compose Resources do not unescape it, so the Turkish statistics dialog showed 2048\'e instead of 2048'e. The fix is to use a plain apostrophe in the copied strings. I found this only because of the next check below. Nothing crashed and nothing failed, the text was just slightly wrong. 5. Test names Kotlin/Native will not accept One test had a comma in its backtick name, a harmless thing on Android. When the iOS test target compiled, it stopped with a message that the name contains illegal characters. Rewriting the name without the comma fixed it. 6. A simulator target that is gone I had listed the iOS simulator targets for both Apple silicon and Intel Macs. The build then reported a dependency resolution failure: the Compose Multiplatform libraries were not published for the Intel simulator target. I removed that target, so the build covers the arm64 simulator and real devices. 7. One DataStore per file The old Android code used a delegate that created one DataStore per process. In shared code I create the store myself and pass it in, and two stores open on the same file crash the app. So I keep a single instance behind a small holder object on Android, pointing at the same file the old delegate used, so existing saved games stay readable. How I checked that nothing else changed The screenshot tests that generate the store images became my regression suite. After the migration I regenerated all sixteen store images and looked at what git reported as modified. Fifteen were identical to the committed files, and the one that differed was the apostrophe bug above. For saved data I installed the build from the old code, played a few moves, then installed the new build over it without uninstalling. After a full app restart the board, score and best score were the same. Because the data file path and keys are unchanged, that check is cheap and worth doing before any release. FAQ Can I use the Android application plugin and Kotlin Multiplatform in one module with AGP 9? No. Put the shared code in a library module that uses the Android library plugin for multiplatform, and keep the application module separate. Why did my shared unit tests not r...

Powered by Readybot.io