kotlin-tooling-agp9-migration

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

KMP AGP 9.0 Migration

KMP 迁移至AGP 9.0

Android Gradle Plugin 9.0 makes the Android application and library plugins incompatible with the Kotlin Multiplatform plugin in the same module. This skill guides you through the migration.
Android Gradle Plugin 9.0 使得Android应用和库插件无法与同一模块中的Kotlin Multiplatform插件兼容。本指南将引导你完成迁移流程。

Step 0: Analyze the Project

步骤0:分析项目

Before making any changes, understand the project structure:
  1. Read
    settings.gradle.kts
    (or
    .gradle
    ) to find all modules
  2. For each module, read its
    build.gradle.kts
    to identify which plugins are applied
  3. Check if the project uses a Gradle version catalog (
    gradle/libs.versions.toml
    ). If it exists, read it for current AGP/Gradle/Kotlin versions. If not, find versions directly in
    build.gradle.kts
    files (typically in the root
    buildscript {}
    or
    plugins {}
    block). Adapt all examples in this guide accordingly — version catalog examples use
    alias(libs.plugins.xxx)
    while direct usage uses
    id("plugin.id") version "x.y.z"
  4. Read
    gradle/wrapper/gradle-wrapper.properties
    for the Gradle version
  5. Check
    gradle.properties
    for any existing workarounds (
    android.enableLegacyVariantApi
    )
  6. Check for
    org.jetbrains.kotlin.android
    plugin usage — AGP 9.0 has built-in Kotlin and this plugin must be removed
  7. Check for
    org.jetbrains.kotlin.kapt
    plugin usage — incompatible with built-in Kotlin, must migrate to KSP or
    com.android.legacy-kapt
  8. Check for third-party plugins that may be incompatible with AGP 9.0 (see "Plugin Compatibility" section below)
