Configurar o plug-in de biblioteca do Android Gradle para KMP

O plug-in do Gradle com.android.kotlin.multiplatform.library é a ferramenta oficialmente compatível para adicionar um destino Android a um módulo de biblioteca do Kotlin Multiplatform (KMP). Ele simplifica a configuração do projeto, melhora a performance do build e oferece uma integração melhor com o Android Studio.

A abordagem anterior foi descontinuada em favor do plug-in, também conhecido como plug-in Android-KMP. O uso do plug-in com.android.library para KMP não será mais compatível com a JetBrains e não vai se beneficiar de atualizações e melhorias futuras.

Para aplicar esse plug-in, consulte a seção Aplicar o plug-in Android-KMP. Se precisar migrar das APIs legadas, consulte o guia de migração.

Principais recursos e diferenças

O plug-in Android-KMP é feito especificamente para projetos KMP e difere do plug-in com.android.library padrão em vários aspectos principais:

  • Arquitetura de variante única:o plug-in usa uma única variante, removendo o suporte para variações de produto e tipos de build, o que simplifica a configuração e melhora o desempenho do build.

  • Otimizado para KMP:o plug-in foi projetado para bibliotecas KMP, com foco em código Kotlin compartilhado e interoperabilidade, sem suporte para AIDL, RenderScript e builds nativos específicos do Android.

  • Testes desativados por padrão:os testes de unidade e de dispositivo (instrumentação) são desativados por padrão para aumentar a velocidade do build. É possível ativá-los se necessário.

  • Nenhuma extensão do Android de nível superior:a configuração é processada com um bloco androidLibrary na DSL KMP do Gradle, mantendo uma estrutura de projeto KMP consistente. Não há um bloqueio de extensão de android de nível superior.

  • Ativar a compilação Java:a compilação Java fica desativada por padrão. Use withJava() no bloco androidLibrary para ativar. Isso melhora os tempos de build quando a compilação Java não é necessária.

Benefícios do plug-in da biblioteca Android-KMP

O plug-in Android-KMP oferece os seguintes benefícios para projetos KMP:

  • Melhoria na performance e estabilidade do build:projetado para otimizar as velocidades de build e melhorar a estabilidade em projetos KMP. O foco nos fluxos de trabalho do KMP contribui para um processo de build mais eficiente e confiável.

  • Integração aprimorada do ambiente de desenvolvimento integrado (IDE):oferece melhor preenchimento de código, navegação, depuração e experiência geral do desenvolvedor ao trabalhar com bibliotecas KMP Android.

  • Configuração simplificada do projeto:o plug-in simplifica a configuração de projetos KMP ao remover complexidades específicas do Android, como variantes de build. Isso resulta em arquivos de build mais limpos e fáceis de manter. Antes, usar o plug-in com.android.library em um projeto KMP podia criar nomes de conjuntos de origem confusos, como androidAndroidTest. Essa convenção de nomenclatura era menos intuitiva para desenvolvedores familiarizados com estruturas de projetos KMP padrão.

Pré-requisitos

Para usar o plug-in com.android.kotlin.multiplatform.library, seu projeto precisa ser configurado com as seguintes versões mínimas ou mais recentes:

  • Plug-in do Android para Gradle (AGP): 8.10.0
  • Plug-in do Kotlin para Gradle (KGP): 2.0.0

Aplicar o plug-in Android-KMP a um módulo atual

