Panoramica della creazione di Gradle

In genere, le applicazioni Android vengono create utilizzando il sistema di compilazione Gradle. Prima di esaminare i dettagli su come configurare la compilazione, esploreremo i concetti alla base della compilazione in modo da poter vedere il sistema nel suo complesso.

Che cos'è una build?

Un sistema di compilazione trasforma il codice sorgente in un'applicazione eseguibile. Le build spesso richiedono più strumenti per analizzare, compilare, collegare e pacchettizzare l'applicazione o la libreria. Gradle utilizza un approccio basato su attività per organizzare ed eseguire questi comandi.

Le attività incapsulano i comandi che traducono gli input in output. I plug-in definiscono le attività e la relativa configurazione. L'applicazione di un plug-in alla compilazione registra le relative attività e le collega utilizzando gli input e gli output. Ad esempio, se applichi il plug-in Android Gradle (AGP) al tuo file di build, verranno registrate tutte le attività necessarie per creare un APK o una libreria Android. Il plug-in java-library consente di creare un jar dal codice sorgente Java. Esistono plug-in simili per Kotlin e per altri linguaggi, ma altri plug-in sono pensati per estendere i plug-in. Ad esempio, il plug-in protobuf ha lo scopo di aggiungere il supporto protobuf a plug-in esistenti come AGP o java-library.

Gradle preferisce le convenzioni alla configurazione, pertanto i plug-in sono dotati di buoni valori predefiniti, ma puoi configurare ulteriormente la compilazione tramite un linguaggio specifico per il dominio (DSL) dichiarativo. La rete DSL è progettata in modo da consentirti di specificare cosa creare, anziché come crearlo. La logica dei plug-in gestisce il "come". Questa configurazione è specificata in diversi file di build nel tuo progetto (e progetti secondari).

Gli input delle attività possono essere file e directory, nonché altre informazioni codificate come tipi Java (interi, stringhe o classi personalizzate). Gli output possono essere solo directory o file, in quanto devono essere scritti sul disco. Se colleghi l'output di un'attività a un altro input, le attività vengono collegate tra loro in modo che una debba essere eseguita prima dell'altra.

Sebbene Gradle supporti la scrittura di dichiarazioni di codice e attività arbitrari nei file di build, questo può rendere più difficile per gli strumenti comprendere la build e gestirla. Ad esempio, puoi scrivere test per il codice all'interno dei plug-in, ma non nei file di build. Devi invece limitare le dichiarazioni della logica di compilazione e delle attività ai plug-in (definiti da te o da altri) e dichiarare come vuoi utilizzare questa logica nei file di compilazione.

Cosa succede quando viene eseguita una compilazione Gradle?

Le build di Gradle vengono eseguite in tre fasi. Ognuna di queste fasi esegue diverse parti di codice definite nei file di build.

  • L'inizializzazione determina i progetti e i sottoprogetti inclusi nella build e imposta classpath contenenti i file di build e i plug-in applicati. Questa fase si concentra su un file di impostazioni in cui dichiari i progetti da compilare e le posizioni da cui recuperare plug-in e librerie.
  • Configurazione registra le attività per ogni progetto ed esegue il file di compilazione per applicare la specifica di compilazione dell'utente. È importante capire che il codice di configurazione non avrà accesso ai dati o ai file prodotti durante l'esecuzione.
  • L'esecuzione esegue effettivamente la "creazione" della tua applicazione. L'output della configurazione è un Directed Acyclic Graph (DAG) di attività, che rappresenta tutti i passaggi di build richiesti richiesti dall'utente (le attività fornite sulla riga di comando o come predefiniti nei file di build). Questo grafico rappresenta la relazione tra le attività, esplicita nella dichiarazione di un'attività o basata sui suoi input e output. Se un'attività ha un input che è l'output di un'altra attività, deve essere eseguita dopo l'altra. Questa fase esegue attività non aggiornate nell'ordine definito nel grafico. Se gli input di un'attività non sono cambiati dall'ultima esecuzione, Gradle la ignorerà.

Per maggiori informazioni, consulta il ciclo di vita della build di Gradle.

DSL di configurazione

Gradle utilizza un linguaggio specifico del dominio (DSL) per configurare le build. Questo approccio dichiarativo si concentra sulla specifica dei dati anziché sulla scrittura di istruzioni dettagliate (imperative). Puoi scrivere i file di build con Kotlin o Groovy, ma ti consigliamo vivamente di usare Kotlin.

I DSL cercano di facilitare a tutti, esperti di dominio e programmatori, contribuire a un progetto, definendo un linguaggio ridotto che rappresenta i dati in modo più naturale. I plug-in Gradle possono estendere il DSL per configurare i dati di cui hanno bisogno per le loro attività.