If Bash is available, run
scripts/analyze-project.sh
from this skill's directory to get a structured summary.
在进行任何修改前,请先了解项目结构:
  1. 阅读
    settings.gradle.kts
    (或
    .gradle
    )文件,找出所有模块
  2. 针对每个模块,阅读其
    build.gradle.kts
    文件,识别已应用的插件
  3. 检查项目是否使用Gradle版本目录(
    gradle/libs.versions.toml
    )。如果存在,查看其中当前的AGP/Gradle/Kotlin版本;如果不存在,直接在
    build.gradle.kts
    文件中查找版本信息(通常在根目录的
    buildscript {}
    plugins {}
    块中)。请根据实际情况调整本指南中的所有示例——版本目录示例使用
    alias(libs.plugins.xxx)
    ,而直接引用版本则使用
    id("plugin.id") version "x.y.z"
  4. 阅读
    gradle/wrapper/gradle-wrapper.properties
    文件获取Gradle版本
  5. 检查
    gradle.properties
    文件中是否存在任何现有变通方案(如
    android.enableLegacyVariantApi
  6. 检查是否使用
    org.jetbrains.kotlin.android
    插件——AGP 9.0已内置Kotlin支持,必须移除该插件
  7. 检查是否使用
    org.jetbrains.kotlin.kapt
    插件——与内置Kotlin不兼容,必须迁移至KSP或
    com.android.legacy-kapt
  8. 检查可能与AGP 9.0不兼容的第三方插件(详见下方“插件兼容性”章节)
如果系统支持Bash,可运行本技能目录下的
scripts/analyze-project.sh
脚本,获取结构化的项目摘要。

Classify Each Module

对每个模块进行分类

For each module, determine its type:
Current pluginsMigration path
kotlin.multiplatform
+
com.android.library
Path A — Library plugin swap
kotlin.multiplatform
+
com.android.application
Path B — Mandatory Android split
kotlin.multiplatform
with multiple platform entry points in one module
Path C — Full restructure (recommended)
com.android.application
or
com.android.library
(no KMP)
See "Pure Android Tips" below
针对每个模块,确定其类型:
当前插件迁移路径
kotlin.multiplatform
+
com.android.library
路径A — 库插件替换
kotlin.multiplatform
+
com.android.application
路径B — 强制拆分Android模块
kotlin.multiplatform
在单个模块中包含多个平台入口点
路径C — 完全重构(推荐)
com.android.application
com.android.library
(未使用KMP)
详见下方“纯Android项目提示”

Determine Scope

确定迁移范围

  • Path B is mandatory for any module combining KMP + Android application plugin
  • Path C is recommended when the project has a monolithic
    composeApp
    (or similar) module containing entry points for multiple platforms (Android, Desktop, Web). This aligns with the new JetBrains default project structure where each platform gets its own app module.
  • Ask the user whether they want Path B only (minimum required) or Path C (recommended full restructure)
  • 路径B为强制要求:任何同时使用KMP和Android应用插件的模块都需遵循此路径
  • 路径C为推荐方案:当项目包含一个单体
    composeApp
    (或类似)模块,且该模块包含多平台(Android、桌面端、Web)入口点时适用。此方案符合JetBrains新的默认项目结构,即每个平台拥有独立的应用模块
  • 询问用户需求:确认用户仅需执行路径B(最低要求)还是路径C(推荐的完全重构)

Path A: Library Module Migration

路径A:库模块迁移

Use this when a module applies
kotlin.multiplatform
+
com.android.library
.
See references/MIGRATION-LIBRARY.md for full before/after code.
Summary:
  1. Replace plugin:
    com.android.library
    com.android.kotlin.multiplatform.library
  2. Remove
    org.jetbrains.kotlin.android
    plugin if present (AGP 9.0 has built-in Kotlin support)
  3. Migrate DSL: Move config from top-level
    android {}
    block into
    kotlin { android {} }
    :
    kotlin
    kotlin {
        android {
            namespace = "com.example.lib"
            compileSdk = 35
            minSdk = 24
        }
    }
  4. Rename source directories (only if the module uses classic Android layout instead of KMP layout):
    • src/main
      src/androidMain
    • src/test
      src/androidHostTest
    • src/androidTest
      src/androidDeviceTest
    • If the module already uses
      src/androidMain/
      , no directory renames are needed
  5. Move dependencies from top-level
    dependencies {}
    into
    sourceSets
    :
    kotlin
    kotlin {
        sourceSets {
            androidMain.dependencies {
                implementation("androidx.appcompat:appcompat:1.7.0")
            }
        }
    }
  6. Enable resources explicitly if the module uses Android resources:
    kotlin
    kotlin {
        android {
            androidResources { enable = true }
        }
    }
  7. Enable Java compilation if module has
    .java
    source files:
    kotlin
    kotlin {
        android {
            withJava()
        }
    }
  8. Enable tests explicitly if the module has unit or instrumented tests:
    kotlin
    kotlin {
        android {
            withHostTest { isIncludeAndroidResources = true }
            withDeviceTest {
                instrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
            }
        }
    }
  9. Update Compose tooling dependency:
    kotlin
    // Old: debugImplementation(libs.androidx.compose.ui.tooling)
    // New:
    dependencies {
        androidRuntimeClasspath(libs.androidx.compose.ui.tooling)
    }
  10. Publish consumer ProGuard rules explicitly if applicable:
    kotlin
    kotlin {
        android {
            consumerProguardFiles.add(file("consumer-rules.pro"))
        }
    }
适用于已应用
kotlin.multiplatform
+
com.android.library
的模块。
完整的前后代码对比请参考references/MIGRATION-LIBRARY.md
摘要:
  1. 替换插件
    com.android.library
    com.android.kotlin.multiplatform.library
  2. 移除
    org.jetbrains.kotlin.android
    插件
    (如果存在)——AGP 9.0已内置Kotlin支持
  3. 迁移DSL:将顶级
    android {}
    块中的配置移至
    kotlin { android {} }
    内部:
    kotlin
    kotlin {
        android {
            namespace = "com.example.lib"
            compileSdk = 35
            minSdk = 24
        }
    }
  4. 重命名源码目录(仅当模块使用经典Android布局而非KMP布局时需要):
    • src/main
      src/androidMain
    • src/test
      src/androidHostTest
    • src/androidTest
      src/androidDeviceTest
    • 如果模块已使用
      src/androidMain/
      ,则无需重命名目录
  5. 移动依赖:将顶级
    dependencies {}
    中的依赖移至
    sourceSets
    kotlin
    kotlin {
        sourceSets {
            androidMain.dependencies {
                implementation("androidx.appcompat:appcompat:1.7.0")
            }
        }
    }
  6. 显式启用资源(如果模块使用Android资源):
    kotlin
    kotlin {
        android {
            androidResources { enable = true }
        }
    }
  7. 启用Java编译(如果模块包含
    .java
    源码文件):
    kotlin
    kotlin {
        android {
            withJava()
        }
    }
  8. 显式启用测试(如果模块包含单元测试或仪器化测试):
    kotlin
    kotlin {
        android {
            withHostTest { isIncludeAndroidResources = true }
            withDeviceTest {
                instrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
            }
        }
    }
  9. 更新Compose工具依赖
    kotlin
    // 旧写法: debugImplementation(libs.androidx.compose.ui.tooling)
    // 新写法:
    dependencies {
        androidRuntimeClasspath(libs.androidx.compose.ui.tooling)
    }
  10. 显式发布消费者ProGuard规则(如适用):
    kotlin
    kotlin {
        android {
            consumerProguardFiles.add(file("consumer-rules.pro"))
        }
    }

Path B: Android App + Shared Module Split

路径B:拆分Android应用与共享模块

Use this when a module applies
kotlin.multiplatform
+
com.android.application
. This is mandatory for AGP 9.0 compatibility.
See references/MIGRATION-APP-SPLIT.md for full guide.
Summary:
  1. Create
    androidApp
    module
    with its own
    build.gradle.kts
    :
    kotlin
    plugins {
        alias(libs.plugins.androidApplication)
        // Do NOT apply kotlin-android — AGP 9.0 includes Kotlin support
        alias(libs.plugins.composeMultiplatform)  // if using Compose
        alias(libs.plugins.composeCompiler)       // if using Compose
    }
    
    android {
        namespace = "com.example.app"
        compileSdk = 35
        defaultConfig {
            applicationId = "com.example.app"
            minSdk = 24
            targetSdk = 35
            versionCode = 1
            versionName = "1.0"
        }
        buildFeatures { compose = true }
    }
    
    dependencies {
        implementation(projects.shared)  // or whatever the shared module is named
        implementation(libs.androidx.activity.compose)
    }
  2. Move Android entry point code from
    src/androidMain/
    to
    androidApp/src/main/
    :
    • MainActivity.kt
      (and any other Activities/Fragments)
    • AndroidManifest.xml
      (app-level manifest with
      <application>
      and launcher
      <activity>
      ) — verify
      android:name
      on
      <activity>
      uses the fully qualified class name in its new location
    • Android Application class if present
    • App-level resources (launcher icons, theme, etc.)
  3. Add to
    settings.gradle.kts
    :
    include(":androidApp")
  4. Add to root
    build.gradle.kts
    : plugin declarations with
    apply false
  5. Convert original module from application to library using Path A steps
  6. Ensure different namespaces: app module and library module must have distinct namespaces
  7. Remove from shared module:
    applicationId
    ,
    targetSdk
    ,
    versionCode
    ,
    versionName
  8. Update IDE run configurations: change the module from the old module to
    androidApp
适用于已应用
kotlin.multiplatform
+
com.android.application
的模块。 此路径是AGP 9.0兼容性的强制要求
完整指南请参考references/MIGRATION-APP-SPLIT.md
摘要:
  1. 创建
    androidApp
    模块
    ,并编写独立的
    build.gradle.kts
    文件:
    kotlin
    plugins {
        alias(libs.plugins.androidApplication)
        // 请勿应用kotlin-android — AGP 9.0已包含Kotlin支持
        alias(libs.plugins.composeMultiplatform)  // 如果使用Compose
        alias(libs.plugins.composeCompiler)       // 如果使用Compose
    }
    
    android {
        namespace = "com.example.app"
        compileSdk = 35
        defaultConfig {
            applicationId = "com.example.app"
            minSdk = 24
            targetSdk = 35
            versionCode = 1
            versionName = "1.0"
        }
        buildFeatures { compose = true }
    }
    
    dependencies {
        implementation(projects.shared)  // 或共享模块的实际名称
        implementation(libs.androidx.activity.compose)
    }
  2. 将Android入口点代码
    src/androidMain/
    移至
    androidApp/src/main/
    • MainActivity.kt
      (及其他Activities/Fragments)
    • AndroidManifest.xml
      (包含
      <application>
      和启动器
      <activity>
      的应用级清单)——验证
      <activity>
      android:name
      是否指向其新位置的全限定类名
    • 若存在Android Application类,一并移动
    • 应用级资源(启动器图标、主题等)
  3. 添加至
    settings.gradle.kts
    include(":androidApp")
  4. 添加至根目录
    build.gradle.kts
    :使用
    apply false
    声明插件
  5. 将原始模块从应用转换为库:遵循路径A的步骤
  6. 确保命名空间不同:应用模块和库模块必须使用不同的命名空间
  7. 从共享模块中移除
    applicationId
    targetSdk
    versionCode
    versionName
  8. 更新IDE运行配置:将运行模块从旧模块更改为
    androidApp

Path C: Full Restructure (Recommended)

路径C:完全重构(推荐)

Use this when the project has a monolithic module (typically
composeApp
) containing entry points for multiple platforms. This is optional but aligns with the new JetBrains default.
See references/MIGRATION-FULL-RESTRUCTURE.md for full guide.
适用于项目包含单体模块(通常为
composeApp
)且该模块包含多平台入口点的场景。此方案为可选,但符合JetBrains的新默认结构。
完整指南请参考references/MIGRATION-FULL-RESTRUCTURE.md

Target Structure

目标结构

project/
├── shared/              ← KMP library (was composeApp), pure shared code
├── androidApp/          ← Android entry point only
├── desktopApp/          ← Desktop entry point only (if desktop target exists)
├── webApp/              ← Wasm/JS entry point only (if web target exists)
├── iosApp/              ← iOS Xcode project (usually already separate)
└── ...
project/
├── shared/              ← KMP库模块(原composeApp),仅包含纯共享代码
├── androidApp/          ← 仅包含Android入口点
├── desktopApp/          ← 仅包含桌面端入口点(如果存在桌面目标平台)
├── webApp/              ← 仅包含Wasm/JS入口点(如果存在Web目标平台)
├── iosApp/              ← iOS Xcode项目(通常已独立)
└── ...

Steps

步骤

  1. Apply Path B first — extract
    androidApp
    (mandatory for AGP 9.0)
  2. Extract
    desktopApp
    (if desktop target exists):
    • Create module with
      org.jetbrains.compose
      and
      application {}
      plugin
    • Move
      main()
      function from
      desktopMain
      to
      desktopApp/src/main/kotlin/
    • Move
      compose.desktop { application { ... } }
      config to
      desktopApp/build.gradle.kts
    • Add dependency on
      shared
      module
  3. Extract
    webApp
    (if wasmJs/js target exists):
    • Create module with appropriate Kotlin/JS or Kotlin/Wasm configuration
    • Move web entry point from
      wasmJsMain
      /
      jsMain
      to
      webApp/src/wasmJsMain/kotlin/
    • Move browser/distribution config to
      webApp/build.gradle.kts
    • Add dependency on
      shared
      module
  4. iOS — typically already in a separate
    iosApp
    directory. Verify:
    • Framework export config (
      binaries.framework
      ) stays in
      shared
      module
    • Xcode project references the correct framework path
  5. Rename module from
    composeApp
    to
    shared
    :
    • Rename directory
    • Update
      settings.gradle.kts
      include
    • Update all dependency references across modules
  6. Clean up shared module: remove all platform entry point code and app-specific config that was moved to the platform app modules
  1. 先执行路径B——提取
    androidApp
    模块(AGP 9.0兼容性强制要求)
  2. 提取
    desktopApp
    模块
    (如果存在桌面目标平台):
    • 创建应用
      org.jetbrains.compose
      application {}
      插件的模块
    • main()
      函数从
      desktopMain
      移至
      desktopApp/src/main/kotlin/
    • compose.desktop { application { ... } }
      配置移至
      desktopApp/build.gradle.kts
    • 添加对
      shared
      模块的依赖
  3. 提取
    webApp
    模块
    (如果存在wasmJs/js目标平台):
    • 创建配置了适当Kotlin/JS或Kotlin/Wasm的模块
    • 将Web入口点从
      wasmJsMain
      /
      jsMain
      移至
      webApp/src/wasmJsMain/kotlin/
    • 将浏览器/分发配置移至
      webApp/build.gradle.kts
    • 添加对
      shared
      模块的依赖
  4. iOS平台——通常已在独立的
    iosApp
    目录中。验证:
    • 框架导出配置(
      binaries.framework
      )保留在
      shared
      模块中
    • Xcode项目引用了正确的框架路径
  5. 重命名模块:将
    composeApp
    更改为
    shared
    • 重命名目录
    • 更新
      settings.gradle.kts
      中的include配置
    • 更新所有模块间的依赖引用
  6. 清理共享模块:移除所有已移至平台应用模块的平台入口点代码和应用特定配置

Variant: Native UI

变体:原生UI

If some platforms use native UI (e.g., SwiftUI for iOS), split
shared
into:
  • sharedLogic
    — business logic consumed by ALL platforms
  • sharedUI
    — Compose Multiplatform UI consumed only by platforms using shared UI
如果部分平台使用原生UI(如iOS的SwiftUI),可将
shared
拆分为:
  • sharedLogic
    — 所有平台共享的业务逻辑
  • sharedUI
    — 仅由使用共享UI的平台消费的Compose Multiplatform UI

Variant: Server

变体:服务端

If the project includes a server target:
  • Add
    server
    module at the root
  • Move all client modules under an
    app/
    directory
  • Add
    core
    module for code shared between server and client (models, validation)
如果项目包含服务端目标平台:
  • 在根目录添加
    server
    模块
  • 将所有客户端模块移至
    app/
    目录下
  • 添加
    core
    模块,用于服务端和客户端共享的代码(如模型、验证逻辑)

Version Updates

版本更新

These are required regardless of migration path:
  1. Gradle wrapper — update to 9.1.0+:
    properties
    # gradle/wrapper/gradle-wrapper.properties
    distributionUrl=https\://services.gradle.org/distributions/gradle-9.1.0-bin.zip
  2. AGP version — update to 9.0.0+.
    If using a version catalog (
    gradle/libs.versions.toml
    ):
    toml
    [versions]
    agp = "9.0.0"
    If versions are set directly in build files, update all
    com.android.*
    plugin version strings:
    kotlin
    // root build.gradle.kts
    plugins {
        id("com.android.application") version "9.0.0" apply false
    }
  3. Add the KMP library plugin.
    With version catalog:
    toml
    [plugins]
    android-kotlin-multiplatform-library = { id = "com.android.kotlin.multiplatform.library", version.ref = "agp" }
    Without version catalog — use the plugin ID directly in build files:
    kotlin
    // root build.gradle.kts
    plugins {
        id("com.android.kotlin.multiplatform.library") version "9.0.0" apply false
    }
    // module build.gradle.kts
    plugins {
        id("com.android.kotlin.multiplatform.library")
    }
  4. Root build.gradle.kts — add
    apply false
    for new plugin (see examples above)
  5. JDK — ensure JDK 17+ is used (required by AGP 9.0)
  6. SDK Build Tools — update to 36.0.0:
    Install via SDK Manager or configure in android { buildToolsVersion = "36.0.0" }
  7. Remove legacy workarounds from
    gradle.properties
    :
    • Remove
      android.enableLegacyVariantApi=true
      (removed in AGP 9.0, causes error if present)
    • Remove
      android.r8.integratedResourceShrinking
      (removed in AGP 9.0, causes error if present)
    • Remove
      android.enableNewResourceShrinker.preciseShrinking
      (removed in AGP 9.0, causes error if present)
    • Remove
      android.builtInKotlin=false
      (unless needed for plugin compatibility — see Plugin Compatibility)
    • Remove
      android.newDsl=false
      (unless needed for plugin compatibility)
  8. Review gradle.properties defaults — see "Gradle Properties Default Changes" section for properties whose defaults changed in AGP 9.0
无论选择哪种迁移路径,以下更新均为必需:
  1. Gradle包装器——升级至9.1.0+:
    properties
    # gradle/wrapper/gradle-wrapper.properties
    distributionUrl=https\://services.gradle.org/distributions/gradle-9.1.0-bin.zip
  2. AGP版本——升级至9.0.0+。
    如果使用版本目录(
    gradle/libs.versions.toml
    ):
    toml
    [versions]
    agp = "9.0.0"
    如果直接在构建文件中设置版本,更新所有
    com.android.*
    插件的版本字符串:
    kotlin
    // 根目录build.gradle.kts
    plugins {
        id("com.android.application") version "9.0.0" apply false
    }
  3. 添加KMP库插件
    使用版本目录:
    toml
    [plugins]
    android-kotlin-multiplatform-library = { id = "com.android.kotlin.multiplatform.library", version.ref = "agp" }
    不使用版本目录——直接在构建文件中使用插件ID:
    kotlin
    // 根目录build.gradle.kts
    plugins {
        id("com.android.kotlin.multiplatform.library") version "9.0.0" apply false
    }
    // 模块build.gradle.kts
    plugins {
        id("com.android.kotlin.multiplatform.library")
    }
  4. 根目录build.gradle.kts——为新插件添加
    apply false
    声明(见上方示例)
  5. JDK——确保使用JDK 17+(AGP 9.0要求)
  6. SDK构建工具——升级至36.0.0:
    通过SDK Manager安装,或在android { buildToolsVersion = "36.0.0" }中配置
  7. 移除gradle.properties中的旧版变通方案
    • 移除
      android.enableLegacyVariantApi=true
      (AGP 9.0已移除,若存在会导致错误)
    • 移除
      android.r8.integratedResourceShrinking
      (AGP 9.0已移除,若存在会导致错误)
    • 移除
      android.enableNewResourceShrinker.preciseShrinking
      (AGP 9.0已移除,若存在会导致错误)
    • 移除
      android.builtInKotlin=false
      (除非因插件兼容性需要——详见插件兼容性章节)
    • 移除
      android.newDsl=false
      (除非因插件兼容性需要)
  8. 检查gradle.properties默认值变更——查看“Gradle属性默认值变更”章节,了解AGP 9.0中默认值已变更的属性

Built-in Kotlin Migration

内置Kotlin迁移

AGP 9.0 enables built-in Kotlin support by default for all
com.android.application
and
com.android.library
modules. The
org.jetbrains.kotlin.android
plugin is no longer needed and will conflict if applied.
Important: Built-in Kotlin does NOT replace KMP support. KMP library modules still need
org.jetbrains.kotlin.multiplatform
+
com.android.kotlin.multiplatform.library
.
AGP 9.0默认对所有
com.android.application
com.android.library
模块启用内置Kotlin支持。
org.jetbrains.kotlin.android
插件不再需要,若应用会产生冲突。
重要提示:内置Kotlin并不替代KMP支持。KMP库模块仍需使用
org.jetbrains.kotlin.multiplatform
+
com.android.kotlin.multiplatform.library

Detection

检测

Check if the project uses
org.jetbrains.kotlin.android
or
kotlin-android
in any build files. If found, this migration is needed. If not, check
gradle.properties
for
android.builtInKotlin=false
which may indicate a previous opt-out.
检查项目是否在任何构建文件中使用
org.jetbrains.kotlin.android
kotlin-android
。如果存在,需要进行此迁移;如果不存在,检查
gradle.properties
中是否有
android.builtInKotlin=false
(这可能表示之前选择了退出内置支持)。

Step 1: Remove kotlin-android Plugin

步骤1:移除kotlin-android插件

Remove from all module-level and root-level build files:
kotlin
// Remove from module build.gradle.kts
plugins {
    // REMOVE: alias(libs.plugins.kotlin.android)
    // REMOVE: id("org.jetbrains.kotlin.android")
}

// Remove from root build.gradle.kts
plugins {
    // REMOVE: alias(libs.plugins.kotlin.android) apply false
}
Remove from version catalog (
gradle/libs.versions.toml
):
toml
[plugins]
所有模块级和根目录级构建文件中移除:
kotlin
// 从模块build.gradle.kts中移除
plugins {
    // 移除: alias(libs.plugins.kotlin.android)
    // 移除: id("org.jetbrains.kotlin.android")
}

// 从根目录build.gradle.kts中移除
plugins {
    // 移除: alias(libs.plugins.kotlin.android) apply false
}
从版本目录(
gradle/libs.versions.toml
)中移除:
toml
[plugins]

REMOVE: kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }

移除: kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }

undefined
undefined

Step 2: Migrate kapt to KSP or legacy-kapt

步骤2:将kapt迁移至KSP或legacy-kapt

The
org.jetbrains.kotlin.kapt
plugin is incompatible with built-in Kotlin.
Preferred: Migrate to KSP — see the KSP migration guide for each annotation processor.
Fallback: Use
com.android.legacy-kapt
(same version as AGP):
toml
undefined
org.jetbrains.kotlin.kapt
插件与内置Kotlin不兼容
首选方案:迁移至KSP——请参考每个注解处理器的KSP迁移指南。
备选方案:使用
com.android.legacy-kapt
(版本与AGP相同):
toml
undefined

gradle/libs.versions.toml

gradle/libs.versions.toml

[plugins] legacy-kapt = { id = "com.android.legacy-kapt", version.ref = "agp" }
```kotlin
// Module build.gradle.kts — replace kotlin-kapt with legacy-kapt
plugins {
    // REMOVE: alias(libs.plugins.kotlin.kapt)
    alias(libs.plugins.legacy.kapt)
}
[plugins] legacy-kapt = { id = "com.android.legacy-kapt", version.ref = "agp" }
```kotlin
// 模块build.gradle.kts — 用legacy-kapt替换kotlin-kapt
plugins {
    // 移除: alias(libs.plugins.kotlin.kapt)
    alias(libs.plugins.legacy.kapt)
}