Para aplicar o plug-in Android-KMP a um módulo de biblioteca KMP atual, siga estas etapas:

  1. Declarar plug-ins no catálogo de versões. Abra o arquivo TOML do catálogo de versões (geralmente gradle/libs.versions.toml) e adicione a seção de definições de plug-in:

    # To check the version number of the latest Kotlin release, go to
    # https://kotlinlang.org/docs/releases.html
    
    [versions]
    androidGradlePlugin = "8.12.0"
    kotlin = "KOTLIN_VERSION"
    
    [plugins]
    kotlin-multiplatform = { id = "org.jetbrains.kotlin.multiplatform", version.ref = "kotlin" }
    android-kotlin-multiplatform-library = { id = "com.android.kotlin.multiplatform.library", version.ref = "androidGradlePlugin" }
    
  2. Aplique a declaração do plug-in no arquivo de build raiz. Abra o arquivo build.gradle.kts localizado no diretório raiz do projeto. Adicione os aliases do plug-in ao bloco plugins usando apply false. Isso disponibiliza os aliases do plug-in para todos os subprojetos sem aplicar a lógica do plug-in ao projeto raiz.

    Kotlin

    // Root build.gradle.kts file
    
    plugins {
       alias(libs.plugins.kotlin.multiplatform) apply false
    
       // Add the following
       alias(libs.plugins.android.kotlin.multiplatform.library) apply false
    }

    Groovy

    // Root build.gradle file
    
    plugins {
       alias(libs.plugins.kotlin.multiplatform) apply false
    
       // Add the following
       alias(libs.plugins.android.kotlin.multiplatform.library) apply false
    }
  3. Aplique o plug-in em um arquivo de build do módulo de biblioteca KMP. Abra o arquivo build.gradle.kts no módulo da biblioteca KMP e aplique o plug-in na parte de cima do arquivo dentro do bloco plugins:

    Kotlin

    // Module-specific build.gradle.kts file
    
    plugins {
       alias(libs.plugins.kotlin.multiplatform)
    
       // Add the following
       alias(libs.plugins.android.kotlin.multiplatform.library)
    }

    Groovy

    // Module-specific build.gradle file
    
    plugins {
       alias(libs.plugins.kotlin.multiplatform)
    
       // Add the following
       alias(libs.plugins.android.kotlin.multiplatform.library)
    }
  4. Configure o destino do KMP do Android. Configure o bloco Kotlin Multiplatform (kotlin) para definir a plataforma de destino do Android. No bloco kotlin, especifique o destino do Android usando androidLibrary:

    Kotlin

    kotlin {
       androidLibrary {
           namespace = "com.example.kmpfirstlib"
           compileSdk = 33
           minSdk = 24
    
           withJava() // enable java compilation support
           withHostTestBuilder {}.configure {}
           withDeviceTestBuilder {
               sourceSetTreeName = "test"
           }
    
           compilations.configureEach {
               compilerOptions.configure {
                   jvmTarget.set(
                       org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_1_8
                   )
               }
           }
       }
    
       sourceSets {
           androidMain {
               dependencies {
                   // Add Android-specific dependencies here
               }
           }
           getByName("androidHostTest") {
               dependencies {
               }
           }
    
           getByName("androidDeviceTest") {
               dependencies {
               }
           }
       }
       // ... other targets (JVM, iOS, etc.) ...
    }

    Groovy

    kotlin {
       androidLibrary {
           namespace = "com.example.kmpfirstlib"
           compileSdk = 33
           minSdk = 24
    
           withJava() // enable java compilation support
           withHostTestBuilder {}.configure {}
           withDeviceTestBuilder {
               it.sourceSetTreeName = "test"
           }
    
           compilations.configureEach {
               compilerOptions.options.jvmTarget.set(
                   org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_1_8
               )
           }
       }
    
       sourceSets {
           androidMain {
               dependencies {
               }
           }
           androidHostTest {
               dependencies {
               }
           }
           androidDeviceTest {
               dependencies {
               }
           }
       }
       // ... other targets (JVM, iOS, etc.) ...
    }
  5. Aplicar mudanças. Depois de aplicar o plug-in e configurar o bloco kotlin, sincronize seu projeto do Gradle para aplicar as mudanças.

Migrar do plug-in legado

Este guia ajuda você a migrar do plug-in com.android.library legado para o plug-in com.android.kotlin.multiplatform.library.

1. Como declarar dependências

Uma tarefa comum é declarar dependências para conjuntos de origem específicos do Android. O novo plug-in exige que eles sejam colocados explicitamente no bloco sourceSets, ao contrário do bloco dependencies geral usado anteriormente.

Android-KMP

O novo plug-in promove uma estrutura mais limpa agrupando dependências do Android no conjunto de origem androidMain. Além do conjunto de origem principal, há dois conjuntos de origem de teste, que são criados sob demanda: androidDeviceTest e androidHostTest. Consulte Configurar testes de host e dispositivo para mais informações.

// build.gradle.kts

