Konfigurowanie wtyczki Android Gradle Library Plugin dla KMP

com.android.kotlin.multiplatform.libraryWtyczka Gradle to oficjalnie obsługiwane narzędzie do dodawania platformy Android do modułu biblioteki Kotlin Multiplatform (KMP). Upraszcza konfigurację projektu, zwiększa wydajność kompilacji i zapewnia lepszą integrację z Androidem Studio.

Poprzednie podejście zostało wycofane na rzecz wtyczki, zwanej też wtyczką Android-KMP. Dalsze korzystanie z com.android.librarywtyczki do KMP nie będzie już obsługiwane przez JetBrains i nie będzie korzystać z przyszłych aktualizacji ani ulepszeń.

Aby zastosować tę wtyczkę, zapoznaj się z sekcją Stosowanie wtyczki Android-KMP. Jeśli musisz przeprowadzić migrację ze starszych interfejsów API, zapoznaj się z przewodnikiem po migracji.

Najważniejsze funkcje i różnice

Wtyczka Android-KMP jest dostosowana specjalnie do projektów KMP i różni się od standardowej wtyczki com.android.library w kilku kluczowych aspektach:

  • Architektura pojedynczego wariantu: wtyczka używa pojedynczego wariantu, co eliminuje obsługę wersji produktu i typów kompilacji, upraszcza konfigurację i zwiększa wydajność kompilacji.

  • Zoptymalizowana pod kątem KMP: wtyczka jest przeznaczona do bibliotek KMP i skupia się na wspólnym kodzie Kotlin oraz interoperacyjności, pomijając obsługę natywnych kompilacji specyficznych dla Androida, AIDL i RenderScript.

  • Testy domyślnie wyłączone: zarówno testy jednostkowe, jak i testy na urządzeniu (instrumentacyjne) są domyślnie wyłączone, aby zwiększyć szybkość kompilacji. W razie potrzeby możesz je włączyć.

  • Brak rozszerzenia Androida najwyższego poziomu: konfiguracja jest obsługiwana za pomocą bloku androidLibrary w języku DSL Gradle KMP, co zapewnia spójną strukturę projektu KMP. Nie ma bloku rozszerzenia android najwyższego poziomu.

  • Kompilacja Javy z wyrażeniem zgody: kompilacja Javy jest domyślnie wyłączona. Aby ją włączyć, użyj withJava() w bloku androidLibrary. Skraca to czas kompilacji, gdy kompilacja w Javie nie jest potrzebna.

Zalety wtyczki biblioteki Android-KMP

Wtyczka Android-KMP zapewnia te korzyści w przypadku projektów KMP:

  • Ulepszona wydajność i stabilność kompilacji: zaprojektowano ją z myślą o optymalizacji szybkości kompilacji i zwiększeniu stabilności w projektach KMP. Skupienie się na przepływach pracy KMP przyczynia się do bardziej wydajnego i niezawodnego procesu kompilacji.

  • Ulepszona integracja z IDE: zapewnia lepsze uzupełnianie kodu, nawigację, debugowanie i ogólne wrażenia deweloperskie podczas pracy z bibliotekami KMP na Androida.

  • Uproszczona konfiguracja projektu: wtyczka upraszcza konfigurację projektów KMP, usuwając złożoności związane z Androidem, takie jak warianty kompilacji. Dzięki temu pliki kompilacji są bardziej przejrzyste i łatwiejsze w utrzymaniu. Wcześniej użycie wtyczki com.android.library w projekcie KMP mogło powodować tworzenie mylących nazw zestawów źródeł, np. androidAndroidTest. Ta konwencja nazewnictwa była mniej intuicyjna dla programistów znających standardowe struktury projektów KMP.

Wymagania wstępne

Aby używać wtyczki com.android.kotlin.multiplatform.library, projekt musi być skonfigurowany z tymi minimalnymi wersjami lub nowszymi:

  • Wtyczka Androida do obsługi Gradle (AGP): 8.10.0
  • Wtyczka Kotlin Gradle Plugin (KGP): 2.0.0