Step 3: Migrate kotlinOptions to compilerOptions

步骤3:将kotlinOptions迁移至compilerOptions

For pure Android modules (non-KMP), migrate
android.kotlinOptions {}
to the top-level
kotlin.compilerOptions {}
:
kotlin
// Old
android {
    kotlinOptions {
        jvmTarget = "11"
        languageVersion = "2.0"
        freeCompilerArgs += listOf("-Xopt-in=kotlin.RequiresOptIn")
    }
}

// New
kotlin {
    compilerOptions {
        jvmTarget.set(org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_11)
        languageVersion.set(org.jetbrains.kotlin.gradle.dsl.KotlinVersion.KOTLIN_2_0)
        optIn.add("kotlin.RequiresOptIn")
    }
}
Note: With built-in Kotlin,
jvmTarget
defaults to
android.compileOptions.targetCompatibility
, so it may be optional if you already set
compileOptions
.
对于纯Android模块(非KMP),将
android.kotlinOptions {}
迁移至顶级
kotlin.compilerOptions {}
kotlin
// 旧写法
android {
    kotlinOptions {
        jvmTarget = "11"
        languageVersion = "2.0"
        freeCompilerArgs += listOf("-Xopt-in=kotlin.RequiresOptIn")
    }
}

// 新写法
kotlin {
    compilerOptions {
        jvmTarget.set(org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_11)
        languageVersion.set(org.jetbrains.kotlin.gradle.dsl.KotlinVersion.KOTLIN_2_0)
        optIn.add("kotlin.RequiresOptIn")
    }
}
注意:使用内置Kotlin时,
jvmTarget
默认值为
android.compileOptions.targetCompatibility
,因此如果已设置
compileOptions
,该配置可能为可选。

