Dokumen ini memberikan panduan bagi penulis plugin tentang cara mendeteksi, berinteraksi dengan, dan mengonfigurasi penyiapan Multiplatform Kotlin (KMP) dengan benar, dengan fokus khusus pada integrasi dengan target Android dalam project KMP.
Rekomendasi ini berlaku baik saat Anda membuat plugin konvensi untuk menstandarkan konfigurasi di seluruh modul project atau mengembangkan plugin untuk penggunaan komunitas yang lebih luas. Seiring dengan terus berkembangnya KMP, memahami hook dan API yang tepat—seperti KotlinMultiplatformExtension, jenis KotlinTarget, dan antarmuka integrasi khusus Android—sangat penting untuk membangun alat yang tangguh 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. Sebaiknya gunakan plugins.withId() untuk bereaksi terhadap penerapan plugin KMP, bukan langsung memeriksanya. Pendekatan reaktif ini mencegah plugin Anda menjadi rapuh 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 sehingga jika
konsumen plugin Anda menjalankan AGP versi yang lebih rendah, memeriksa
target is KotlinMultiplatformAndroidLibraryTarget dapat menghasilkan
ClassNotFoundException. Untuk membuatnya 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 Android KMP dan propertinya
Plugin Anda akan berinteraksi terutama 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 direpresentasikan 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. Plugin ini berada dalam hierarki target KMP untuk memastikan hanya berlaku untuk target Android tertentu yang ditentukan dalam penyiapan multiplatform Anda.
Menangani kompilasi dan set sumber
Sering kali, plugin perlu bekerja pada tingkat yang lebih terperinci daripada hanya target—khususnya, plugin perlu bekerja 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 akan memicu pembuatan varian dan kompilasi pengujian Android 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 melakukannya akan menampilkan error yang menyatakan bahwa kompilasi telah dibuat.
Sebagai gantinya, sebaiknya gunakan blok configureEach reaktif pada penampung kompilasi. Hal ini memungkinkan Anda memberikan konfigurasi default yang hanya berlaku jika dan saat modul secara eksplisit mengaktifkan kompilasi pengujian:
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 plugin konvensi Anda tetap lambat dan memungkinkan setiap modul memanggil withDeviceTest { } untuk mengaktifkan dan menyesuaikan pengujian lebih lanjut tanpa bertentangan dengan default.
Berinteraksi dengan Variant API
Untuk tugas yang memerlukan konfigurasi tahap akhir, akses artefak (seperti manifes atau kode byte), atau kemampuan untuk mengaktifkan atau menonaktifkan komponen tertentu, Anda harus menggunakan Android Variant API. Dalam project KMP, ekstensi berjenis KotlinMultiplatformAndroidComponentsExtension.
Ekstensi ini didaftarkan di tingkat project saat plugin Android KMP diterapkan.
Gunakan beforeVariants untuk mengontrol pembuatan varian atau komponen pengujian bertingkatnya (hostTests dan deviceTests). Ini adalah 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 sinilah Anda dapat memeriksa properti yang di-resolve 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