G8

d8 è uno strumento a riga di comando che Android Studio e il plug-in Android per Gradle utilizzano per compilare il bytecode Java del tuo progetto in bytecode DEX che viene eseguito sui dispositivi Android. d8 ti consente di utilizzare le funzionalità del linguaggio Java 8 nel codice della tua app.

d8 è anche incluso come strumento autonomo in Android Build Tools 28.0.1 e versioni successive: android_sdk/build-tools/version/.

Uso generale

d8 richiede solo un percorso del bytecode Java compilato che vuoi convertire in bytecode DEX. Ecco alcuni esempi:

d8 MyProject/app/build/intermediates/classes/debug/*/*.class

Il bytecode di input può essere qualsiasi combinazione di file o container *.class, ad esempio file JAR, APK o ZIP. Puoi anche includere file DEX per d8 da unire nell'output DEX, il che è utile quando includi l'output di una build incrementale.

Per impostazione predefinita, d8 compila il bytecode Java in file DEX ottimizzati e include informazioni di debug che puoi utilizzare per eseguire il debug del codice durante il runtime. Tuttavia, puoi includere flag facoltativi per eseguire una build incrementale, specificare le classi da compilare nel file DEX principale e specificare i percorsi alle risorse aggiuntive necessarie per utilizzare le funzionalità del linguaggio Java 8.

d8 path-to-input-files [options]

La tabella seguente descrive i flag facoltativi che puoi utilizzare con d8:

Opzione Descrizione
--debug

Compila il bytecode DEX per includere informazioni di debug, ad esempio le tabelle dei simboli di debug.

Questa opzione è abilitata per impostazione predefinita. Per includere informazioni di debug nel bytecode DEX, d8 prevede che il bytecode Java di input includa queste informazioni. Ad esempio, se utilizzi javac per compilare il codice, devi passare il flag -g per includere le informazioni di debug nel bytecode Java di output.

Quando compili file DEX per la versione di release dell'app o della libreria, utilizza invece il flag --release.

--release

Compila il bytecode DEX senza informazioni di debug. Tuttavia, d8 include alcune informazioni che vengono utilizzate durante la generazione di analisi dello stack e delle eccezioni di logging.

Passa questo flag quando compili il bytecode per una release pubblica.

--output path

Specifica il percorso desiderato per l'output DEX. Per impostazione predefinita, d8 restituisce i file DEX nella directory di lavoro attuale.

Se specifichi il percorso e il nome di un file ZIP o JAR, d8 crea il file specificato e include i file DEX di output. Se specifichi il percorso di una directory esistente, d8 restituisce i file DEX in quella directory.

--lib android_sdk/platforms/api-level/android.jar Specifica il percorso dell'elemento android.jar del tuo SDK Android. Questo flag è obbligatorio per la compilazione di bytecode che utilizzano le caratteristiche del linguaggio Java 8.
--classpath path Specifica le risorse del percorso della classe che d8 potrebbe richiedere per compilare i file DEX del progetto. In particolare, d8 richiede che specifichi determinate risorse durante la compilazione di bytecode che utilizzano le funzionalità del linguaggio Java 8.
--min-api number Specifica il livello API minimo che desideri sia supportato dai file DEX di output.
--intermediate Passa questo flag per far sapere a d8 che non stai compilando l'intero set di bytecode Java del tuo progetto. Questo flag è utile quando si eseguono build incrementali. Anziché compilare i file DEX ottimizzati che prevedi di eseguire su un dispositivo, d8 crea file DEX intermedi e li archivia nell'output o nel percorso predefinito specificato.

Quando vuoi compilare i file DEX che intendi eseguire su un dispositivo, escludi questo flag e specifica il percorso delle classi DEX intermedie come input.

--file-per-class

Compila ogni classe in file DEX separati.

L'abilitazione di questo flag consente di eseguire build più incrementali ricompilando solo le classi che sono state modificate. Durante l'esecuzione di build incrementali utilizzando il plug-in Android per Gradle, questa ottimizzazione è abilitata per impostazione predefinita.

Non puoi utilizzare questo flag e specificare anche --main-dex-list.

--no-desugaring Disattiva le funzionalità del linguaggio Java 8. Utilizza questo flag solo se non intendi compilare bytecode Java che utilizzi le caratteristiche del linguaggio Java 8.
--main-dex-list path

Specifica un file di testo che elenca le classi che d8 deve includere nel file DEX principale, che in genere è denominato classes.dex. Se non specifichi un elenco di classi utilizzando questo flag, d8 non garantisce quali classi sono incluse nel file DEX principale.

Poiché il sistema Android carica per primo il file DEX principale all'avvio dell'app, puoi utilizzare questo flag per assegnare la priorità a determinate classi all'avvio, compilandole nel file DEX principale. Questo è particolarmente utile quando si supporta il multidex legacy, perché solo le classi nel file DEX principale sono disponibili in fase di runtime fino al caricamento della libreria multidex legacy.

Tieni presente che ogni file DEX deve comunque soddisfare il limite di riferimento di 64.000. Quindi, non specificare troppe classi per il file DEX principale, altrimenti riceverai un errore di compilazione. Per impostazione predefinita, quando specifichi classi utilizzando --main-dex-list, d8 include solo quelle classi nel file DEX principale. In questo modo, è più facile eseguire il debug dei problemi relativi alle classi mancanti nel file DEX principale. Se specifichi la modalità --release, d8 cerca di ridurre il numero di file DEX pacchettizzati nella versione di release dell'app includendo il maggior numero possibile di altre classi nel file DEX principale finché non viene raggiunto il limite di 64.000.

Non puoi utilizzare questo flag e specificare anche --file-per-class.

--pg-map file Utilizza file come file di mapping per la distribuzione.
--file-per-class-file

Genera un file DEX separato per ogni file .class di input.

Mantieni le classi sintetiche con la classe di origine.

--desugared-lib file

Specifica la configurazione di una libreria di destinazione.

file è un file di configurazione della libreria desugarato in formato JSON.

--main-dex-rules file ProGuard mantiene le regole per le classi da inserire nel file DEX principale.
--main-dex-list-output file Output dell'elenco DEX principale risultante in file.

--force-enable-assertions [:class_or_package_name...]

--force-ea [:class_or_package_name...]

Attiva forzatamente il codice di asserzione generato da javac.

--force-disable-assertions [:class_or_package_name...]

--force-da [:class_or_package_name...]

Disattiva forzatamente il codice di asserzione generato da javac. Questa è la modalità di gestione predefinita del codice di asserzione javac durante la generazione di file DEX.

--force-passthrough-assertions [:class_or_package_name...]

--force-pa [:class_or_package_name...]

Non modificare il codice dell'asserzione generato da javac. Questa è la gestione predefinita del codice di asserzione javac durante la generazione di file class.

--force-assertions-handler:handler method [:class_or_package_name...]

--force-ah:handler method [:class_or_package_name...]

Modifica il codice dell'asserzione generato da javac e kotlinc per richiamare il metodo handler method con ogni errore di asserzione anziché generarlo. handler method viene specificato come nome di classe seguito da un punto e dal nome del metodo. Il metodo del gestore deve utilizzare un singolo argomento di tipo java.lang.Throwable e avere un tipo restituito void.
--thread-count number of threads Specifica il numero di thread da utilizzare per la compilazione. Se non specificato, il numero si basa su un'euristica, tenendo in considerazione il numero di core.
--map-diagnostics[ :type] from-level to-level La diagnostica della mappa di type (valore predefinito qualsiasi) è segnalata come from-level a to-level, dove from-level e to-level sono uno dei seguenti valori: "info", "avviso" o "errore" e facoltativo type è il nome di tipo Java semplice o completo di una diagnostica. Se type non è specificato, tutta la diagnostica in from-level viene mappata. Tieni presente che non è possibile mappare gli errori irreversibili del compilatore.
--version Stampa la versione di d8 che stai utilizzando attualmente.
--help Stampa il testo della guida per l'utilizzo di d8.

Esegui build incrementali

Per migliorare la velocità della build in fase di sviluppo, ad esempio per le build di integrazione continua, indica a d8 di compilare solo un sottoinsieme del bytecode Java del tuo progetto. Ad esempio, se abiliti la dexing per classe, puoi ricompilare solo le classi che hai modificato dalla build precedente.

Il seguente comando esegue una build incrementale di alcune classi e consente il dexing per classe. Il comando specifica anche una directory di output per la build incrementale.

d8 MainActivity.class R.class --intermediate --file-per-class --output ~/build/intermediate/dex

Quando d8 esegue una build incrementale, archivia informazioni aggiuntive nell'output DEX. In seguito, d8 utilizza queste informazioni per elaborare correttamente l'opzione --main-dex-list e per unire i file DEX durante una build completa dell'app.

Ad esempio, durante l'elaborazione di classi lambda Java 8, d8 tiene traccia di quali classi lambda vengono create per ogni classe di input. Durante una build completa, quando d8 include una classe nel file DEX principale, consulta i metadati per assicurarsi che tutte le classi lambda create per quella classe siano incluse anche nel file DEX principale.

Se hai già compilato tutti i bytecode del progetto in file DEX in più build incrementali, esegui una build completa passando la directory dei file DEX intermedi a d8, come mostrato nel comando seguente. Inoltre, puoi specificare le classi che vuoi che d8 compili nel file DEX principale utilizzando --main-dex-list. Poiché l'input è un insieme di file già compilati in bytecode DEX, questa build dovrebbe essere completata più velocemente di una build pulita.

d8 ~/build/intermediate/dex --release --main-dex-list ~/build/classes.txt --output ~/build/release/dex

Compilare bytecode che utilizza le caratteristiche del linguaggio Java 8

d8 consente di utilizzare le funzionalità del linguaggio Java 8 nel codice tramite un processo di compilazione chiamato desugaring. Il desugaring converte queste utili funzionalità linguistiche in bytecode che possono essere eseguite sulla piattaforma Android.

Android Studio e il plug-in Android per Gradle includono risorse classpath che d8 richiede per attivare il deprovisioning. Tuttavia, quando utilizzi d8 dalla riga di comando, devi includerli manualmente.

Una di queste risorse è il android.jar dell'SDK Android di destinazione. Questa risorsa include un insieme di API della piattaforma Android. Specifica il percorso utilizzando il flag --lib.

Un'altra risorsa è l'insieme di bytecode Java compilato nel progetto che attualmente non stai compilando in bytecode DEX, ma che devi compilare altre classi in bytecode DEX.

Ad esempio, se il codice utilizza metodi di interfaccia predefiniti e statici, che sono una funzionalità del linguaggio Java 8, devi utilizzare questo flag per specificare il percorso di tutto il bytecode Java del tuo progetto, anche se non intendi compilare tutti i bytecode in bytecode DEX. Il motivo è che d8 richiede queste informazioni per comprendere il codice del progetto e risolvere le chiamate ai metodi dell'interfaccia.

Il seguente esempio di codice esegue una build incrementale di una classe che accede a un metodo di interfaccia predefinito:

d8 MainActivity.class --intermediate --file-per-class --output ~/build/intermediate/dex
--lib android_sdk/platforms/api-level/android.jar
--classpath ~/build/javac/debug