Este guia explica como detectar, interagir e configurar o destino do Android em um projeto Kotlin Multiplatform (KMP) usando um plug-in personalizado do Gradle. Use essas APIs ao escrever plug-ins de convenção para seu build ou publicar plug-ins do Gradle para projetos KMP.
Verificar se um projeto usa o plug-in do Kotlin Multiplatform
Para evitar erros e garantir que o plug-in seja executado apenas quando o KMP estiver presente,
verifique se o projeto usa o plug-in do KMP. A prática recomendada é usar
plugins.withId() para reagir à aplicação do plug-in do KMP, em vez de
verificar imediatamente. Essa abordagem reativa impede que o plug-in seja
frágil em relação à ordem em que os plug-ins são aplicados nos scripts de build
do usuário.
import org.gradle.api.Plugin
import org.gradle.api.Project
class MyPlugin : Plugin<Project> {
override fun apply(project: Project) {
project.plugins.withId("org.jetbrains.kotlin.multiplatform") {
// The KMP plugin is applied, you can now configure your KMP integration.
}
}
}
Acessar o modelo
O ponto de entrada para todas as configurações do Kotlin Multiplatform é a
extensão KotlinMultiplatformExtension.
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
class MyPlugin : Plugin<Project> {
override fun apply(project: Project) {
project.plugins.withId("org.jetbrains.kotlin.multiplatform") {
val kmpExtension = project.extensions.getByType(KotlinMultiplatformExtension::class.java)
}
}
}
Reagir a destinos do Kotlin Multiplatform
Use o contêiner targets para configurar o plug-in de forma reativa para cada destino
adicionado pelo usuário.
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
class MyPlugin : Plugin<Project> {
override fun apply(project: Project) {
project.plugins.withId("org.jetbrains.kotlin.multiplatform") {
val kmpExtension = project.extensions.getByType(KotlinMultiplatformExtension::class.java)
kmpExtension.targets.configureEach { target ->
// 'target' is an instance of KotlinTarget
val targetName = target.name // for example, "android", "iosX64", "jvm"
val platformType = target.platformType // for example, androidJvm, jvm, native, js
}
}
}
}
Aplicar lógica específica do destino
Se o plug-in precisar aplicar lógica apenas a determinados tipos de plataformas, uma abordagem comum
é verificar a propriedade platformType. Este é um tipo enumerado que categoriza
amplamente o destino.
Por exemplo, use isso se o plug-in só precisar fazer uma diferenciação ampla, como executar apenas em destinos semelhantes à JVM:
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType
class MyPlugin : Plugin<Project> {
override fun apply(project: Project) {
project.plugins.withId("org.jetbrains.kotlin.multiplatform") {
val kmpExtension = project.extensions.getByType(KotlinMultiplatformExtension::class.java)
kmpExtension.targets.configureEach { target ->
when (target.platformType) {
KotlinPlatformType.jvm -> { /* Standard JVM */ }
KotlinPlatformType.androidJvm -> { /* Android */ }
KotlinPlatformType.js -> { /* JavaScript */ }
KotlinPlatformType.native -> { /* Any Native (iOS, Linux, Windows, etc.) */ }
KotlinPlatformType.wasm -> { /* WebAssembly */ }
KotlinPlatformType.common -> { /* Metadata target (rarely needs direct plugin interaction) */ }
}
}
}
}
}
Detalhes específicos do Android
Embora todos os destinos do Android tenham o indicador platformType.androidJvm, o KMP tem
dois pontos de integração distintos, dependendo do Plug-in do Android para Gradle usado:
KotlinAndroidTarget para projetos que usam com.android.library ou
com.android.application e KotlinMultiplatformAndroidLibraryTarget para
projetos que usam com.android.kotlin.multiplatform.library.
A API KotlinMultiplatformAndroidLibraryTarget foi adicionada no AGP 8.8.0. Portanto, se
os consumidores do seu plug-in estiverem usando uma versão anterior do AGP, a verificação
de target is KotlinMultiplatformAndroidLibraryTarget pode resultar em um
ClassNotFoundException. Para que isso seja seguro, verifique
AndroidPluginVersion.getCurrent() antes de verificar o tipo de destino.
O AndroidPluginVersion.getCurrent() requer o AGP 8.3.1 ou versões mais recentes.
import com.android.build.api.AndroidPluginVersion
import com.android.build.api.dsl.KotlinMultiplatformAndroidLibraryTarget
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinAndroidTarget
class MyPlugin : Plugin<Project> {
override fun apply(project: Project) {
project.plugins.withId("org.jetbrains.kotlin.multiplatform") {
val kmpExtension = project.extensions.getByType(KotlinMultiplatformExtension::class.java)
kmpExtension.targets.configureEach { target ->
if (target is KotlinAndroidTarget) {
// Old kmp android integration using com.android.library or com.android.application
} else if (
// Check platformType first, so AGP classes load only for Android targets
target.platformType == KotlinPlatformType.androidJvm &&
AndroidPluginVersion.getCurrent() >= AndroidPluginVersion(8, 8) &&
target is KotlinMultiplatformAndroidLibraryTarget
) {
// New kmp android integration using com.android.kotlin.multiplatform.library
}
}
}
}
}
Acessar a extensão do KMP para Android e as propriedades dela
Seu plug-in interage principalmente com a extensão do Kotlin fornecida
pelo plug-in do Kotlin Multiplatform e com a extensão do Android fornecida pelo AGP
para o destino do Android do KMP. O bloco android {} na extensão Kotlin
em um projeto KMP é representado pela interface
KotlinMultiplatformAndroidLibraryTarget, que também estende KotlinMultiplatformAndroidLibraryExtension.
Isso significa que é possível acessar as propriedades de DSL específicas do destino e do Android
por esse único objeto.
import com.android.build.api.dsl.KotlinMultiplatformAndroidLibraryTarget
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
import org.jetbrains.kotlin.gradle.plugin.KotlinMultiplatformPluginWrapper
class MyPlugin : Plugin<Project> {
override fun apply(project: Project) {
project.plugins.withId("com.android.kotlin.multiplatform.library") {
val kmpExtension = project.extensions.getByType(KotlinMultiplatformExtension::class.java)
// Access the Android target, which also serves as the Android-specific DSL extension
kmpExtension.targets.withType(KotlinMultiplatformAndroidLibraryTarget::class.java).configureEach { androidTarget ->
// You can now access properties and methods from both
// KotlinMultiplatformAndroidLibraryTarget and KotlinMultiplatformAndroidLibraryExtension
androidTarget.compileSdk = 34
androidTarget.namespace = "com.example.myplugin.library"
androidTarget.withJava() // enable Java sources
}
}
}
}
Ao contrário de outros plug-ins do Android (como com.android.library ou
com.android.application), o plug-in do Android para KMP não registra a extensão principal
da DSL no nível do projeto. Ele fica na hierarquia de destino do KMP
para garantir que seja aplicado apenas ao destino específico do Android definido na sua
configuração multiplataforma.
Processar compilações e conjuntos de origem
Muitas vezes, os plug-ins precisam funcionar em um nível mais granular do que apenas o destino,
especificamente no nível de compilação. O
KotlinMultiplatformAndroidLibraryTarget contém
instâncias de KotlinMultiplatformAndroidCompilation (por exemplo, main,
hostTest, deviceTest). Cada compilação está associada a conjuntos de origem
do Kotlin. Os plug-ins podem interagir com eles para adicionar origens, dependências ou configurar
tarefas de compilação.
import com.android.build.api.dsl.KotlinMultiplatformAndroidCompilation
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
class MyPlugin : Plugin<Project> {
override fun apply(project: Project) {
project.plugins.withId("com.android.kotlin.multiplatform.library") {
val kmpExtension = project.extensions.getByType(KotlinMultiplatformExtension::class.java)
kmpExtension.targets.configureEach { target ->
target.compilations.configureEach { compilation ->
// standard compilations are usually 'main' and 'test'
// android target has 'main', 'hostTest', 'deviceTest'
val compilationName = compilation.name
// Access the default source set for this compilation
val defaultSourceSet = compilation.defaultSourceSet
// Access the Android-specific compilation DSL
if (compilation is KotlinMultiplatformAndroidCompilation) {
}
// Access and configure the Kotlin compilation task
compilation.compileTaskProvider.configure { compileTask ->
}
}
}
}
}
}
Configurar compilações de teste em plug-ins de convenção
Ao configurar valores padrão para compilações de teste (como targetSdk para testes de instrumentação) em um plug-in de convenção, evite usar métodos de ativação, como withDeviceTest { } ou withHostTest { }. Chamar esses métodos aciona
a criação das variantes de teste do Android correspondentes e
as compilações para cada módulo que aplica o plug-in de convenção, o que pode
não ser adequado. Esses métodos também não podem ser chamados uma segunda vez em um módulo
específico para refinar as configurações, porque isso gera um erro informando que a
compilação já foi criada.
Em vez disso, use um bloco configureEach reativo no contêiner de compilações.
Isso permite que você forneça configurações padrão que só se aplicam se e quando um
módulo ativa explicitamente a compilação de teste:
import com.android.build.api.dsl.KotlinMultiplatformAndroidDeviceTestCompilation
import com.android.build.api.dsl.KotlinMultiplatformAndroidLibraryTarget
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
class MyPlugin : Plugin<Project> {
override fun apply(project: Project) {
project.plugins.withId("com.android.kotlin.multiplatform.library") {
val kmpExtension =
project.extensions.getByType(KotlinMultiplatformExtension::class.java)
kmpExtension.targets.withType(KotlinMultiplatformAndroidLibraryTarget::class.java)
.configureEach { androidTarget ->
androidTarget.compilations.withType(
KotlinMultiplatformAndroidDeviceTestCompilation::class.java
).configureEach {
it.targetSdk { version = release(34) }
}
}
}
}
}
Esse padrão garante que o plug-in de convenção permaneça lento e permite que
módulos individuais chamem withDeviceTest { } para ativar e personalizar ainda mais
os testes sem entrar em conflito com os padrões.
Interagir com a API Variant
Para tarefas que exigem configuração de estágio final, acesso a artefatos (como
manifestos ou bytecode) ou a capacidade de ativar ou desativar componentes
específicos, use a API Android Variant. Em projetos KMP, a
extensão é do tipo KotlinMultiplatformAndroidComponentsExtension.
A extensão é registrada no nível do projeto quando o plug-in do Android para KMP é aplicado.
Use beforeVariants para controlar a criação de variantes ou os componentes de teste
aninhados (hostTests e deviceTests). Esse é o lugar correto para
desativar testes de maneira programática ou mudar os valores das propriedades da DSL.
import com.android.build.api.variant.KotlinMultiplatformAndroidComponentsExtension
import org.gradle.api.Plugin
import org.gradle.api.Project
class MyPlugin : Plugin<Project> {
override fun apply(project: Project) {
project.plugins.withId("com.android.kotlin.multiplatform.library") {
val androidComponents = project.extensions.findByType(KotlinMultiplatformAndroidComponentsExtension::class.java)
androidComponents?.beforeVariants { variantBuilder ->
// Disable all tests for this module
variantBuilder.hostTests.values.forEach { it.enable = false }
variantBuilder.deviceTests.values.forEach { it.enable = false }
}
}
}
}
Use onVariants para acessar o objeto de variante final
(KotlinMultiplatformAndroidVariant). É aqui que você pode inspecionar propriedades
resolvidas ou registrar transformações em artefatos, como o manifesto integrado
ou as classes de biblioteca.
import com.android.build.api.variant.KotlinMultiplatformAndroidComponentsExtension
import org.gradle.api.Plugin
import org.gradle.api.Project
class MyPlugin : Plugin<Project> {
override fun apply(project: Project) {
project.plugins.withId("com.android.kotlin.multiplatform.library") {
val androidComponents = project.extensions.findByType(KotlinMultiplatformAndroidComponentsExtension::class.java)
androidComponents?.onVariants { variant ->
// 'variant' is a KotlinMultiplatformAndroidVariant
val variantName = variant.name
// Access the artifacts API
val manifest = variant.artifacts.get(com.android.build.api.artifact.SingleArtifact.MERGED_MANIFEST)
}
}
}
}
Recomendados para você
- Observação: o texto do link aparece quando o JavaScript está desativado.
- Configurar o ambiente
- Adicionar um módulo KMP a um projeto
- Configurar o plug-in da biblioteca do Android para Gradle para KMP