Zastosuj wtyczkę Android-KMP do istniejącego modułu

Aby zastosować wtyczkę Android-KMP do istniejącego modułu biblioteki KMP, wykonaj te czynności:

  1. Zadeklaruj wtyczki w katalogu wersji. Otwórz plik TOML katalogu wersji (zwykle gradle/libs.versions.toml) i dodaj sekcję definicji wtyczek:

    # 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. Zastosuj deklarację wtyczki w głównym pliku kompilacji. Otwórz plik build.gradle.kts znajdujący się w katalogu głównym projektu. Dodaj aliasy wtyczek do bloku plugins za pomocą apply false. Dzięki temu aliasy wtyczek są dostępne we wszystkich podprojektach bez stosowania logiki wtyczki do samego projektu głównego.

    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. Zastosuj wtyczkę w pliku kompilacji modułu biblioteki KMP. Otwórz plik build.gradle.kts w module biblioteki KMP i zastosuj wtyczkę u góry pliku w bloku 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. Skonfiguruj platformę docelową KMP na Androida. Skonfiguruj blok Kotlin Multiplatform (kotlin), aby zdefiniować platformę docelową Androida. W bloku kotlin określ miejsce docelowe na Androidzie za pomocą 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. Zastosuj zmiany. Po zastosowaniu wtyczki i skonfigurowaniu bloku kotlin zsynchronizuj projekt Gradle, aby zastosować zmiany.

Migracja ze starszej wtyczki

Ten przewodnik pomoże Ci przeprowadzić migrację ze starszej wtyczki com.android.library do wtyczki com.android.kotlin.multiplatform.library.

1. Deklarowanie zależności

Częstym zadaniem jest deklarowanie zależności dla zestawów źródeł specyficznych dla Androida. Nowa wtyczka wymaga, aby były one wyraźnie umieszczone w bloku sourceSets, w przeciwieństwie do ogólnego bloku dependencies używanego wcześniej.

Android-KMP

Nowa wtyczka zapewnia przejrzystszą strukturę, grupując zależności Androida w androidMain źródłowym zbiorze. Oprócz głównego zestawu źródeł istnieją 2 zestawy źródeł testowych, które są tworzone na żądanie: androidDeviceTest i androidHostTest (więcej informacji znajdziesz w artykule konfigurowanie testów hosta i urządzenia).

// 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")
        }
    }
}

Zestawy źródeł mają odpowiednie kompilacje w języku Kotlin o nazwach main, deviceTesthostTest. Zestawy i kompilacje źródeł można skonfigurować w skrypcie kompilacji w ten sposób:

// build.gradle.kts

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

Starsza wtyczka

W przypadku starej wtyczki zależności specyficzne dla Androida można było deklarować w bloku zależności najwyższego poziomu, co czasami mogło być mylące w module wieloplatformowym.

// 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. Włączanie zasobów Androida

Obsługa zasobów Androida (folderów res) nie jest domyślnie włączona w nowej wtyczce, aby zoptymalizować wydajność kompilacji. Aby z nich korzystać, musisz wyrazić na to zgodę. Ta zmiana pomaga zapewnić, że projekty, które nie wymagają zasobów specyficznych dla Androida, nie będą obciążone związanym z tym narzutem na kompilację.

Android-KMP

Musisz wyraźnie włączyć przetwarzanie zasobów Androida. Zasoby powinny znajdować się w 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

Starsza wtyczka

Przetwarzanie zasobów było domyślnie włączone. Możesz od razu dodać katalog ressrc/main i zacząć dodawać rysunki XML, wartości itp.

// 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. Konfigurowanie testów hosta i urządzenia

Istotną zmianą w nowej wtyczce jest to, że testy po stronie hosta (jednostkowe) i po stronie urządzenia (instrumentalne) na Androidzie są domyślnie wyłączone. Aby utworzyć zestawy i konfiguracje źródeł testowych, musisz wyraźnie wyrazić na to zgodę. Stara wtyczka tworzyła je automatycznie.

Ten model zgody pomaga sprawdzić, czy projekt jest uproszczony i zawiera tylko logikę kompilacji oraz zestawy źródeł, których aktywnie używasz.

