|
1 | | -[//]: # (title: Migrating a Kotlin Multiplatform project to support AGP 9.0) |
| 1 | +[//]: # (title: Updating a Kotlin Multiplatform project to support AGP 9) |
| 2 | +<show-structure for="chapter,procedure" depth="3"/> |
2 | 3 |
|
3 | | -Projects where multiplatform modules configured Android targets using the `com.android.application` plugin |
4 | | -need to be restructured to upgrade to Android Gradle plugin 9.0. |
5 | | -AGP 9 deprecates several APIs which are used by Kotlin Multiplatform, |
6 | | -but provides a new [Android Gradle Library plugin](https://developer.android.com/kotlin/multiplatform/plugin) |
7 | | -to be used instead. |
| 4 | +Kotlin Multiplatform projects targeting Android need to migrate to using the new |
| 5 | +[Android Gradle Library plugin](https://developer.android.com/kotlin/multiplatform/plugin) |
| 6 | +to be able to use Android Gradle plugin version 9.0 and newer. |
8 | 7 |
|
9 | | -The following guide shows how to swap the plugins and restructure the project at the same time. |
| 8 | +> AGP 9 is supported in IntelliJ IDEA starting with version 2025.3 TODO |
| 9 | +> and Android Studio starting with Otter 2025.3 TODO |
| 10 | +> |
| 11 | +{style="note"} |
| 12 | + |
| 13 | +## Mandatory changes |
| 14 | + |
| 15 | +### Migrate to built-in Kotlin |
| 16 | + |
| 17 | +AGP 9.0 brings built-in Kotlin support that is enabled by default, |
| 18 | +so you don't need to enable the Kotlin Android Gradle plugin (`org.jetbrains.kotlin.android`) explicitly anymore. |
| 19 | + |
| 20 | +If you're using [kapt](https://kotlinlang.org/docs/kapt.html) or custom `kotlinOptions`, |
| 21 | +you may need to perform additional migration steps. |
| 22 | + |
| 23 | +Follow the [migration guide](https://developer.android.com/build/migrate-to-built-in-kotlin) |
| 24 | +to make sure you don't miss anything. |
| 25 | + |
| 26 | +### Migrate to the Android Gradle Library plugin |
| 27 | + |
| 28 | +Previously, to configure an Android target in a multiplatform module you needed to use |
| 29 | +the KMP plugin (`org.jetbrains.kotlin.multiplatform`) |
| 30 | +together with either |
| 31 | +the Android application (`com.android.application`) or the Android library (`com.android.library`) plugin. |
| 32 | + |
| 33 | +With AGP 9.0, these plugins stop being compatible with KMP, |
| 34 | +and you need to migrate to the new Android Gradle Library plugin built specifically for KMP. |
10 | 35 |
|
11 | 36 | > To make your project work with AGP 9.0 in the short term, you can manually enable the deprecated APIs. |
12 | 37 | > To do that, in the `gradle.properties` file of your project add this property: |
13 | 38 | > `android.enableLegacyVariantApi=true`. |
14 | 39 | > |
15 | | -> The legacy APIs are going to be removed completely in AGP 10, make sure you finish the migration before that! |
| 40 | +> The legacy APIs are going to be removed completely in AGP 10. Make sure you finish the migration before that! |
16 | 41 | > |
17 | 42 | {style="note"} |
18 | 43 |
|
19 | | -## Migration guide |
| 44 | +For library migration steps, see the [guide in Android documentation](https://developer.android.com/kotlin/multiplatform/plugin#migrate). |
| 45 | + |
| 46 | +To migrate an app project, you need to have the Android entry point and the shared code in properly configured separate modules. |
| 47 | +There is a [general tutorial for migrating a sample app](#step-by-step-migration-of-a-sample-app), |
| 48 | +but the mandatory parts are: |
| 49 | +* [Create and configure a shared module]() |
| 50 | +* [Create and configure an Android app module]() |
| 51 | + |
| 52 | +## Recommended changes |
| 53 | + |
| 54 | +Along with updating your Gradle configuration, we recommend to review the structure of your KMP project. |
| 55 | +The general approach is to extract shared code in its own module, and create a separate module for each platform-specific |
| 56 | +entry point. |
20 | 57 |
|
21 | | -In this guide, we show how to restructure a combined multiplatform module into discrete modules clearly delineating |
22 | | -shared logic, shared UI, and individual entry points. |
| 58 | +In terms of [Android modularization approach](https://developer.android.com/topic/modularization), |
| 59 | +we recommend creating separate **app modules** for platform-specific entry points |
| 60 | +(so, a separate module for Android, web, and JVM) |
| 61 | +and **feature modules** for shared code. |
23 | 62 |
|
24 | | -The example project is a Compose Multiplatform app that is the result of the [](compose-multiplatform-new-project.md) |
| 63 | +<!-- TODO link to the blog post explaining the changes --> |
| 64 | + |
| 65 | +## Step by step migration of a sample app |
| 66 | + |
| 67 | +The example project that you will prepare for the migration is a Compose Multiplatform app that is the result of the |
| 68 | +[](compose-multiplatform-new-project.md) |
25 | 69 | tutorial. |
26 | | -You can check out the initial state of the project in |
27 | | -the [update_october_2025 branch](https://github.com/kotlin-hands-on/get-started-with-cm/tree/update_october_2025) |
28 | | -of the sample project. |
29 | | - |
30 | | -<!-- TODO this branch doesn't work, need something else here — I just followed the tutorial with the current plugin version |
31 | | - and migrated the result |
32 | | - in the meantime, the best approach is to follow the tutorial :)--> |
33 | | - |
34 | | -The example consists of a single Gradle module (`composeApp`) that contains all the shared code and all of the KMP entry |
35 | | -points. |
36 | | -You will extract shared code and entry points into separate modules to reach two goals: |
37 | | - |
38 | | -* Create a more flexible and scalable project structure that allows managing shared logic, shared UI, and different |
39 | | - entry points |
40 | | - separately. |
41 | | -* Isolate the Android module (that uses the `androidApplication` Gradle plugin) from KMP modules (that use the |
42 | | - `androidLibrary` |
43 | | - Gradle plugin). |
44 | | - |
45 | | -For general modularization advice, |
46 | | -see [Android modularization intro](https://developer.android.com/topic/modularization). |
47 | | -In these terms, you are going to create several **app modules**, for each platform, and shared **feature modules**, for |
48 | | -UI and business logic. |
49 | | - |
50 | | -> If your project is simple enough, it might suffice to combine all shared code (shared logic and UI) in a single |
51 | | -module. |
52 | | -> We'll separate them to illustrate the modularisation pattern. |
53 | | -> |
54 | | -{style="note"} |
| 70 | +The example consists of a single Gradle module (`composeApp`) that contains all the shared code and KMP entry |
| 71 | +points, |
| 72 | +and the `iosApp` project with the iOS-specific code and configuration. |
| 73 | + |
| 74 | +To prepare for the AGP 9 migration and to create a generally more flexible and scalable project structure, |
| 75 | +you will: |
| 76 | + |
| 77 | +* Create feature modules for shared UI and business logic code. |
| 78 | +* Create app modules with entry points for each platform. |
| 79 | + |
| 80 | +If you are looking to only implement changes mandatory for the AGP 9 migration, |
| 81 | +you required steps are: |
| 82 | + |
| 83 | +* [Create and configure a shared module](#create-shared-modules) |
| 84 | +* [Create and configure an Android app module](#android-app) |
| 85 | + |
| 86 | +<!-- When the new structure is implemented in the wizard, this is going to change: |
| 87 | + following the tutorial will bring you to the new structure already. |
| 88 | + So we need to save a sample of "how things used to be" and link to it when the wizard update hits.--> |
| 89 | + |
| 90 | +### Create shared modules |
| 91 | + |
| 92 | +The rule of thumb for shared modules is: |
| 93 | + |
| 94 | +* If you implement Compose Multiplatform UI for each of your apps, you only need a single `shared` module that |
| 95 | + includes all multiplatform dependencies. |
| 96 | +* If at least one of your apps has fully native UI and only should depend on common code for business logic, |
| 97 | + create a `sharedLogic` and a `sharedUI` module to separate them. |
| 98 | + |
| 99 | +The UI in the sample project is fully implemented using Compose Multiplatform, |
| 100 | +but to illustrate the more general case we'll show the more complicated structure with `sharedUI` and `sharedLogic` modules. |
| 101 | +If you only want a single shared module, skip the shared logic step, jump ahead to the [`sharedUI`](#create-a-shared-ui-module) |
| 102 | +section and use it as a blueprint. |
55 | 103 |
|
56 | | -### Create a shared logic module |
| 104 | +#### Create a shared logic module |
57 | 105 |
|
58 | 106 | Before actually creating a module, you need to decide on what is business logic, which code is both UI- and |
59 | 107 | platform-independent. |
@@ -194,9 +242,9 @@ To do that, recreate the source set structure with the folders that contain `Pla |
194 | 242 | The entry points |
195 | 243 | 10. Sync Gradle check that there are no expect-actual errors. --> |
196 | 244 |
|
197 | | -### Create a shared UI module |
| 245 | +#### Create a shared UI module |
198 | 246 |
|
199 | | -Isolate shared code implementing common UI elements in the `sharedUi` module: |
| 247 | +Extract shared code implementing common UI elements in the `sharedUi` module: |
200 | 248 |
|
201 | 249 | 1. Create the `sharedUi` directory at the root of the project. |
202 | 250 | 2. Inside that directory, create an empty `build.gradle.kts` file and the `src` directory. |
@@ -440,7 +488,7 @@ Create and configure a new entry point module for the Android app: |
440 | 488 | 9. Start the run configuration to make sure that the app runs as expected. |
441 | 489 | 10. If everything works correctly: |
442 | 490 | * Remove the `composeApp/src/androidMain` directory. |
443 | | - * In the `composeApp/build.gradle.kts` file, remove the desktop-related code: |
| 491 | + * In the `composeApp/build.gradle.kts` file, remove the Android-related code: |
444 | 492 | * the `android {}` block, |
445 | 493 | * the `androidMain.dependencies {}`, |
446 | 494 | * the `androidTarget {}` block inside the `kotlin {}` block. |
|
0 commit comments