Dokumen ini memberikan panduan bagi penulis plugin tentang cara mendeteksi, berinteraksi dengan, dan mengonfigurasi penyiapan Kotlin Multiplatform (KMP) dengan benar, dengan fokus khusus pada integrasi dengan target Android dalam project KMP. Seiring dengan terus berkembangnya KMP, pemahaman tentang hook dan API yang tepat—seperti jenis KotlinMultiplatformExtension, KotlinTarget, dan antarmuka integrasi khusus Android—sangat penting untuk membangun alat yang andal dan siap digunakan di masa mendatang yang berfungsi dengan lancar di semua platform yang ditentukan dalam project multiplatform.
Memeriksa apakah project menggunakan plugin Multiplatform Kotlin
Untuk menghindari error dan memastikan plugin Anda hanya berjalan saat KMP ada, Anda harus memeriksa apakah project menggunakan plugin KMP. Praktik terbaiknya adalah menggunakan
plugins.withId() untuk bereaksi terhadap penerapan plugin KMP, bukan
memeriksanya secara langsung. Pendekatan reaktif ini mencegah plugin Anda menjadi rentan terhadap urutan penerapan plugin dalam skrip build pengguna.
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.
}
}
}
Mengakses model
Titik entri untuk semua konfigurasi Multiplatform Kotlin adalah ekstensi
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)
}
}
}
Bereaksi terhadap target Multiplatform Kotlin
Gunakan penampung targets untuk mengonfigurasi plugin secara reaktif untuk setiap target yang ditambahkan pengguna.
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
}
}
}
}
Menerapkan logika khusus target
Jika plugin Anda perlu menerapkan logika hanya ke jenis platform tertentu, pendekatan umum adalah memeriksa properti platformType. Ini adalah enum yang secara luas mengategorikan target.
Misalnya, gunakan ini jika plugin Anda hanya perlu membedakan secara luas (misalnya, hanya berjalan pada target seperti 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 or Android */ }
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) */ }
}
}
}
}
}
Detail khusus Android
Meskipun semua target Android memiliki indikator platformType.androidJvm, KMP memiliki
dua titik integrasi yang berbeda, bergantung pada plugin Android Gradle yang digunakan:
KotlinAndroidTarget untuk project yang menggunakan com.android.library atau
com.android.application, dan KotlinMultiplatformAndroidLibraryTarget untuk
project yang menggunakan com.android.kotlin.multiplatform.library.
API KotlinMultiplatformAndroidLibraryTarget ditambahkan di AGP 8.8.0, jadi jika
konsumen plugin Anda berjalan di versi AGP yang lebih rendah, memeriksa
target is KotlinMultiplatformAndroidLibraryTarget dapat menyebabkan
ClassNotFoundException. Agar aman, periksa
AndroidPluginVersion.getCurrent() sebelum memeriksa jenis target.
Perhatikan bahwa AndroidPluginVersion.getCurrent() memerlukan AGP 7.1 atau yang lebih tinggi.
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.mpp.KotlinAndroidTarget
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 ->
if (target is KotlinAndroidTarget) {
// Old kmp android integration using com.android.library or com.android.application
}
if (AndroidPluginVersion.getCurrent() >= AndroidPluginVersion(8, 8) &&
target is KotlinMultiplatformAndroidLibraryTarget
) {
// New kmp android integration using com.android.kotlin.multiplatform.library
}
}
}
}
}
Mengakses ekstensi KMP Android dan propertinya
Plugin Anda terutama akan berinteraksi dengan ekstensi Kotlin yang disediakan
oleh plugin Multiplatform Kotlin dan ekstensi Android yang disediakan oleh AGP
untuk target Android KMP. Blok android {} dalam ekstensi Kotlin di project KMP diwakili oleh antarmuka KotlinMultiplatformAndroidLibraryTarget, yang juga memperluas KotlinMultiplatformAndroidLibraryExtension.
Artinya, Anda dapat mengakses properti DSL khusus target dan khusus Android melalui satu objek ini.
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
}
}
}
}
Tidak seperti plugin Android lainnya (seperti com.android.library atau
com.android.application), plugin Android KMP tidak mendaftarkan ekstensi DSL
utamanya di tingkat project. File ini berada dalam hierarki target KMP
untuk memastikan file ini hanya berlaku untuk target Android tertentu yang ditentukan dalam
penyiapan multiplatform Anda.
Menangani kompilasi dan set sumber
Sering kali, plugin perlu berfungsi pada tingkat yang lebih terperinci daripada hanya
target—khususnya, plugin perlu berfungsi pada tingkat kompilasi. KotlinMultiplatformAndroidLibraryTarget
berisi instance KotlinMultiplatformAndroidCompilation (misalnya, main,
hostTest, deviceTest). Setiap kompilasi dikaitkan dengan set sumber Kotlin. Plugin dapat berinteraksi dengan ini untuk menambahkan sumber, dependensi, atau mengonfigurasi
tugas kompilasi.
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 ->
}
}
}
}
}
}
Mengonfigurasi kompilasi pengujian di plugin konvensi
Saat mengonfigurasi nilai default untuk kompilasi pengujian (seperti targetSdk untuk
pengujian instrumentasi) di plugin konvensi, Anda harus menghindari penggunaan metode
pengaktif seperti withDeviceTest { } atau withHostTest { }. Memanggil metode ini secara langsung akan memicu pembuatan varian pengujian Android dan kompilasi yang sesuai untuk setiap modul yang menerapkan plugin konvensi, yang mungkin tidak sesuai. Selain itu, metode ini tidak dapat dipanggil untuk kedua kalinya dalam
modul tertentu untuk menyempurnakan setelan, karena tindakan tersebut akan memunculkan error
yang menyatakan bahwa kompilasi telah dibuat.
Sebagai gantinya, sebaiknya gunakan blok configureEach reaktif
pada penampung kompilasi. Dengan demikian, Anda dapat memberikan konfigurasi default
yang hanya berlaku jika dan saat modul mengaktifkan kompilasi pengujian secara eksplisit:
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 {
targetSdk { version = release(34) }
}
}
}
}
}
Pola ini memastikan bahwa plugin konvensi Anda tetap dimuat secara lazy dan memungkinkan
setiap modul memanggil withDeviceTest { } untuk mengaktifkan dan menyesuaikan lebih lanjut
pengujiannya tanpa berkonflik dengan default.
Berinteraksi dengan Variant API
Untuk tugas yang memerlukan konfigurasi tahap akhir, akses artefak (seperti
manifest atau byte-code), atau kemampuan untuk mengaktifkan atau menonaktifkan
komponen tertentu, Anda harus menggunakan Android Variant API. Dalam project KMP, ekstensi berjenis KotlinMultiplatformAndroidComponentsExtension.
Ekstensi didaftarkan di tingkat project saat plugin Android KMP diterapkan.
Gunakan beforeVariants untuk mengontrol pembuatan varian atau komponen pengujian bertingkatnya (hostTests dan deviceTests). Di sinilah tempat yang tepat untuk menonaktifkan pengujian secara terprogram atau mengubah nilai properti 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 }
}
}
}
}
Gunakan onVariants untuk mengakses objek varian akhir
(KotlinMultiplatformAndroidVariant). Di sini Anda dapat memeriksa properti yang telah diselesaikan
atau mendaftarkan transformasi pada artefak seperti manifes gabungan
atau class library.
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.variant.SingleArtifact.MERGED_MANIFEST)
}
}
}
}
Direkomendasikan untuk Anda
- Catatan: teks link ditampilkan saat JavaScript nonaktif
- Menyiapkan lingkungan Anda
- Menambahkan modul KMP ke project
- Menyiapkan Plugin Library Android Gradle untuk KMP