Abhängigkeiten zwischen Tools und Bibliotheken

Build-Abhängigkeiten sind externe Komponenten, die für die erfolgreiche Erstellung 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.

Jede Abhängigkeit kann selbst andere Abhängigkeiten erfordern. Diese werden als transitive Abhängigkeiten bezeichnet. Sie können die von Ihrer Anwendung verwendeten Gesamtabhängigkeiten schnell erhöhen. Wenn Sie eine Abhängigkeit aktualisieren möchten, unabhängig davon, ob es sich um eine Bibliothek, ein Tool oder das Android SDK handelt, kann dieses Upgrade kaskadiert werden, wodurch viele andere Abhängigkeiten aktualisiert werden.

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 major-Teil ändert, kann dies zu wichtigen Änderungen der API oder des Verhaltens der Bibliothek führen. Dies kann sich auf das Build- oder Anwendungsverhalten auswirken.

Wenn sich die Teile minor (neue Funktionen) oder patch (Fehlerkorrekturen) ändern, teilt Ihnen der Entwickler der Bibliothek mit, dass die Bibliothek weiterhin kompatibel ist und keine Auswirkungen auf Ihre Anwendung haben sollte.

Es ist wichtig, auf solche Änderungen zu achten. Mehrere Tools für das Abhängigkeitsupgrade können Ihnen dabei helfen.

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 deren Beziehungen aufbauen
Abbildung 1. Beziehungen aufbauen

Quellcode

Ihr Quellcode ist Kotlin- oder Java-Code, den Sie in Ihre 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 Annotationen, die zusätzlich verarbeitet werden müssen. 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 Annotationsverarbeitungstools verarbeitet werden.

Bibliotheksabhängigkeiten

Bibliotheken enthalten Bytecode, der als Teil Ihrer Anwendung abgerufen wurde. 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 auch diese vorübergehenden Abhängigkeiten aktualisiert werden können.

Manchmal sind für eine Bibliothek zur Laufzeit (minSdk) oder Kompilierungszeit (compileSdk) Mindestversionen des Android SDK erforderlich. Dies ist erforderlich, 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 Annotationen und einen KSP, der sie in generierten Code umwandelt, um Daten in einer Datenbank abzurufen und zu ändern. Für Jetpack Compose muss das 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 virtuellen Java-Maschinen aus und die 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 zur Verfügung, mit der externe Analysen und Codegenerierung direkt im Compiler ausgeführt werden können. Dabei greift er auf die geparste Codestruktur zu.

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 Gradle-Plug-ins auf den Build anwenden.

Android SDK

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

Jede Version des Android SDK bietet bestimmte Java-APIs, auf die Ihr Quellcode zugreifen kann, sowie eine Unterstützung für die Desugarierung, um diese APIs unter früheren 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. In einem Android-Build sind mehrere JDKs im Spiel. Weitere Informationen finden Sie unter Java-Versionen in Android-Builds.

Gradle-Bereiche

Gradle gruppiert Bibliotheksabhängigkeiten in verschiedene Bereiche (in der Gradle API als Konfigurationen bezeichnet), sodass Sie unterschiedliche Gruppen von Bibliotheksabhängigkeiten angeben können, die in verschiedenen Teilen Ihres Builds verwendet werden. Wahrscheinlich möchten Sie beispielsweise keine Testbibliotheken wie JUnit in Ihre veröffentlichte Anwendung oder Bibliothek aufnehmen, aber beim Erstellen und Ausführen Ihrer Einheitentests. Sie verwenden Bereiche auch, um Symbol- oder Annotationsprozessoren hinzuzufügen und Ihren Code zu analysieren.

AGP definiert beispielsweise die Bereiche implementation und api, mit denen Sie festlegen, ob eine Abhängigkeit Nutzern Ihres Unterprojekts zugänglich gemacht werden soll. Beschreibungen dieser und anderer Bereiche, die in einem Android-Build verwendet werden, finden Sie unter Abhängigkeiten konfigurieren.

Fügen Sie im Block dependencies der Build-Dateien Bibliotheksabhängigkeiten 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)
}

Cool

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

dependencies {
    implementation libs.example.library
}