Ad esempio, la configurazione della parte Android della build potrebbe avere il seguente aspetto:

Kotlin

android {
    namespace = "com.example.app"
    compileSdk = 34
    // ...

    defaultConfig {
        applicationId = "com.example.app"
        minSdk = 34
        // ...
    }
}

Alla moda

android {
    namespace 'com.example.myapplication'
    compileSdk 34
    // ...

    defaultConfig {
        applicationId "com.example.myapplication"
        minSdk 24
        // ...
    }
}

Dietro le quinte, il codice DSL è simile a questo:

fun Project.android(configure: ApplicationExtension.() -> Unit) {
    ...
}

interface ApplicationExtension {
    var compileSdk: Int
    var namespace: String?

    val defaultConfig: DefaultConfig

    fun defaultConfig(configure: DefaultConfig.() -> Unit) {
        ...
    }
}

Ogni blocco nel DSL è rappresentato da una funzione che accetta un lambda per configurarlo e una proprietà con lo stesso nome per accedervi. In questo modo, il codice nei file di compilazione sembra più una specifica dei dati.

Dipendenze esterne

Il sistema di compilazione Maven ha introdotto una specifica per le dipendenze, nonché un sistema di archiviazione e gestione. Le librerie vengono archiviate in repository (server o directory), con metadati che includono la loro versione e le dipendenze da altre librerie. Specifichi i repository da cercare, le versioni delle dipendenze che vuoi utilizzare e il sistema di compilazione le scarica durante la compilazione.

Gli artefatti Maven sono identificati dal nome del gruppo (azienda, sviluppatore e così via), nome dell'artefatto (il nome della libreria) e versione dell'artefatto. In genere viene rappresentato come group:artifact:version.

Questo approccio migliora notevolmente la gestione delle build. Spesso questi repository vengono chiamati "repository Maven", ma il tutto dipende dal modo in cui gli elementi vengono pacchettizzati e pubblicati. Questi repository e metadati sono stati riutilizzati in diversi sistemi di build, incluso Gradle (e Gradle può pubblicare in questi repository). I repository pubblici consentono la condivisione per tutti e i repository aziendali mantengono le dipendenze interne in-house.

Puoi anche modularizzare il progetto in sottoprogetti (chiamati anche "moduli" in Android Studio), che possono essere utilizzati anche come dipendenze. Ogni sottoprogetto produce output (ad esempio jar) che possono essere utilizzati dai sottoprogetti o dal tuo progetto di primo livello. Ciò può migliorare i tempi di compilazione isolando le parti che devono essere ricreate, oltre a separare meglio le responsabilità nell'applicazione.

Approfondiremo come specificare le dipendenze in Aggiungere dipendenze nelle build.

Creare varianti di compilazione

Quando crei un'applicazione per Android, in genere vuoi creare più varianti. Le varianti contengono codice diverso o sono create con opzioni diverse e sono composte da tipi di build e versioni di prodotto.

I tipi di build variano in base alle opzioni di build dichiarate. Per impostazione predefinita, AGP configura i tipi di build "release" e "debug", ma puoi modificarli e aggiungerne altri (ad esempio per la gestione temporanea o i test interni).

Una build di debug non riduce al minimo o offusca l'applicazione, accelerandone la compilazione e preservando tutti i simboli così come sono. Inoltre, contrassegna l'applicazione come "debuggabile", la firma con una chiave di debug generica e consente l'accesso ai file dell'applicazione installati sul dispositivo. In questo modo, è possibile esplorare i dati salvati in file e database durante l'esecuzione dell'applicazione.

Una build di release ottimizza l'applicazione, la firma con la chiave di rilascio e protegge i file dell'applicazione installata.

Utilizzando i flavor del prodotto, puoi modificare il codice sorgente incluso e le varianti di dipendenza per l'applicazione. Ad esempio, potresti voler creare versioni "demo" e "complete" per la tua applicazione o magari versioni "senza costi" e "a pagamento". Scrivi la tua origine comune in una directory set di origine "principale" ed esegui l'override o aggiungi l'origine in un set di origini denominato come la versione.

AGP crea varianti per ogni combinazione di tipo di build e versione del prodotto. Se non definisci i gusti, le varianti vengono denominate in base ai tipi di build. Se li definisci entrambi, la variante viene denominata <flavor><Buildtype>. Ad esempio, con i tipi di compilazione release e debug e i gusti demo e full, AGP creerà le varianti:

  • demoRelease
  • demoDebug
  • fullRelease
  • fullDebug

Passaggi successivi

Ora che hai visto i concetti di base della build, dai un'occhiata alla struttura della build di Android nel tuo progetto.