Abhängigkeiten zwischen Tools und Bibliotheken

Buildabhängigkeiten sind externe Komponenten, die für den erfolgreichen Build Ihres Projekts erforderlich sind. Ein Build kann von Bibliotheken, Plug-ins, Unterprojekten, dem Android SDK, Tools wie Kotlin- und Java-Compilern, Entwicklungsumgebungen wie Android Studio und Gradle selbst abhängen.

Für jede Abhängigkeit können wiederum andere Abhängigkeiten erforderlich sein. Wir nennen diese transitive Abhängigkeiten. Sie können die Gesamtzahl der Abhängigkeiten, die von Ihrer Anwendung verwendet werden, schnell erhöhen. Wenn Sie eine Abhängigkeit aktualisieren möchten, z. B. eine Bibliothek, ein Tool oder das Android SDK, kann dieses Upgrade kaskadieren und viele andere Abhängigkeiten aktualisieren.

Oft ist das kein Problem, da viele Bibliotheken dem semantischen Versionierungsschema folgen. Diese Bibliotheken beschränken die Arten von Änderungen, die sie vornehmen, um für die Kompatibilität mit niedrigeren Versionen zu sorgen.

Die semantische Versionsverwaltung folgt dem Format major.minor.patch. In der Versionsnummer 4.8.3 steht 4 beispielsweise für die major-Version, 8 für die minor-Version und 3 für die patch-Nummer. Wenn sich der Teil major ändert, kann es zu gravierenden Änderungen an der API oder dem Verhalten der Bibliothek kommen. Dies kann sich auf das Verhalten Ihres Builds oder Ihrer Anwendung auswirken.

Wenn sich die Teile minor (neue Funktionen) oder patch (Fehlerkorrekturen) ändern, geben die Bibliotheksentwickler an, dass die Bibliothek weiterhin kompatibel ist und sich nicht auf Ihre Anwendung auswirken sollte.

Beziehungen in Ihrem Build

Android-Builds enthalten Beziehungen zwischen:

  • Quellcode: Code und Ressourcen, über die Sie die Kontrolle haben
  • Bibliotheksabhängigkeiten: Externe Bibliotheken oder Module, die beim Erstellen in Ihr Projekt und Ihre untergeordneten Projekte aufgenommen werden
  • Tools: Compiler, Plug-ins und SDKs, die Ihre Quelle in eine Anwendung oder Bibliothek umwandeln
Abhängigkeiten und ihre Beziehungen aufbauen
Abbildung 1: Beziehungen aufbauen

Quellcode

Der Quellcode ist Kotlin- oder Java-Code, den Sie in Ihrer Anwendung oder Bibliothek schreiben. Weitere Informationen zur Verwendung von C++ finden Sie unter Android NDK.

Der Quellcode ist von Bibliotheken (einschließlich Kotlin- und Java-Laufzeitbibliotheken) und dem Android SDK abhängig und erfordert den entsprechenden Kotlin- oder Java-Compiler.

Einige Quellcodes enthalten Anmerkungen, die eine zusätzliche Verarbeitung erfordern. Wenn Sie beispielsweise Jetpack Compose-Code schreiben, fügen Sie Anmerkungen wie @Composable hinzu, die vom Compose Kotlin-Compiler-Plug-in verarbeitet werden müssen. Andere Anmerkungen können von einem Kotlin Symbol Processor (KSP) oder separaten Tools zur Anmerkungsverarbeitung verarbeitet werden.

Bibliotheksabhängigkeiten

Bibliotheken enthalten Bytecode, der im Rahmen Ihrer Anwendung abgerufen wird. Dies kann eine Java-JAR-Datei, eine Android-Bibliothek (AAR) oder ein Unterprojekt in Ihrem Build sein. Viele Bibliotheken folgen der semantischen Versionsverwaltung. So können Sie besser nachvollziehen, ob sie nach einem Upgrade weiterhin kompatibel sind oder nicht.

Bibliotheken können zur Wiederverwendung von anderen Bibliotheken abhängig sein, was als transitive Abhängigkeit bezeichnet wird. Dadurch werden die Abhängigkeiten reduziert, die Sie explizit verwalten müssen. Sie geben die Abhängigkeiten an, die Sie direkt verwenden, und Gradle ruft sie zusammen mit diesen transitiven Abhängigkeiten ab. Beachten Sie, dass beim Upgrade Ihrer direkten Abhängigkeiten möglicherweise auch diese transitiven Abhängigkeiten aktualisiert werden.

Manchmal sind für eine Bibliothek Mindestversionen des Android SDK zur Laufzeit (minSdk) oder zur Kompilierungszeit (compileSdk) erforderlich. Das ist notwendig, wenn eine Bibliothek Funktionen verwendet, die im Android SDK oder in den bereitgestellten JDK-APIs enthalten sind. Die effektive minSdk Ihrer Anwendung ist die höchste minSdk, die von Ihrer Anwendung und allen direkten und transitiven Bibliotheksabhängigkeiten angefordert wird.

