Gradle to system budowania, automatyzujący kompilację, testowanie i pakowanie aplikacji Android. W przeciwieństwie do Apache Ant czy Maven, obsługuje przyrostowe budowanie i buforowanie wyników. Więcej o możliwościach przeczytasz w oficjalnej dokumentacji Gradle. Od 2013 roku narzędzie jest używane jako standardowy system budowania dla projektów Android w Android Studio.
Najważniejsze
Gradle to narzędzie automatyzacji budowania z otwartym kodem źródłowym napisane w Javie, działające na JVM. Przyjmuje na wejściu kod źródłowy, zależności i zasoby, a na wyjściu daje gotową aplikację — APK lub AAB dla Androida. U podstaw Gradle leży koncepcja skierowanego acyklicznego grafu zadań (DAG), gdzie każde zadanie to atomowa jednostka pracy, a powiązania między nimi określają kolejność wykonania. W przeciwieństwie do Make czy Ant, Gradle nie wymaga ręcznego opisywania sekwencji kroków: wystarczy zadeklarować zależności między zadaniami, a system sam zbuduje optymalną kolejność. Takie podejście czyni Gradle elastycznym i skalowalnym dla projektów dowolnej wielkości.
System używa trzech faz wykonania: inicjalizacji (określenie uczestniczących projektów), konfiguracji (zbudowanie grafu zadań) i wykonania (uruchomienie zadań w odpowiedniej kolejności). Faza konfiguracji to kluczowa różnica Gradle: cały skrypt budowania jest wykonywany przed uruchomieniem zadań, co pozwala dynamicznie zmieniać graf w zależności od warunków. Daje to możliwość, na przykład, dodawania zadań tylko dla określonych wariantów budowania bez powielania kodu. Builder jest napisany w Groovy, ale pliki konfiguracyjne obsługują dwa języki: Groovy DSL i Kotlin DSL.
Wtyczka Android dla Gradle to com.android.application i com.android.library, które dodają do projektu zadania do pracy z narzędziami Android. Kiedy programista uruchamia budowanie, Gradle sekwencyjnie wykonuje dziesiątki zadań: kompilację Kotlin i Java przez javac lub kotlinc, przetwarzanie zasobów przez AAPT2, generowanie R.java, kompilację bajtkodu do DEX przez D8 lub R8, podpisywanie i zipowanie APK. Każde zadanie sprawdza, czy jego dane wejściowe się zmieniły, a jeśli nie — używa zbuforowanego wyniku. Ten mechanizm nazywa się przyrostowym budowaniem i przyspiesza ponowną kompilację o 60–80% w porównaniu z pełną przebudową.
Konfiguracja modułu Android jest określana w bloku android pliku build.gradle.kts. Wewnątrz bloku definiuje się compileSdk, minSdk, targetSdk, wersję aplikacji, podpisy i inne parametry. Gradle automatycznie tworzy dla każdego modułu kilka wariantów budowania — kombinację typu (release, debug) i flavora. Na przykład dla modułu z dwoma flavorami i dwoma typami Gradle generuje cztery zadania: assembleDemoDebug, assembleDemoRelease, assembleFullDebug, assembleFullRelease. Wszystkie te zadania można wykonywać osobno lub uruchomić jednym poleceniem dla wszystkich wariantów naraz.
Każdy projekt Android zawiera dwa poziomy konfiguracji: główny build.gradle.kts (ustawienia dla wszystkich modułów) i modułowy build.gradle.kts (ustawienia dla konkretnego modułu). W głównym pliku deklaruje się wtyczki bez stosowania, repozytoria i wspólne zmienne. W pliku modułowym wtyczki są stosowane do konkretnego modułu i konfigurowane są parametry budowania. Takie podejście pozwala centralnie zarządzać wersjami zależności poprzez katalog wersji lub blok ext.
@Suppress("UnstableApiUsage")
plugins {
id("com.android.application") version "8.2.2"
id("org.jetbrains.kotlin.android") version "1.9.22"
}
android {
namespace = "com.example.myapp"
compileSdk = 34
defaultConfig {
applicationId = "com.example.myapp"
minSdk = 24
targetSdk = 34
versionCode = 1
versionName = "1.0"
}
}Blok dependencies — kolejny krytyczny element build.gradle.kts. W nim wymienia się biblioteki, moduły i zależności plikowe potrzebne aplikacji. Gradle obsługuje kilka konfiguracji zależności: implementation (dostępna tylko bieżącemu modułowi), api (dostępna także zależnym modułom), testImplementation (tylko dla testów), androidTestImplementation (dla testów instrumentalnych) i compileOnly (tylko na etapie kompilacji). Każda konfiguracja zarządza widocznością klas w grafie zależności, co wpływa na czas budowania i rozmiar końcowego artefaktu.
dependencies {
implementation("androidx.core:core-ktx:1.12.0")
implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.7.0")
implementation("androidx.activity:activity-compose:1.8.2")
testImplementation("junit:junit:4.13.2")
androidTestImplementation("androidx.test.ext:junit:1.1.5")
}Build variant to kombinacja build type i product flavor, która określa wersję aplikacji z unikalnymi ustawieniami, kodem i zasobami. Build type (typ budowania) określa parametry pakowania: debug (z debugowaniem i sufiksem .debug) lub release (z obfuskarżą i podpisem). Product flavor (flavor produktowy) określa warianty funkcjonalne: na przykład demo (ograniczona wersja) i full (pełna wersja z dodatkowymi możliwościami). Gradle automatycznie generuje zadania dla każdej kombinacji, co pozwala budować wszystkie wersje jednym poleceniem.
android {
buildTypes {
release {
isMinifyEnabled = true
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
}
debug {
applicationIdSuffix = ".debug"
}
}
flavorDimensions += "version"
productFlavors {
create("demo") {
dimension = "version"
applicationIdSuffix = ".demo"
}
create("full") {
dimension = "version"
applicationIdSuffix = ".full"
}
}
}Każdemu build variant odpowiada oddzielny source set. Gradle używa katalogów src/demo/release, src/full/debug i innych, gdzie przechowywane są unikalne zasoby, manifesty i źródła dla konkretnego wariantu. Wspólny kod pozostaje w src/main. Takie podejście pozwala ponownie wykorzystywać główną logikę i zastępować tylko różniące się części: stringi, ikony, endpointy API lub pliki konfiguracyjne. Source set może nadpisywać dowolne zasoby z main: manifest, drawable, values, a nawet klasy Kotlin. Podczas budowania konkretnego wariantu Gradle łączy pliki z main i odpowiedniego source set, przy czym pliki z wariantu mają priorytet.
Ekosystem wtyczek Gradle obejmuje wszystkie etapy tworzenia aplikacji Android. Oficjalne wtyczki od Google obejmują com.android.application (dla modułu aplikacji), com.android.library (dla modułu bibliotecznego), com.android.test (dla modułów testowych) i wtyczki Kotlin od JetBrains. Wtyczki dodają do projektu nowe zadania, rozszerzają DSL nowymi blokami konfiguracji i podłączają dodatkowe narzędzia. Bez wtyczki com.android.application projekt nie może zbudować APK: ta wtyczka rejestruje wszystkie zadania specyficzne dla Androida i łączy je w graf budowania.
Wtyczki firm trzecich rozwiązują bardziej szczegółowe zadania. Google Services (com.google.gms.google-services) integruje Firebase i Google Play Services, automatycznie podstawiając google-services.json do budowania. Hilt (dagger.hilt.android.plugin) generuje kod do wstrzykiwania zależności na etapie kompilacji. Safe Args (androidx.navigation.safeargs.kotlin) tworzy typowo bezpieczne klasy do nawigacji między fragmentami. Każda wtyczka jest podłączana w głównym build.gradle.kts przez blok plugins i zwykle wymaga minimalnej konfiguracji. Gradle automatycznie rozwiązuje zależności przechodnie między wtyczkami i gwarantuje zgodność wersji poprzez pliki Bom i katalog wersji.
Task (zadanie) to atomowa jednostka pracy w Gradle. Każde zadanie ma dane wejściowe, dane wyjściowe i działanie. Wbudowane zadania dla Androida obejmują assemble (budowanie wszystkich wariantów), lint (sprawdzanie kodu), test (uruchamianie testów jednostkowych) i clean (czyszczenie plików tymczasowych). Programista może dodawać własne zadania za pomocą Groovy lub Kotlin DSL. Niestandardowe zadania są przydatne do automatyzacji rutynowych operacji: generowania raportów, kopiowania artefaktów, wdrażania na urządzenia testowe lub integracji z systemami CI.
tasks.register("printBuildInfo") {
description = "Wyświetla informacje o budowaniu"
group = "custom"
doLast {
println("Build variant: ${project.name}")
println("Version: ${android.defaultConfig.versionName}")
}
}Każde zadanie może zależeć od innych zadań poprzez mechanizm dependsOn. Jeśli zadanie A zależy od zadania B, Gradle gwarantuje, że B wykona się przed A. System nie wymaga ręcznego wskazywania kolejności dla każdej pary — wystarczy zadeklarować zależności, a Gradle zbuduje skierowany graf, zoptymalizowany do równoległego wykonywania niezależnych zadań. Wbudowane zadania wtyczki Android są już ze sobą powiązane: lint zależy od kompilacji, test zależy od assemble, assembleDebug zależy od compileDebugKotlin. Programista może wbudować swoje zadania w dowolny węzeł grafu, używając dependsOn, mustRunAfter lub shouldRunAfter.
Jednym z częstych problemów jest konflikt wersji zależności, kiedy dwie biblioteki wymagają różnych wersji tej samej zależności przechodniej. Gradle zgłasza błąd konfliktu, ale nie zawsze proponuje automatyczne rozwiązanie. Do diagnozy użyj polecenia ./gradlew :app:dependencies, które wyświetla pełne drzewo zależności. Zaleca się wymuszenie wersji biblioteki konfliktowej poprzez blok resolutionStrategy. Innym częstym scenariuszem jest wolne budowanie z powodu braku przyrostowego przetwarzania. Sprawdź, czy wszystkie wtyczki są zaktualizowane, Gradle Daemon jest włączony (org.gradle.daemon=true) i w gradle.properties ustawiono wystarczającą ilość pamięci: org.gradle.jvmargs=-Xmx4096m.
Problemy z buforowaniem występują po aktualizacji zależności: Gradle może używać nieaktualnego bufora i budowanie kończy się błędem. Rozwiązanie — uruchom budowanie z flagą --refresh-dependencies lub wyczyść bufor ręcznie przez ./gradlew cleanBuildCache. Trzecim co do częstotliwości błędem jest niezgodność wersji Android Gradle Plugin (AGP) i Gradle. Każda wersja AGP wymaga określonej minimalnej wersji Gradle. Tabela zgodności jest publikowana na developer.android.com. Jeśli wersje są niezgodne, Gradle kończy się błędem na etapie konfiguracji z komunikatem o minimalnej wymaganej wersji. Zawsze sprawdzaj, czy wersja Gradle wrapper odpowiada wymaganiom AGP.
Często zadawane pytania
Gradle to program-automatyzator budowania projektów. Bierze twój kod źródłowy w Kotlin lub Java, podłącza biblioteki z internetu, kompiluje wszystko do bajtkodu i pakuje do APK. Działa na JVM i używa deklaratywnych skryptów zamiast ręcznych instrukcji. Programista musi tylko opisać reguły, a resztę Gradle robi sam.
Build.gradle jest pisany w Groovy — dynamicznym języku z elastyczną składnią i mniejszą ścisłością. Build.gradle.kts używa Kotlin DSL: ścisłe typowanie, autouzupełnianie w Android Studio i sprawdzanie błędów na etapie kompilacji. Google zaleca Kotlin DSL dla wszystkich nowych projektów. Pliki Groovy są łatwiejsze do migracji, ale pliki Kotlin są bardziej niezawodne w utrzymaniu.
Włącz Gradle Daemon (org.gradle.daemon=true) i równoległe budowanie (org.gradle.parallel=true). Zwiększ pamięć JVM do 4–8 GB przez org.gradle.jvmargs. Używaj konfiguracji projektów na żądanie (org.gradle.configureondemand=true). Dla projektów Android skonfiguruj buforowanie zadań i budowanie tylko dla potrzebnego ABI. W Android Studio uruchom Build Analyzer, aby znaleźć wąskie gardła.
Build variant — to kombinacja build type (na przykład debug lub release) i product flavor (na przykład demo lub full). Każdy wariant może mieć swoją nazwę pakietu, wersję, zasoby i pliki źródłowe. Gradle automatycznie tworzy osobne zadanie budowania dla każdego wariantu. Pozwala to budować kilka wersji aplikacji z jednego projektu.
Zależności dodaje się w bloku dependencies pliku build.gradle.kts. Format zapisu: configuration("group:artifact:version"). Na przykład implementation("androidx.core:core-ktx:1.12.0"). Do testów używaj testImplementation, do testów instrumentalnych — androidTestImplementation. Wersje wygodnie wynieść do osobnego katalogu wersji (version catalog) poprzez plik libs.versions.toml.
Podsumowanie
Opracujemy aplikację mobilną pod klucz
IT Sectr tworzy aplikacje na iOS i Androida dla startupów i firm od 2017 roku. Doradzimy Ci i zaproponujemy najlepsze rozwiązanie.
Przeczytaj również