Step 4: Migrate kotlin.sourceSets to android.sourceSets

步骤4:将kotlin.sourceSets迁移至android.sourceSets

With built-in Kotlin, only
android.sourceSets {}
with the
kotlin
set is supported:
kotlin
// NOT SUPPORTED with built-in Kotlin:
kotlin.sourceSets.named("main") {
    kotlin.srcDir("additionalSourceDirectory/kotlin")
}

// Correct:
android.sourceSets.named("main") {
    kotlin.directories += "additionalSourceDirectory/kotlin"
}
For generated sources, use the Variant API:
kotlin
androidComponents.onVariants { variant ->
    variant.sources.kotlin!!.addStaticSourceDirectory("additionalSourceDirectory/kotlin")
}
使用内置Kotlin时,仅支持
android.sourceSets {}
搭配
kotlin
集合:
kotlin
// 内置Kotlin不支持此写法:
kotlin.sourceSets.named("main") {
    kotlin.srcDir("additionalSourceDirectory/kotlin")
}

// 正确写法:
android.sourceSets.named("main") {
    kotlin.directories += "additionalSourceDirectory/kotlin"
}
对于生成的源码,使用Variant API:
kotlin
androidComponents.onVariants { variant ->
    variant.sources.kotlin!!.addStaticSourceDirectory("additionalSourceDirectory/kotlin")
}

Per-Module Migration Strategy

分模块迁移策略

For large projects, migrate module-by-module:
  1. Disable globally:
    android.builtInKotlin=false
    in
    gradle.properties
  2. Enable per migrated module by applying the opt-in plugin:
    kotlin
    plugins {
        id("com.android.built-in-kotlin") version "AGP_VERSION"
    }
  3. Follow Steps 1-4 for that module
  4. Once all modules are migrated, remove
    android.builtInKotlin=false
    and all
    com.android.built-in-kotlin
    plugins
对于大型项目,可分模块进行迁移:
  1. 全局禁用:在
    gradle.properties
    中设置
    android.builtInKotlin=false
  2. 对已迁移的模块启用:应用opt-in插件:
    kotlin
    plugins {
        id("com.android.built-in-kotlin") version "AGP_VERSION"
    }
  3. 对该模块执行步骤1-4
  4. 所有模块迁移完成后,移除
    android.builtInKotlin=false
    以及所有
    com.android.built-in-kotlin
    插件

Optional: Disable Kotlin for Non-Kotlin Modules

可选:为非Kotlin模块禁用Kotlin

For modules that contain no Kotlin sources, disable built-in Kotlin to save build time:
kotlin
android {
    enableKotlin = false
}
对于不包含任何Kotlin源码的模块,可禁用内置Kotlin以节省构建时间:
kotlin
android {
    enableKotlin = false
}

Opt-Out (Temporary)

退出(临时)

If blocked by plugin incompatibilities, opt out temporarily:
properties
undefined
如果因插件兼容性问题受阻,可临时退出:
properties
undefined

gradle.properties

gradle.properties

android.builtInKotlin=false android.newDsl=false # also required if using new DSL opt-out

**Warning:** Ask the user if they want to opt out, and if so,
remind them this is a temporary measure.
android.builtInKotlin=false android.newDsl=false # 如果使用新DSL退出,也需要设置此属性

**警告**:请询问用户是否要退出,并提醒这只是临时措施。

Plugin Compatibility

插件兼容性

See references/PLUGIN-COMPATIBILITY.md for the full compatibility table with known compatible versions, opt-out flag workarounds, and broken plugins.
Before migrating, inventory all plugins in the project and check each against that table. If any plugin is broken without workaround, inform the user. If plugins need opt-out flags, add them to
gradle.properties
and note them as temporary workarounds.
完整的兼容性表格(包含已知兼容版本、退出标志变通方案和已损坏插件)请参考references/PLUGIN-COMPATIBILITY.md
迁移前,请清点项目中的所有插件,并逐一对照该表格。如果任何插件已损坏且无变通方案,请告知用户;如果插件需要退出标志,请将其添加至
gradle.properties
并注明为临时变通方案。

Gradle Properties Default Changes

Gradle属性默认值变更

AGP 9.0 changes the defaults for many gradle properties. Check
gradle.properties
for any explicitly set values that may now conflict. Key changes:
PropertyOld DefaultNew DefaultAction
android.uniquePackageNames
false
true
Ensure each library has a unique namespace
android.enableAppCompileTimeRClass
false
true
Refactor
switch
on R fields to
if/else
android.defaults.buildfeatures.resvalues
true
false
Enable
resValues = true
where needed
android.defaults.buildfeatures.shaders
true
false
Enable shaders where needed
android.r8.optimizedResourceShrinking
false
true
Review R8 keep rules
android.r8.strictFullModeForKeepRules
false
true
Update keep rules to be explicit
android.proguard.failOnMissingFiles
false
true
Remove invalid ProGuard file references
android.r8.proguardAndroidTxt.disallowed
false
true
Use
proguard-android-optimize.txt
only
android.r8.globalOptionsInConsumerRules.disallowed
false
true
Remove global options from library consumer rules
android.sourceset.disallowProvider
false
true
Use
Sources
API on androidComponents
android.sdk.defaultTargetSdkToCompileSdkIfUnset
false
true
Specify
targetSdk
explicitly
android.onlyEnableUnitTestForTheTestedBuildType
false
true
Only if testing non-default build types
Check for and remove properties that now cause errors:
  • android.r8.integratedResourceShrinking
    — removed, always on
  • android.enableNewResourceShrinker.preciseShrinking
    — removed, always on
AGP 9.0变更了许多Gradle属性的默认值。请检查
gradle.properties
中是否存在任何显式设置的值,这些值现在可能与默认值冲突。主要变更如下:
属性旧默认值新默认值操作
android.uniquePackageNames
false
true
确保每个库都有唯一的命名空间
android.enableAppCompileTimeRClass
false
true
将基于R字段的
switch
重构为
if/else
android.defaults.buildfeatures.resvalues
true
false
在需要的地方启用
resValues = true
android.defaults.buildfeatures.shaders
true
false
在需要的地方启用着色器
android.r8.optimizedResourceShrinking
false
true
检查R8保留规则
android.r8.strictFullModeForKeepRules
false
true
更新保留规则使其更明确
android.proguard.failOnMissingFiles
false
true
移除无效的ProGuard文件引用
android.r8.proguardAndroidTxt.disallowed
false
true
仅使用
proguard-android-optimize.txt
android.r8.globalOptionsInConsumerRules.disallowed
false
true
从库消费者规则中移除全局选项
android.sourceset.disallowProvider
false
true
在androidComponents上使用
Sources
API
android.sdk.defaultTargetSdkToCompileSdkIfUnset
false
true
显式指定
targetSdk
android.onlyEnableUnitTestForTheTestedBuildType
false
true
仅在测试非默认构建类型时需要调整
检查并移除现在会导致错误的属性:
  • android.r8.integratedResourceShrinking
    — 已移除,始终启用
  • android.enableNewResourceShrinker.preciseShrinking
    — 已移除,始终启用

Pure Android Tips

纯Android项目提示

For non-KMP Android modules upgrading to AGP 9.0:
  • Remove
    org.jetbrains.kotlin.android
    plugin — AGP 9.0 includes Kotlin support built-in (see "Built-in Kotlin Migration" above)
  • Migrate kapt to KSP or
    com.android.legacy-kapt
  • Migrate
    kotlinOptions
    to
    kotlin { compilerOptions {} }
  • Migrate
    kotlin.sourceSets
    to
    android.sourceSets
    with
    .kotlin
    accessor
  • Review new DSL interfaces
    BaseExtension
    is removed; use
    CommonExtension
    or specific extension types
  • Java default changed from Java 8 to Java 11 — ensure
    compileOptions
    reflects this
  • R class is now compile-time non-final in app modules — refactor any
    switch
    statements on R class fields to
    if/else
  • targetSdk defaults to compileSdk if not set — specify
    targetSdk
    explicitly to avoid surprises
  • NDK default changed to r28c — specify
    ndkVersion
    explicitly if using native code
  • Temporary opt-out:
    android.builtInKotlin=false
    +
    android.newDsl=false
    in
    gradle.properties
    (removed in AGP 10)
对于未使用KMP的Android项目升级至AGP 9.0:
  • 移除
    org.jetbrains.kotlin.android
    插件
    ——AGP 9.0已内置Kotlin支持(详见“内置Kotlin迁移”章节)
  • 将kapt迁移至KSP或
    com.android.legacy-kapt
  • kotlinOptions
    迁移至
    kotlin { compilerOptions {} }
  • kotlin.sourceSets
    迁移至带有
    .kotlin
    访问器的
    android.sourceSets
  • 查看新DSL接口——
    BaseExtension
    已移除;请使用
    CommonExtension
    或特定的扩展类型
  • Java默认版本从8变更为11——确保
    compileOptions
    反映此变更
  • R类在应用模块中现为编译时非final——将任何基于R类字段的
    switch
    语句重构为
    if/else
  • 如果未设置
    targetSdk
    ,默认值为compileSdk
    ——请显式指定
    targetSdk
    以避免意外
  • NDK默认版本变更为r28c——如果使用原生代码,请显式指定
    ndkVersion
  • 临时退出:在
    gradle.properties
    中设置
    android.builtInKotlin=false
    +
    android.newDsl=false
    (AGP 10中将移除该选项)