Für die Verwendung einiger Bibliotheken ist möglicherweise ein bestimmtes Gradle-Plug-in erforderlich. Diese Hilfs-Plug-ins installieren häufig Kotlin-Symbolprozessoren oder andere Anmerkungs-Prozessoren, die Code generieren oder die Kompilierung Ihrer Quelle ändern, um die Verwendung von Bibliotheksfunktionen zu unterstützen. Jetpack Room enthält beispielsweise Anmerkungen und einen KSP, der sie in generierten Code umwandelt, um Daten in einer Datenbank abzurufen und zu ändern. Für Jetpack Compose muss das Compose-Compiler-Plug-in annotierte Funktionen ändern, um zu verwalten, wie und wann diese Funktion noch einmal ausgeführt wird.

Tools

Gradle

Gradle ist das Build-Tool, das Ihre Build-Dateien liest und Ihre Anwendung oder Bibliothek generiert. Außerdem stellt es eine API für Plug-ins bereit, um die Funktionen zu erweitern. Gradle führt mehrere Prozesse auf einer oder mehreren Java-VMs aus und seine Java-Plug-ins rufen die Java-Tools im JDK auf.

Gradle-Plug-ins

Gradle-Plug-ins erweitern Gradle durch das Definieren neuer Aufgaben und Konfigurationen. Wenn Sie ein Plug-in auf Ihren Build anwenden, werden bestimmte Build-Funktionen aktiviert, die in Ihren Build-Scripts als Daten konfiguriert sind. Das wichtigste Gradle-Plug-in für Android-Builds ist das Android Gradle Plugin (AGP).

Compiler

Der Kotlin- oder Java-Compiler wandelt Ihren Quellcode in ausführbaren Bytecode um. Der Kotlin-Compiler stellt eine Plug-in-API bereit, mit der externe Analysen und die Codegenerierung direkt im Compiler ausgeführt werden können, wobei auf die geparste Codestruktur zugegriffen wird.

Compiler-Plug-ins

Compiler-Plug-ins führen die Analyse und Codegenerierung innerhalb des Kotlin-Compilers aus, während der Kotlin-Compiler Ihren Code analysiert. Sie werden installiert, wenn Sie die zugehörigen Gradle-Plug-ins auf den Build anwenden.

Android SDK

Das Android SDK enthält die Android-Plattform und Java APIs für eine bestimmte Android-Version sowie die entsprechenden Tools. Mit diesen Tools können Sie das SDK verwalten, Ihre Anwendungen erstellen und mit Android-Geräten kommunizieren und sie emulieren.

Jede Version des Android SDK bietet bestimmte Java APIs, auf die Ihr Quellcode zugreifen kann, und Desugaring-Unterstützung, um diese APIs in älteren Android-Versionen zu verwenden.

JDK

Das Java Development Kit, das Java-Bibliotheken und ausführbare Dateien zum Kompilieren von Java-Quellcode und Ausführen von Java-Anwendungen enthält. Bei einem Android-Build werden mehrere JDKs verwendet. Weitere Informationen finden Sie unter Java-Versionen in Android-Builds.

Gradle-Bereiche

Gradle gruppiert Bibliotheksabhängigkeiten in verschiedene Bereiche (in der Gradle API Konfigurationen genannt). So können Sie verschiedene Bibliotheksabhängigkeiten für verschiedene Teile Ihres Builds angeben. Beispielsweise sollten Sie Testbibliotheken wie JUnit nicht in Ihre veröffentlichte Anwendung oder Bibliothek aufnehmen, aber beim Erstellen und Ausführen Ihrer Unit-Tests benötigen Sie sie. Außerdem können Sie mit Bereichen Symbol- oder Anmerkungs-Prozessoren hinzufügen, um Ihren Code zu analysieren.

AGP definiert beispielsweise die Bereiche implementation und api, mit denen Sie angeben können, ob eine Abhängigkeit für Nutzer Ihres untergeordneten Projekts freigegeben werden soll. Beschreibungen dieser und anderer Bereiche, die in einem Android-Build verwendet werden, finden Sie unter Abhängigkeiten konfigurieren.

Fügen Sie Bibliotheksabhängigkeiten im dependencies-Block Ihrer Build-Dateien entweder als group:artifact:version-Strings hinzu:

Kotlin

// In a module-level build script
// explicit dependency strings ("group:artifact:version")
dependencies {
    implementation("com.example:library1:1.2.3")
    api("com.example:library2:1.1.1")
}

Groovy

// In a module-level build script
// explicit dependency strings ("group:artifact:version")
dependencies {
    implementation 'com.example:library1:1.2.3'
    api 'com.example:library2:1.1.1'
}

oder in einem Versionskatalog:

# Version catalog - gradle/libs.versions.toml
[versions]
exampleLib = "1.2.3"
examplePlugin = "2.3.4"

[libraries]
example-library = { group = "com.example", name = "library", version.ref = "exampleLib" }

[plugins]
example-plugin = { id = "com.example.plugin", version.ref = "examplePlugin" }

und geben Sie die generierten Variablen in Ihren Build-Dateien an:

Kotlin

// In a module-level build script
// Using a version catalog
plugins {
    alias(libs.plugins.example.plugin)
}

dependencies {
    implementation(libs.example.library)
}

Groovy

// In a module-level build script
// Using a version catalog
plugins {
    alias(libs.plugins.example.plugin)
}

dependencies {
    implementation libs.example.library
}