kotlin {
    android {}
    //... other targets

    sourceSets {
        commonMain.dependencies {
            implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.0")
        }

        // Dependencies are now scoped to the specific Android source set
        androidMain.dependencies {
            implementation("androidx.appcompat:appcompat:1.7.0")
            implementation("com.google.android.material:material:1.11.0")
        }
    }
}

Os conjuntos de origem têm compilações correspondentes do Kotlin chamadas main, deviceTest e hostTest. Os conjuntos e as compilações de origem podem ser configurados no script de build da seguinte maneira:

// build.gradle.kts

kotlin {
    androidLibrary {
        compilations.getByName("deviceTest") {
            kotlinOptions.languageVersion = "2.0"
        }
    }
}

Plug-in legado

Com o plug-in antigo, era possível declarar dependências específicas do Android no bloco de dependências de nível superior, o que às vezes podia ser confuso em um módulo multiplataforma.

// build.gradle.kts

kotlin {
  androidTarget()
  //... other targets
}

// Dependencies for all source sets were often mixed in one block
dependencies {
  // Common dependencies
  commonMainImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.0")

  // Android-specific dependencies
  implementation("androidx.appcompat:appcompat:1.7.0")
  implementation("com.google.android.material:material:1.11.0")
}

2. Como ativar recursos do Android

O suporte para recursos do Android (pastas res) não é ativado por padrão no novo plug-in para otimizar o desempenho do build. É necessário ativar esse recurso para usar. Essa mudança ajuda a garantir que os projetos que não exigem recursos específicos do Android não sejam afetados pela sobrecarga de build associada.

Android-KMP

É preciso ativar explicitamente o processamento de recursos do Android. Os recursos precisam ser colocados em src/androidMain/res.

// build.gradle.kts

kotlin {
  android {
    // ...
    // Enable Android resource processing
    androidResources {
      enable = true
    }
  }
}

// Project Structure
// └── src
//     └── androidMain
//         └── res
//             ├── values
//             │   └── strings.xml
//             └── drawable
//                 └── icon.xml

Plug-in legado

O processamento de recursos estava ativado por padrão. Você pode adicionar imediatamente um diretório res em src/main e começar a adicionar elementos gráficos, valores XML etc.

// build.gradle.kts

android {
    namespace = "com.example.library"
    compileSdk = 34
    // No extra configuration was needed to enable resources.
}

// Project Structure
// └── src
//     └── main
//         └── res
//             ├── values
//             │   └── strings.xml
//             └── drawable
//                 └── icon.xml

3. Como configurar testes de host e dispositivo

Uma mudança significativa no novo plug-in é que os testes do lado do host (unidade) e do dispositivo (instrumentados) do Android são desativados por padrão. É necessário ativar explicitamente a criação dos conjuntos de origem e configurações de teste, enquanto o plug-in antigo os criava automaticamente.

Esse modelo de inclusão ajuda a verificar se o projeto permanece enxuto e inclui apenas a lógica de build e os conjuntos de origem que você usa ativamente.

Android-KMP

No novo plug-in, ative e configure os testes dentro do bloco kotlin.android. Isso torna a configuração mais explícita e evita a criação de componentes de teste não utilizados. O conjunto de origem test se torna androidHostTest, e androidTest se torna androidDeviceTest.

// build.gradle.kts

kotlin {
  android {
    // ...

    // Opt-in to enable and configure host-side (unit) tests
    withHostTest {
      isIncludeAndroidResources = true
    }

    // Opt-in to enable and configure device-side (instrumented) tests
    withDeviceTest {
      instrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
      execution = "ANDROIDX_TEST_ORCHESTRATOR"
    }
  }
}

// Project Structure (After Opt-in)
// └── src
//     ├── androidHostTest
//     └── androidDeviceTest

Plug-in legado

Com o plug-in com.android.library, os conjuntos de origem test e androidTest foram criados por padrão. Você configuraria o comportamento deles dentro do bloco android, geralmente usando a DSL testOptions.

// build.gradle.kts

android {
  defaultConfig {
    // Runner was configured in defaultConfig
    testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
  }

  testOptions {
    // Configure unit tests (for the 'test' source set)
    unitTests.isIncludeAndroidResources = true

    // Configure device tests (for the 'androidTest' source set)
    execution = "ANDROIDX_TEST_ORCHESTRATOR"
  }
}