Verification

验证

After migration, verify with the checklist. Key checks:
  1. ./gradlew build
    succeeds with no errors
  2. ./gradlew :androidApp:assembleDebug
    succeeds (if app module exists)
  3. No
    com.android.library
    or
    com.android.application
    in KMP modules
  4. No
    org.jetbrains.kotlin.android
    in AGP 9.0 modules
  5. Source sets use correct names (
    androidMain
    ,
    androidHostTest
    ,
    androidDeviceTest
    )
  6. No deprecation warnings about variant API
  7. Run configurations point to correct modules
迁移完成后,请使用检查清单进行验证。关键检查点:
  1. ./gradlew build
    执行成功,无错误
  2. ./gradlew :androidApp:assembleDebug
    执行成功(如果存在应用模块)
  3. KMP模块中不存在
    com.android.library
    com.android.application
    插件
  4. AGP 9.0模块中不存在
    org.jetbrains.kotlin.android
    插件
  5. 源码集使用正确的名称(
    androidMain
    androidHostTest
    androidDeviceTest
  6. 无关于variant API的弃用警告
  7. 运行配置指向正确的模块

Common Issues

常见问题

See references/KNOWN-ISSUES.md for details. Key gotchas:
详细内容请参考references/KNOWN-ISSUES.md。主要注意事项:

KMP Library Plugin Issues

KMP库插件问题

  • BuildConfig unavailable in library modules — use DI/
    AppConfiguration
    interface, or use BuildKonfig or gradle-buildconfig-plugin for compile-time constants
  • No build variants — single variant architecture; compile-time constants can use BuildKonfig/gradle-buildconfig-plugin flavors, but variant-specific dependencies/resources/signing must move to app module
  • NDK/JNI unsupported in new plugin — extract to separate
    com.android.library
    module
  • Compose resources crash without
    androidResources { enable = true }
    (CMP-9547)
  • Consumer ProGuard rules silently dropped if not migrated to
    consumerProguardFiles.add(file(...))
    in new DSL
  • KSP requires version 2.3.4+ for AGP 9.0 compatibility
  • BuildConfig在库模块中不可用——使用DI/
    AppConfiguration
    接口,或使用BuildKonfiggradle-buildconfig-plugin生成编译时常量
  • 无构建变体——单一变体架构;编译时常量可使用BuildKonfig/gradle-buildconfig-plugin的flavors,但变体特定的依赖/资源/签名必须移至应用模块
  • 新插件不支持NDK/JNI——将其提取至独立的
    com.android.library
    模块
  • 未设置
    androidResources { enable = true }
    时Compose资源崩溃
    (CMP-9547)
  • 如果未迁移至新DSL中的
    consumerProguardFiles.add(file(...))
    ,消费者ProGuard规则会被静默丢弃
  • KSP需要2.3.4+版本才能兼容AGP 9.0

AGP 9.0 General Issues

AGP 9.0通用问题

  • Built-in Kotlin conflicts
    org.jetbrains.kotlin.android
    must be removed; kapt must be replaced
  • BaseExtension removed — convention plugins using old DSL types need rewriting
  • Variant APIs removed
    applicationVariants
    ,
    libraryVariants
    ,
    variantFilter
    replaced by
    androidComponents
  • R class non-final
    switch
    on R fields fails in app modules; refactor to
    if/else
  • targetSdk defaults to compileSdk — set explicitly to avoid unexpected behavior changes
  • R8 rule changes — strict full mode, no global options in consumer rules
  • Plugin compatibility — many plugins need updates or opt-out flags; check Plugin Compatibility section
  • Convention plugins need refactoring — old
    android {}
    extension helpers are obsolete
  • 内置Kotlin冲突——必须移除
    org.jetbrains.kotlin.android
    ;必须替换kapt
  • BaseExtension已移除——使用旧DSL类型的约定插件需要重写
  • Variant API已移除——
    applicationVariants
    libraryVariants
    variantFilter
    已被
    androidComponents
    替代
  • R类非final——应用模块中基于R字段的
    switch
    语句会失败;需重构为
    if/else
  • targetSdk默认值为compileSdk——请显式设置以避免意外行为变更
  • R8规则变更——严格全模式,消费者规则中不允许全局选项
  • 插件兼容性——许多插件需要更新或退出标志;请查看插件兼容性章节
  • 约定插件需要重构——旧的
    android {}
    扩展助手已过时

Reference Files

参考文件

  • DSL Reference — side-by-side old→new DSL mapping
  • Version Matrix — AGP/Gradle/KGP/IDE compatibility
  • Plugin Compatibility — third-party plugin status and workarounds
  • DSL参考——新旧DSL映射对比
  • 版本矩阵——AGP/Gradle/KGP/IDE兼容性
  • 插件兼容性——第三方插件状态和变通方案