Android-KMP

W nowej wtyczce włączasz i konfigurujesz testy w bloku kotlin.android. Dzięki temu konfiguracja jest bardziej jednoznaczna i nie tworzy nieużywanych komponentów testowych. Zbiór źródeł test staje się androidHostTest, a androidTest staje się 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

Starsza wtyczka

Wtyczka com.android.library domyślnie utworzyła zestawy źródeł testandroidTest. Ich działanie konfiguruje się w bloku android, zwykle za pomocą języka 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. Włączanie kompilacji kodu źródłowego w Javie

Jeśli biblioteka KMP musi kompilować źródła Java na potrzeby platformy Android, musisz wyraźnie włączyć tę funkcję za pomocą nowego wtyczki. Pamiętaj, że ta opcja umożliwia kompilację plików Java znajdujących się bezpośrednio w projekcie, a nie w jego zależnościach. Zmienia się też metoda ustawiania wersji JVM kompilatora Java i Kotlin.

Android-KMP

Aby włączyć kompilację w języku Java, musisz wywołać funkcję withJava(). Cel JVM jest teraz konfigurowany bezpośrednio w bloku kotlin { androidLibrary {} }, co zapewnia bardziej ujednoliconą konfigurację. Ustawienie jvmTarget dotyczy zarówno kompilacji w Kotlinie, jak i w Javie na platformę Androida.

// 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

Starsza wtyczka

Kompilacja w języku Java była domyślnie włączona. Docelowa maszyna JVM dla źródeł Java i Kotlin została ustawiona w bloku android za pomocą 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. Interakcja z wariantami kompilacji za pomocą androidComponents

Rozszerzenie androidComponents jest nadal dostępne do programowego korzystania z artefaktów kompilacji. Chociaż większość interfejsu Variant API pozostaje bez zmian, nowy interfejs AndroidKotlinMultiplatformVariant jest bardziej ograniczony, ponieważ wtyczka generuje tylko jeden wariant.

W związku z tym właściwości związane z typami kompilacji i wersjami produktu nie są już dostępne w obiekcie wariantu.

Android-KMP

Blok onVariants iteruje teraz po jednym wariancie. Nadal możesz uzyskiwać dostęp do wspólnych właściwości, takich jak nameartifacts, ale nie do właściwości specyficznych dla typu kompilacji.

// build.gradle.kts

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

Starsza wtyczka

W przypadku wielu wariantów możesz uzyskać dostęp do właściwości specyficznych dla typu kompilacji, aby skonfigurować zadania.

// build.gradle.kts

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

6. Wybieranie wariantów zależności biblioteki Androida

Biblioteka KMP generuje jeden wariant dla Androida. Możesz jednak korzystać ze standardowej biblioteki Androida (com.android.library), która ma wiele wariantów (np. free/paid warianty usługi). Kontrolowanie sposobu, w jaki projekt wybiera wariant z tej zależności, jest powszechnym wymaganiem.

Android-KMP

Nowa wtyczka centralizuje i wyjaśnia tę logikę w bloku kotlin.android.localDependencySelection. Dzięki temu będzie znacznie jaśniejsze, które warianty zależności zewnętrznych zostaną wybrane dla biblioteki KMP z jedną odmianą.

// 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"))
      }
    }
  }
}

Starsza wtyczka

Strategie wyboru zależności zostały skonfigurowane w blokach buildTypes and productFlavors. Często wiązało się to z użyciem missingDimensionStrategy w celu podania domyślnej wersji wymiaru, którego nie było w bibliotece, lub matchingFallbacks w ramach konkretnej wersji w celu zdefiniowania kolejności wyszukiwania.

Więcej informacji o korzystaniu z interfejsu API znajdziesz w sekcji Rozwiązywanie błędów dopasowywania.

Dokumentacja API wtyczek

Nowa wtyczka ma inny interfejs API niż com.android.library. Szczegółowe informacje o nowym języku DSL i interfejsach znajdziesz w dokumentacji interfejsu API: