Updating multiplatform projects with Android apps to use AGP 9
When used along with Android Gradle plugin 9.0 or newer, the Kotlin Multiplatform Gradle plugin stops being compatible with the com.android.application and the com.android.library plugins.
To update your project:
If your Android entry point is currently implemented in a shared code module, extract it into a separate module to avoid Gradle plugin conflicts.
Migrate your shared code module to use the new Android-KMP library plugin built specifically for multiplatform projects.
Migrate to the Android-KMP library plugin
Previously, to configure an Android target in a multiplatform module you needed to use the KMP plugin (org.jetbrains.kotlin.multiplatform) together with either the Android application (com.android.application) or the Android library (com.android.library) plugin.
With AGP 9.0, these plugins are no longer compatible with KMP, so you need to migrate to the new Android-KMP library plugin built specifically for KMP.
For library migration steps, see the guide in Android documentation.
To migrate an Android app project, you need to have the Android entry point and the shared code in properly configured separate modules. Below is a general tutorial for migrating a sample app, where you can see:
Migration of a sample app
The example project that you will prepare for the migration is a Compose Multiplatform app that is the result of the Create your own application tutorial. The sample with the example of an app that needs to be updated is in the main branch of the sample repository.
The sample consists of a single Gradle module (composeApp) that contains all the shared code and KMP entry points, and the iosApp project with the iOS-specific code and configuration.
To prepare for the AGP 9.0 migration, you will:
Extract the Android app entry point into a separate
androidAppmodule.Reconfigure the module with shared code (
composeApp) to use the Android-KMP library plugin
Module for the Android app entry point
Create and configure the Android app module
To create an Android app module (androidApp):
Create the
androidAppdirectory at the root of the project.Inside that directory, create an empty
build.gradle.ktsfile and thesrcdirectory.Add the new module to project settings in the
settings.gradle.ktsfile by adding this line at the end of the file:include(":androidApp")Select Build | Sync Project with Gradle Files in the main menu, or click the Gradle refresh button in the editor.
Configure the build script for the Android app
Configure the Gradle build script for the new module:
In the
gradle/libs.versions.tomlfile, add the Kotlin Android Gradle plugin to your version catalog:[plugins] kotlinAndroid = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }In the
androidApp/build.gradle.ktsfile, specify the plugins necessary for the Android app module:plugins { alias(libs.plugins.kotlinAndroid) alias(libs.plugins.androidApplication) alias(libs.plugins.composeMultiplatform) alias(libs.plugins.composeCompiler) }Make sure all of these plugins are mentioned in the root
build.gradle.ktsfile:plugins { alias(libs.plugins.kotlinAndroid) apply false alias(libs.plugins.androidApplication) apply false alias(libs.plugins.composeMultiplatform) apply false alias(libs.plugins.composeCompiler) apply false // ... }To add the necessary dependencies, copy existing dependencies from the
androidMain.dependencies {}block of thecomposeAppbuild script, and add the dependency on thecomposeAppitself. In this example, the result should look like this:kotlin { dependencies { implementation(projects.composeApp) implementation(libs.androidx.activity.compose) implementation(compose.components.uiToolingPreview) } }Copy the entire
android {}block with Android-specific configuration from thecomposeApp/build.gradle.ktsfile to theandroidApp/build.gradle.ktsfile.Copy the compiler options from the
androidTarget {}block of thecomposeApp/build.gradle.ktsfile to thetarget {}block of theandroidApp/build.gradle.ktsfile:target { compilerOptions { jvmTarget.set(JvmTarget.JVM_11) } }
Change the configuration of the
composeAppmodule from an Android application to an Android library, since that's what it effectively becomes. IncomposeApp/build.gradle.kts:Change the reference to the Gradle plugin:
alias(libs.plugins.androidApplication)alias(libs.plugins.androidLibrary)Remove the application property lines from the
android.defaultConfig {}block:defaultConfig { applicationId = "com.jetbrains.demo" minSdk = libs.versions.android.minSdk.get().toInt() targetSdk = libs.versions.android.targetSdk.get().toInt() versionCode = 1 versionName = "1.0" }defaultConfig { minSdk = libs.versions.android.minSdk.get().toInt() }
Select Build | Sync Project with Gradle Files in the main menu, or click the Gradle refresh button in the editor.
Move the code and run the Android app
Move the
composeApp/src/androidMaindirectory into theandroidApp/src/directory.Rename the
androidApp/src/androidMaindirectory tomain.If everything is configured correctly, the imports in the
androidApp/src/main/.../MainActivity.ktfile work and the code compiles.When you're using IntelliJ IDEA or Android Studio, the IDE recognizes the new module and automatically creates a new run configuration, androidApp. If that doesn't happen, modify the composeApp Android run configuration manually:
In the run configuration dropdown, select Edit Configurations.
Find the composeApp configuration in the Android category.
In the General | Module field, change
demo.composeApptodemo.androidApp.
Start the new run configuration to make sure that the app runs as expected.
If everything works correctly, in the
composeApp/build.gradle.ktsfile, remove thekotlin.sourceSets.androidMain.dependencies {}block.
You have extracted the Android entry point to a separate module. Now update the common code module to use the new Android-KMP library plugin.
Configure the shared module to use the Android-KMP library plugin
To simply extract the Android entry point, you applied the com.android.library plugin for the shared composeApp module. Now migrate to the new multiplatform library plugin:
In
gradle/libs.versions.toml, add the Android-KMP library plugin to your version catalog:[plugins] androidMultiplatformLibrary = { id = "com.android.kotlin.multiplatform.library", version.ref = "agp" }In the
composeApp/build.gradle.ktsfile, swap the old Android library plugin for the new one:alias(libs.plugins.androidLibrary)alias(libs.plugins.androidMultiplatformLibrary)In the root
build.gradle.ktsfile, add the following line to avoid conflicts in applying the plugin:alias(libs.plugins.androidMultiplatformLibrary) apply falseIn the
composeApp/build.gradle.ktsfile, instead of thekotlin.androidTarget {}block add akotlin.androidLibrary {}block:androidLibrary { namespace = "compose.project.demo.composedemo" compileSdk = libs.versions.android.compileSdk.get().toInt() compilerOptions { jvmTarget.set(JvmTarget.JVM_11) } androidResources { enable = true } }Remove both the
android {}and thedependencies {}block from thecomposeApp/build.gradle.ktsfile.The
android {}block is replaced with thekotlin.androidLibrary {}configuration.The only root dependency (
debugImplementation(compose.uiTooling)) conflicts with the new plugin that doesn't support build variants.
Select Build | Sync Project with Gradle Files in the main menu, or click the Gradle refresh button in the editor.
Check that the Android app is running as expected.
Update the Android Gradle plugin version
When all of your code works with the new configuration:
If you followed the instructions, you have working run configurations for the new app modules. You can delete obsolete run configurations associated with the
composeAppmodule.In the
gradle/libs.versions.tomlfile, update the AGP to a 9.* version, for example:[versions] agp = "9.0.0"Update the Gradle version in the
gradle/wrapper/gradle-wrapper.propertiesfile to at least 9.1.0:distributionUrl=https\://services.gradle.org/distributions/gradle-9.1.0-bin.zipRemove this line from the
androidApp/build.gradle.ktsfile, since Kotlin support is built-in with AGP 9.0 and applying the Kotlin Android plugin is no longer necessary:alias(libs.plugins.kotlinAndroid)In the
composeApp/build.gradle.ktsfile update the namespace in thekotlin.androidLibrary {}block so that it doesn't conflict with the app's namespace. For example:kotlin { androidLibrary { namespace = "compose.project.demo.composedemolibrary" // ...Select Build | Sync Project with Gradle Files in the main menu, or click the Gradle refresh button in the build script editor.
Check that your app builds and runs with the new AGP version.
Congratulations! You have upgraded your project to be compatible with AGP 9.0.