// Project Structure (Defaults)
// └── src
//     ├── test
//     └── androidTest

4. Ativar a compilação de origem Java

Se a biblioteca KMP precisar compilar fontes Java para a plataforma Android, você precisará ativar explicitamente essa funcionalidade com o novo plug-in. Isso ativa a compilação de arquivos Java localizados diretamente no projeto, não nas dependências dele. O método para definir a versão de destino da JVM do compilador Java e Kotlin também muda.

Android-KMP

Você precisa ativar a compilação Java chamando withJava(). O destino da JVM agora é configurado diretamente no bloco kotlin { androidLibrary {} } para uma configuração mais unificada. A definição de jvmTarget aqui se aplica à compilação em Kotlin e em Java para a plataforma Android.

// build.gradle.kts

kotlin {
  android {
    //  Opt-in to enable Java source compilation
    withJava()
    // Configure the JVM target for both Kotlin and Java sources
    compilerOptions {
      jvmTarget.set(org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_1_8)
    }
  }
  // ...
}

// Project Structure:
// └── src
//     └── androidMain
//         ├── kotlin
//         │   └── com/example/MyKotlinClass.kt
//         └── java
//             └── com.example/MyJavaClass.java

Plug-in legado

A compilação Java era ativada por padrão. O destino da JVM para fontes Java e Kotlin foi definido no bloco "android" usando "compileOptions".

// build.gradle.kts

android {
  // ...
  compileOptions {
    sourceCompatibility = JavaVersion.VERSION_1_8
    targetCompatibility = JavaVersion.VERSION_1_8
  }
}

kotlin {
  androidTarget {
    compilations.all {
      kotlinOptions.jvmTarget = "1.8"
    }
  }
}

5. Interagir com variantes de build usando androidComponents

A extensão androidComponents ainda está disponível para interagir com artefatos de build de forma programática. Embora grande parte da API Variant permaneça a mesma, a nova interface AndroidKotlinMultiplatformVariant é mais limitada porque o plug-in produz apenas uma variante.

Consequentemente, as propriedades relacionadas a tipos de build e variações de produto não estão mais disponíveis no objeto de variante.

Android-KMP

O bloco onVariants agora itera em uma única variante. Você ainda pode acessar propriedades comuns, como name e artifacts, mas não aquelas específicas do tipo de build.

// build.gradle.kts

androidComponents {
  onVariants { variant ->
      val artifacts = variant.artifacts
  }
}

Plug-in legado

Com várias variantes, você pode acessar propriedades específicas do tipo de build para configurar tarefas.

// build.gradle.kts

androidComponents {
  onVariants(selector().withBuildType("release")) { variant ->
    // ...
  }
}

6. Selecionar variantes de dependências de biblioteca do Android

Sua biblioteca KMP produz uma única variante para Android. No entanto, talvez você dependa de uma biblioteca padrão do Android (com.android.library) que tenha várias variantes (por exemplo, free/paid variações de produtos). Controlar como seu projeto seleciona uma variante dessa dependência é um requisito comum.

Android-KMP

O novo plug-in centraliza e esclarece essa lógica no bloco kotlin.android.localDependencySelection. Isso deixa muito mais claro quais variantes de dependências externas serão selecionadas para sua biblioteca KMP de variante única.

// build.gradle.kts
kotlin {
  android {
    localDependencySelection {
      // For dependencies with multiple build types, select 'debug' first, and 'release' in case 'debug' is missing
      selectBuildTypeFrom.set(listOf("debug", "release"))

      // For dependencies with a 'type' flavor dimension...
      productFlavorDimension("type") {
        // ...select the 'typeone' flavor.
        selectFrom.set(listOf("typeone"))
      }
    }
  }
}

Plug-in legado

Você configurou estratégias de seleção de dependências nos blocos buildTypes and productFlavors. Isso geralmente envolvia o uso de missingDimensionStrategy para fornecer uma variação padrão para uma dimensão que a biblioteca não tinha, ou matchingFallbacks em uma variação específica para definir uma ordem de pesquisa.

Consulte Resolver erros de correspondência para mais informações sobre o uso da API.

Referência da API do plug-in

O novo plug-in tem uma plataforma de API diferente de com.android.library. Para informações detalhadas sobre a nova DSL e as interfaces, consulte as referências da API: