Android
Gradle per Android
Ricerca…
introduzione
Gradle è un sistema di build basato su JVM che consente agli sviluppatori di scrivere script di alto livello che possono essere utilizzati per automatizzare il processo di compilazione e produzione di applicazioni. È un sistema flessibile basato su plugin, che consente di automatizzare vari aspetti del processo di creazione; inclusi la compilazione e la firma di un file .jar
, il download e la gestione di dipendenze esterne, l'inserimento di campi AndroidManifest
o l'utilizzo di versioni specifiche dell'SDK.
Sintassi
apply plugin
: i plugin che dovrebbero essere usati normalmente solo'com.android.application'
o'com.android.library'
.android
: la configurazione principale della tua app-
compileSdkVersion
: la versione di compilazione dell'SDK -
buildToolsVersion
: la versione degli strumenti di compilazione -
defaultConfig
: le impostazioni predefinite che possono essere sovrascritte da sapori e tipi di build-
applicationId
: l'ID dell'applicazione che usi, ad esempio, nel Play Store, quasi uguale al nome del tuo pacchetto -
minSdkVersion
: la versione minima richiesta dell'SDK -
targetSdkVersion
: la versione dell'SDK con cui si compila (dovrebbe essere sempre la nuova) -
versionCode
: il numero di versione interno che deve essere più grande su ciascun aggiornamento -
versionName
: il numero di versione che l'utente può vedere nella pagina dei dettagli dell'app
-
-
buildTypes
: guarda da qualche altra parte (TODO)
-
dependencies
: ledependencies
Maven o locali della tua app-
compile
una singola dipendenza -
testCompile
: una dipendenza per l'unità o test di integrazione
-
Osservazioni
Guarda anche
- La homepage ufficiale di gradle
- Come configurare build gradle
- Il plugin Android per gradle
- Android Gradle DSL
Gradle per Android - Documentazione estesa:
C'è un altro tag dove puoi trovare più argomenti ed esempi sull'uso di gradle in Android.
http://www.riptutorial.com/topic/2092
Un file build.gradle di base
Questo è un esempio di un file build.gradle
predefinito in un modulo.
apply plugin: 'com.android.application'
android {
compileSdkVersion 25
buildToolsVersion '25.0.3'
signingConfigs {
applicationName {
keyAlias 'applicationName'
keyPassword 'password'
storeFile file('../key/applicationName.jks')
storePassword 'keystorePassword'
}
}
defaultConfig {
applicationId 'com.company.applicationName'
minSdkVersion 14
targetSdkVersion 25
versionCode 1
versionName '1.0'
signingConfig signingConfigs.applicationName
}
buildTypes {
release {
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile 'com.android.support:appcompat-v7:25.3.1'
compile 'com.android.support:design:25.3.1'
testCompile 'junit:junit:4.12'
}
DSL (linguaggio specifico del dominio)
Ogni blocco nel file sopra è chiamato DSL
(linguaggio specifico del dominio).
plugin
La prima riga, apply plugin: 'com.android.application'
, applica il plug-in Android per Gradle alla build e rende disponibile il blocco android {}
per dichiarare le opzioni di generazione specifiche per Android.
Per un'applicazione Android :
apply plugin: 'com.android.application'
Per una libreria Android :
apply plugin: 'com.android.library'
Comprendere i DSL nell'esempio sopra
La seconda parte, il blocco android {...}
, è il DSL
Android che contiene informazioni sul tuo progetto.
Ad esempio, puoi impostare compileSdkVersion
che specifica il livello dell'API Android, che dovrebbe essere usato da Gradle per compilare la tua app.
Il sub-blocco defaultConfig
contiene i valori predefiniti per il manifest. Puoi override
con gli aromi del prodotto .
Puoi trovare maggiori informazioni in questi esempi:
dipendenze
Il blocco delle dependencies
è definito al di fuori del blocco android
{...}
: ciò significa che non è definito dal plug-in Android ma è Gradle standard.
Il blocco delle dependencies
specifica quali librerie esterne (tipicamente le librerie Android, ma anche le librerie Java sono valide) che desideri includere nella tua app. Gradle scaricherà automaticamente queste dipendenze per te (se non è disponibile una copia locale), devi semplicemente aggiungere linee di compile
simili quando desideri aggiungere un'altra libreria.
Diamo un'occhiata a una delle righe qui presenti:
compile 'com.android.support:design:25.3.1'
Questa linea dice fondamentalmente
aggiungi una dipendenza dalla libreria di progettazione del supporto Android al mio progetto.
Gradle farà in modo che la libreria sia scaricata e presente in modo che tu possa usarla nella tua app e il suo codice sarà incluso anche nella tua app.
Se hai familiarità con Maven, questa sintassi è GroupId , due punti, ArtifactId , un altro punto, quindi la versione della dipendenza che desideri includere, dandoti il pieno controllo sul controllo delle versioni.
Mentre è possibile specificare le versioni di artefatto usando il segno più (+), la migliore pratica è evitare di farlo; può portare a problemi se la libreria viene aggiornata con interruzioni di modifica a tua insaputa, il che probabilmente causerebbe arresti anomali nella tua app.
Puoi aggiungere diversi tipi di dipendenze:
Un'attenzione particolare dovrebbe essere dedicata alle dipendenze piatte .
Puoi trovare maggiori dettagli in questo argomento.
Nota su -v7 in appcompat-v7
compile 'com.android.support:appcompat-v7:25.3.1'
Ciò significa semplicemente che questa libreria ( appcompat
) è compatibile con il livello API Android 7 e versioni successive.
Nota sulla junit: junit: 4.12
Questa è la dipendenza del test per il test dell'unità.
Specifica delle dipendenze specifiche per diverse configurazioni di build
È possibile specificare che una dipendenza deve essere utilizzato solo per un determinato configurazione di generazione oppure è possibile definire diverse dipendenze per i tipi di compilazione o dei sapori di prodotti (ad esempio, eseguire il debug, test o di rilascio) utilizzando debugCompile
, testCompile
o releaseCompile
al posto della solita compile
.
Questo è utile per mantenere le dipendenze test-debug-correlate fuori dalla build di rilascio, che manterrà il tuo APK
release il più sottile possibile e ti aiuterà a garantire che qualsiasi informazione di debug non possa essere utilizzata per ottenere informazioni interne sulla tua app.
signingConfig
signingConfig
consente di configurare Gradle in modo da includere le informazioni sul keystore
e garantire che l'APK creato utilizzando queste configurazioni sia firmato e pronto per la versione Play Store.
Qui puoi trovare un argomento dedicato .
Nota : non è tuttavia consigliabile mantenere le credenziali di firma all'interno del file Gradle. Per rimuovere le configurazioni di firma, basta omettere la porzione signingConfigs
.
Puoi specificarli in diversi modi:
- memorizzazione in un file esterno
- memorizzandoli nell'impostazione delle variabili d'ambiente .
Vedi questo argomento per maggiori dettagli: Firma APK senza esporre la password del keystore .
Puoi trovare ulteriori informazioni su Gradle per Android nell'argomento dedicato di Gradle .
Definire i sapori del prodotto
I sapori del prodotto sono definiti nel file build.gradle
all'interno del blocco di android { ... }
come mostrato di seguito.
...
android {
...
productFlavors {
free {
applicationId "com.example.app.free"
versionName "1.0-free"
}
paid {
applicationId "com.example.app.paid"
versionName "1.0-paid"
}
}
}
In questo modo, ora disponiamo di due ulteriori prodotti: free
e a paid
. Ciascuno può avere la propria configurazione e attributi specifici. Ad esempio, entrambi i nostri nuovi aromi hanno un applicationId
e versioneName versionName
rispetto al nostro aroma main
esistente (disponibile per impostazione predefinita, quindi non mostrato qui).
Aggiunta di dipendenze specifiche per il gusto del prodotto
Le dipendenze possono essere aggiunte per un determinato gusto del prodotto , in modo simile a come possono essere aggiunte per configurazioni di build specifiche.
Per questo esempio, supponiamo di aver già definito due aromi di prodotto chiamati free
e a paid
(più sulla definizione degli aromi qui ).
Possiamo quindi aggiungere la dipendenza di AdMob per l'aroma free
e la libreria di Picasso per quella a paid
modo:
android {
...
productFlavors {
free {
applicationId "com.example.app.free"
versionName "1.0-free"
}
paid {
applicationId "com.example.app.paid"
versionName "1.0-paid"
}
}
}
...
dependencies {
...
// Add AdMob only for free flavor
freeCompile 'com.android.support:appcompat-v7:23.1.1'
freeCompile 'com.google.android.gms:play-services-ads:8.4.0'
freeCompile 'com.android.support:support-v4:23.1.1'
// Add picasso only for paid flavor
paidCompile 'com.squareup.picasso:picasso:2.5.2'
}
...
Aggiunta di risorse specifiche per il gusto del prodotto
Le risorse possono essere aggiunte per un determinato gusto del prodotto .
Per questo esempio, supponiamo di aver già definito due sapori del prodotto chiamati free
e a paid
. Per aggiungere risorse specifiche per il gusto del prodotto, creiamo ulteriori cartelle di risorse accanto alla cartella main/res
, che possiamo aggiungere come al solito. Per questo esempio, definiremo una stringa, lo status
, per ogni gusto del prodotto:
/ src / main /res/values/strings.xml
<resources>
<string name="status">Default</string>
</resources>
/ src / free /res/values/strings.xml
<resources>
<string name="status">Free</string>
</resources>
/ src / paid /res/values/strings.xml
<resources>
<string name="status">Paid</string>
</resources>
Le stringhe di status
specifiche per l'aroma del prodotto sostituiranno il valore per lo status
nel gusto main
.
Definire e utilizzare i Campi configurazione build
BuildConfigField
Gradle consente buildConfigField
linee buildConfigField
di definire le costanti. Queste costanti saranno accessibili in runtime come campi statici della classe BuildConfig
. Questo può essere usato per creare aromi definendo tutti i campi all'interno del blocco defaultConfig
, quindi sovrascrivendolo per i singoli sapori di build, se necessario.
Questo esempio definisce la data di costruzione e contrassegna la build per la produzione anziché il test:
android {
...
defaultConfig {
...
// defining the build date
buildConfigField "long", "BUILD_DATE", System.currentTimeMillis() + "L"
// define whether this build is a production build
buildConfigField "boolean", "IS_PRODUCTION", "false"
// note that to define a string you need to escape it
buildConfigField "String", "API_KEY", "\"my_api_key\""
}
productFlavors {
prod {
// override the productive flag for the flavor "prod"
buildConfigField "boolean", "IS_PRODUCTION", "true"
resValue 'string', 'app_name', 'My App Name'
}
dev {
// inherit default fields
resValue 'string', 'app_name', 'My App Name - Dev'
}
}
}
Il <nome_pacchetto> generato automaticamente. BuildConfig
.java nella cartella gen contiene i seguenti campi basati sulla direttiva sopra:
public class BuildConfig {
// ... other generated fields ...
public static final long BUILD_DATE = 1469504547000L;
public static final boolean IS_PRODUCTION = false;
public static final String API_KEY = "my_api_key";
}
I campi definiti possono ora essere utilizzati all'interno dell'app in fase di runtime accedendo alla classe BuildConfig
generata:
public void example() {
// format the build date
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd");
String buildDate = dateFormat.format(new Date(BuildConfig.BUILD_DATE));
Log.d("build date", buildDate);
// do something depending whether this is a productive build
if (BuildConfig.IS_PRODUCTION) {
connectToProductionApiEndpoint();
} else {
connectToStagingApiEndpoint();
}
}
ResValue
Il resValue
nei productFlavors
crea un valore di risorsa. Può essere qualsiasi tipo di risorsa ( string
, dimen
, color
, ecc.). Questo è simile alla definizione di una risorsa nel file appropriato: ad es. strings.xml
una stringa in un file strings.xml
. Il vantaggio è che quello definito in gradle può essere modificato in base al prodotto Flavor / buildVariant. Per accedere al valore, scrivi lo stesso codice come se tu stessi accedendo a una res dal file delle risorse:
getResources().getString(R.string.app_name)
L'importante è che le risorse definite in questo modo non possano modificare le risorse esistenti definite nei file. Possono solo creare nuovi valori di risorse.
Alcune librerie (come l'API Android di Google Maps) richiedono una chiave API fornita nel Manifesto come tag dei meta-data
. Se sono necessarie chiavi diverse per il debug e le build di produzione, specificare un segnaposto manifest compilato da Gradle.
Nel tuo file AndroidManifest.xml
:
<meta-data
android:name="com.google.android.geo.API_KEY"
android:value="${MAPS_API_KEY}"/>
Quindi imposta il campo di conseguenza nel file build.gradle
:
android {
defaultConfig {
...
// Your development key
manifestPlaceholders = [ MAPS_API_KEY: "AIza..." ]
}
productFlavors {
prod {
// Your production key
manifestPlaceholders = [ MAPS_API_KEY: "AIza..." ]
}
}
}
Il sistema di build Android genera automaticamente un numero di campi e li inserisce in BuildConfig.java
. Questi campi sono:
Campo | Descrizione |
---|---|
DEBUG | un Boolean indica se l'app è in modalità di debug o di rilascio |
APPLICATION_ID | una String contenente l'ID dell'applicazione (es. com.example.app ) |
BUILD_TYPE | una String contenente il tipo di build dell'applicazione (di solito sia il debug che il release ) |
FLAVOR | una String contiene il particolare sapore della build |
VERSION_CODE | un int contenente il numero della versione (build). È lo stesso di versionCode in build.gradle o versionCode in AndroidManifest.xml |
VERSION_NAME | una String contenente il nome della versione (build). È lo stesso di versionName in build.gradle o versionName in AndroidManifest.xml |
In aggiunta a quanto sopra, se hai definito più dimensioni di sapore, ciascuna dimensione avrà il suo valore. Ad esempio, se hai due dimensioni di aroma per color
e size
avrai anche le seguenti variabili:
Campo | Descrizione |
---|---|
FLAVOR_color | una String contenente il valore per il sapore "colore". |
FLAVOR_size | una String contenente il valore per il sapore "taglia". |
Centralizzazione delle dipendenze tramite il file "dependencies.gradle"
Quando si lavora con progetti multi-modulo, è utile centralizzare le dipendenze in una singola posizione piuttosto che distribuirle su molti file di build, specialmente per le librerie comuni come le librerie di supporto Android e le librerie Firebase .
Un modo consigliato è quello di separare i file di build di Gradle, con un build.gradle
per modulo, nonché uno nella root del progetto e un altro per le dipendenze, ad esempio:
root
+- gradleScript/
| dependencies.gradle
+- module1/
| build.gradle
+- module2/
| build.gradle
+- build.gradle
Quindi, tutte le tue dipendenze possono trovarsi in gradleScript/dependencies.gradle
:
ext {
// Version
supportVersion = '24.1.0'
// Support Libraries dependencies
supportDependencies = [
design: "com.android.support:design:${supportVersion}",
recyclerView: "com.android.support:recyclerview-v7:${supportVersion}",
cardView: "com.android.support:cardview-v7:${supportVersion}",
appCompat: "com.android.support:appcompat-v7:${supportVersion}",
supportAnnotation: "com.android.support:support-annotations:${supportVersion}",
]
firebaseVersion = '9.2.0';
firebaseDependencies = [
core: "com.google.firebase:firebase-core:${firebaseVersion}",
database: "com.google.firebase:firebase-database:${firebaseVersion}",
storage: "com.google.firebase:firebase-storage:${firebaseVersion}",
crash: "com.google.firebase:firebase-crash:${firebaseVersion}",
auth: "com.google.firebase:firebase-auth:${firebaseVersion}",
messaging: "com.google.firebase:firebase-messaging:${firebaseVersion}",
remoteConfig: "com.google.firebase:firebase-config:${firebaseVersion}",
invites: "com.google.firebase:firebase-invites:${firebaseVersion}",
adMod: "com.google.firebase:firebase-ads:${firebaseVersion}",
appIndexing: "com.google.android.gms:play-services-appindexing:${firebaseVersion}",
];
}
Quale può quindi essere applicato da quel file nel file di livello superiore build.gradle
modo:
// Load dependencies
apply from: 'gradleScript/dependencies.gradle'
e nel module1/build.gradle
modo:
// Module build file
dependencies {
// ...
compile supportDependencies.appCompat
compile supportDependencies.design
compile firebaseDependencies.crash
}
Un altro approccio
Un approccio meno dettagliato per la centralizzazione delle versioni delle dipendenze della libreria può essere ottenuto dichiarando il numero di versione come variabile una volta e utilizzandolo ovunque.
Nell'area di lavoro root build.gradle
aggiungere questo:
ext.v = [
supportVersion:'24.1.1',
]
E in ogni modulo che usa la stessa libreria aggiungi le librerie necessarie
compile "com.android.support:support-v4:${v.supportVersion}"
compile "com.android.support:recyclerview-v7:${v.supportVersion}"
compile "com.android.support:design:${v.supportVersion}"
compile "com.android.support:support-annotations:${v.supportVersion}"
Struttura della directory per risorse specifiche per il gusto
Diversi tipi di build dell'applicazione possono contenere risorse diverse. Per creare una risorsa specifica per il gusto, crea una directory con il nome in minuscolo del tuo gusto nella directory src
e aggiungi le tue risorse nello stesso modo in cui faresti normalmente.
Ad esempio, se si dispone di uno Development
sapore e si desidera fornire un'icona di avvio distinta per esso, si creerà una directory src/development/res/drawable-mdpi
e all'interno di tale directory creare un file ic_launcher.png
con l'icona specifica per lo sviluppo.
La struttura della directory sarà simile a questa:
src/
main/
res/
drawable-mdpi/
ic_launcher.png <-- the default launcher icon
development/
res/
drawable-mdpi/
ic_launcher.png <-- the launcher icon used when the product flavor is 'Development'
(Naturalmente, in questo caso si creerebbero anche icone per disegnabili-hdpi, disegnabili-xhdpi, ecc .).
Perché ci sono due file build.gradle in un progetto Android Studio?
<PROJECT_ROOT>\app\build.gradle
è specifico per il modulo app .
<PROJECT_ROOT>\build.gradle
è un "file di build di livello superiore" in cui è possibile aggiungere opzioni di configurazione comuni a tutti i sottoprogetti / moduli.
Se utilizzi un altro modulo nel tuo progetto, come libreria locale avresti un altro file build.gradle
: <PROJECT_ROOT>\module\build.gradle
Nel file di livello superiore è possibile specificare proprietà comuni come blocco di script o alcune proprietà comuni.
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:2.2.0'
classpath 'com.google.gms:google-services:3.0.0'
}
}
ext {
compileSdkVersion = 23
buildToolsVersion = "23.0.1"
}
Nell'app app\build.gradle
si definiscono solo le proprietà per il modulo:
apply plugin: 'com.android.application'
android {
compileSdkVersion rootProject.ext.compileSdkVersion
buildToolsVersion rootProject.ext.buildToolsVersion
}
dependencies {
//.....
}
Esecuzione di uno script di shell da gradle
Uno script di shell è un modo molto versatile per estendere la tua build a praticamente qualsiasi cosa tu possa pensare.
Come un exmaple, ecco un semplice script per compilare i file di protobuf e aggiungere i file java risultanti alla directory di origine per un'ulteriore compilazione:
def compilePb() {
exec {
// NOTICE: gradle will fail if there's an error in the protoc file...
executable "../pbScript.sh"
}
}
project.afterEvaluate {
compilePb()
}
Lo script di shell 'pbScript.sh' per questo esempio, che si trova nella cartella principale del progetto:
#!/usr/bin/env bash
pp=/home/myself/my/proto
/usr/local/bin/protoc -I=$pp \
--java_out=./src/main/java \
--proto_path=$pp \
$pp/my.proto \
--proto_path=$pp \
$pp/my_other.proto
Eseguire il debug degli errori di Gradle
Quello che segue è un estratto di Gradle - Cos'è un valore di uscita diverso da zero e come lo risolvo? , guardalo per la discussione completa.
Diciamo che stai sviluppando un'applicazione e ottieni un errore di Gradle che sembra che in genere sarà simile a quello.
:module:someTask FAILED
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':module:someTask'.
> some message here... finished with non-zero exit value X
* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.
BUILD FAILED
Total time: Y.ZZ secs
Cerca qui StackOverflow per il tuo problema e le persone dicono di pulire e ricostruire il tuo progetto, o abilitare MultiDex , e quando lo provi, non risolve il problema.
Ci sono modi per ottenere maggiori informazioni , ma l'output Gradle stesso dovrebbe puntare all'errore effettivo nelle poche righe sopra quel messaggio tra: module:someTask FAILED
e l'ultimo :module:someOtherTask
che è passato. Pertanto, se fai una domanda sul tuo errore, modifica le tue domande per includere più contesto nell'errore.
Quindi, ottieni un "valore di uscita diverso da zero". Bene, quel numero è un buon indicatore di ciò che dovresti provare a sistemare. Qui ci sono alcuni che si verificano più frequentemente.
-
1
è solo un codice di errore generale e l'errore è probabile nell'uscita Gradle -
2
sembra essere correlato a dipendenze sovrapposte o errata configurazione del progetto. -
3
sembra che includa troppe dipendenze o un problema di memoria.
Le soluzioni generali per quanto sopra (dopo aver tentato di pulire e ricostruire il progetto) sono:
-
1
- Risolvi l'errore menzionato. Generalmente, questo è un errore in fase di compilazione, nel senso che parte del codice nel tuo progetto non è valida. Questo include sia XML che Java per un progetto Android. -
2
e3
- Molte risposte qui ti dicono di abilitare il multidex . Mentre può risolvere il problema, è molto probabile una soluzione alternativa. Se non capisci perché lo stai usando (vedi il link), probabilmente non ne hai bisogno. Le soluzioni generali comportano un taglio eccessivo delle dipendenze della libreria (come tutti i servizi di Google Play, quando è necessario utilizzare solo una libreria, ad esempio Maps o Accesso, ad esempio).
Specifica di diversi ID di applicazione per tipi di build e aromi di prodotto
È possibile specificare gli ID di applicazione diversi o nomi dei pacchetti per ogni buildType
o productFlavor
utilizzando l'attributo di configurazione applicationIdSuffix:
Esempio di buildType
applicationId
per ogni buildType
:
defaultConfig {
applicationId "com.package.android"
minSdkVersion 17
targetSdkVersion 23
versionCode 1
versionName "1.0"
}
buildTypes {
release {
debuggable false
}
development {
debuggable true
applicationIdSuffix ".dev"
}
testing {
debuggable true
applicationIdSuffix ".qa"
}
}
I nostri applicationIds
risultanti ora sarebbero:
- com.package.android per il
release
- com.package.android. dev per lo
development
- com.package.android. qa per il
testing
Questo può essere fatto anche per productFlavors
:
productFlavors {
free {
applicationIdSuffix ".free"
}
paid {
applicationIdSuffix ".paid"
}
}
Le applicationIds
risultanti sarebbero:
- com.package.android. gratis per il gusto
free
- com.package.android. pagato per il sapore
paid
Firma APK senza esporre la password del keystore
È possibile definire la configurazione della firma per firmare l'apk nel file build.gradle
utilizzando queste proprietà:
-
storeFile
: il file keystore -
storePassword
: la password del keystore -
keyAlias
: un nome alias chiave -
keyPassword
: una password alias chiave
In molti casi potrebbe essere necessario evitare questo tipo di informazioni nel file build.gradle
.
Metodo A: Configurare la firma di rilascio utilizzando un file keystore.properties
È possibile configurare build.gradle
modo che legga le informazioni sulla configurazione della firma da un file delle proprietà come keystore.properties
.
Impostare la firma in questo modo è utile perché:
- Le informazioni sulla configurazione della firma sono separate dal file
build.gradle
- Non è necessario intervenire durante la procedura di firma per fornire password per il file del keystore
- È possibile escludere facilmente il file
keystore.properties
dal controllo di versione
Per prima cosa, crea un file chiamato keystore.properties
nella radice del tuo progetto con contenuto come questo (sostituendo i valori con il tuo):
storeFile=keystore.jks
storePassword=storePassword
keyAlias=keyAlias
keyPassword=keyPassword
Ora, nel file build.gradle
della tua app, imposta il blocco signingConfigs
come segue:
android {
...
signingConfigs {
release {
def propsFile = rootProject.file('keystore.properties')
if (propsFile.exists()) {
def props = new Properties()
props.load(new FileInputStream(propsFile))
storeFile = file(props['storeFile'])
storePassword = props['storePassword']
keyAlias = props['keyAlias']
keyPassword = props['keyPassword']
}
}
}
}
Questo è davvero tutto quello che c'è da fare, ma non dimenticare di escludere sia il file keystore.properties
file keystore.properties
dal controllo di versione .
Un paio di cose da notare:
- Il percorso del file
storeFile
specificato nel filekeystore.properties
deve essere relativo al filebuild.gradle
dell'app. In questo esempio si presuppone che il file keystore si trovi nella stessa directory del filebuild.gradle
dell'app. - Questo esempio ha il file
keystore.properties
nella radice del progetto. Se lo metti da qualche altra parte, assicurati di cambiare il valore inrootProject.file('keystore.properties')
nella posizione del tuo, rispetto alla radice del tuo progetto.
Metodo B: utilizzando una variabile di ambiente
Lo stesso può essere ottenuto anche senza un file di proprietà, rendendo la password più difficile da trovare:
android {
signingConfigs {
release {
storeFile file('/your/keystore/location/key')
keyAlias 'your_alias'
String ps = System.getenv("ps")
if (ps == null) {
throw new GradleException('missing ps env variable')
}
keyPassword ps
storePassword ps
}
}
La variabile di ambiente "ps"
può essere globale, ma un approccio più sicuro può essere aggiungendolo alla shell di Android Studio.
In Linux questo può essere fatto modificando la Desktop Entry
Android Studio
Exec=sh -c "export ps=myPassword123 ; /path/to/studio.sh"
Puoi trovare maggiori dettagli in questo argomento .
Eseguendo il controllo delle versioni tramite il file "version.properties"
Puoi utilizzare Gradle per incrementare automaticamente la versione del pacchetto ogni volta che lo compili. Per fare in modo di creare un version.properties
file nella stessa directory del build.gradle
con il seguente contenuto:
VERSION_MAJOR=0
VERSION_MINOR=1
VERSION_BUILD=1
(Cambiando i valori per maggiore e minore come meglio credi). Quindi nel tuo build.gradle
aggiungi il seguente codice alla sezione android
:
// Read version information from local file and increment as appropriate
def versionPropsFile = file('version.properties')
if (versionPropsFile.canRead()) {
def Properties versionProps = new Properties()
versionProps.load(new FileInputStream(versionPropsFile))
def versionMajor = versionProps['VERSION_MAJOR'].toInteger()
def versionMinor = versionProps['VERSION_MINOR'].toInteger()
def versionBuild = versionProps['VERSION_BUILD'].toInteger() + 1
// Update the build number in the local file
versionProps['VERSION_BUILD'] = versionBuild.toString()
versionProps.store(versionPropsFile.newWriter(), null)
defaultConfig {
versionCode versionBuild
versionName "${versionMajor}.${versionMinor}." + String.format("%05d", versionBuild)
}
}
È possibile accedere alle informazioni in Java come una stringa BuildConfig.VERSION_NAME
per il numero {major}. {Minor}. { BuildConfig.VERSION_NAME
} completo e come un intero BuildConfig.VERSION_CODE
per il solo numero di build.
Modifica del nome apk di output e aggiunta del nome della versione:
Questo è il codice per cambiare il nome del file dell'applicazione di output (.apk). Il nome può essere configurato assegnando un valore diverso a newName
android {
applicationVariants.all { variant ->
def newName = "ApkName";
variant.outputs.each { output ->
def apk = output.outputFile;
newName += "-v" + defaultConfig.versionName;
if (variant.buildType.name == "release") {
newName += "-release.apk";
} else {
newName += ".apk";
}
if (!output.zipAlign) {
newName = newName.replace(".apk", "-unaligned.apk");
}
output.outputFile = new File(apk.parentFile, newName);
logger.info("INFO: Set outputFile to "
+ output.outputFile
+ " for [" + output.name + "]");
}
}
}
Disattiva la compressione dell'immagine per una dimensione file APK più piccola
Se si stanno ottimizzando manualmente tutte le immagini, disabilitare Cruncher APT per una dimensione file APK più piccola.
android {
aaptOptions {
cruncherEnabled = false
}
}
Abilita Proguard usando Gradle
Per abilitare le configurazioni Proguard per la tua applicazione devi abilitarlo nel tuo file gradle a livello di modulo. È necessario impostare il valore di minifyEnabled
su true
.
buildTypes {
release {
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
Il codice sopra riportato applicherà le configurazioni Proguard contenute nell'SDK Android predefinito combinato con il file "proguard-rules.pro" sul tuo modulo per l'apk rilasciato.
Abilita il supporto del plug-in NDK sperimentale per Gradle e AndroidStudio
Abilita e configura il plugin Gradle sperimentale per migliorare il supporto NDK di AndroidStudio. Verifica di soddisfare i seguenti requisiti:
- Gradle 2.10 (per questo esempio)
- Android NDK r10 o successivo
- Android SDK con strumenti di compilazione v19.0.0 o versioni successive
Configura il file MyApp / build.gradle
Modifica la linea dependencies.classpath in build.gradle da es
classpath 'com.android.tools.build:gradle:2.1.2'
a
classpath 'com.android.tools.build:gradle-experimental:0.7.2'
(V0.7.2 era l'ultima versione al momento della stesura. Controlla la versione più recente e adatta la tua linea di conseguenza)
Il file build.gradle dovrebbe essere simile a questo:
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle-experimental:0.7.2'
}
}
allprojects {
repositories {
jcenter()
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
Configura il file MyApp / app / build.gradle
Modifica il file build.gradle in modo che assomigli al seguente esempio. I numeri di versione potrebbero essere diversi.
apply plugin: 'com.android.model.application'
model {
android {
compileSdkVersion 19
buildToolsVersion "24.0.1"
defaultConfig {
applicationId "com.example.mydomain.myapp"
minSdkVersion.apiLevel 19
targetSdkVersion.apiLevel 19
versionCode 1
versionName "1.0"
}
buildTypes {
release {
minifyEnabled false
proguardFiles.add(file('proguard-android.txt'))
}
}
ndk {
moduleName "myLib"
/* The following lines are examples of a some optional flags that
you may set to configure your build environment
*/
cppFlags.add("-I${file("path/to/my/includes/dir")}".toString())
cppFlags.add("-std=c++11")
ldLibs.addAll(['log', 'm'])
stl = "c++_static"
abiFilters.add("armeabi-v7a")
}
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
}
Sincronizzare e controllare che non ci siano errori nei file Gradle prima di procedere.
Verifica se il plugin è abilitato
Innanzitutto assicurati di aver scaricato il modulo NDK di Android. Quindi crea una nuova app in AndroidStudio e aggiungi quanto segue al file ActivityMain:
public class MainActivity implements Activity {
onCreate() {
// Pregenerated code. Not important here
}
static {
System.loadLibrary("myLib");
}
public static native String getString();
}
La parte getString()
dovrebbe essere evidenziata in rosso per indicare che non è stato possibile trovare la funzione JNI corrispondente. Passa il mouse sopra la chiamata di funzione fino a quando non viene visualizzata una lampadina rossa. Fare clic sulla lampadina e selezionare create function JNI_...
Questo dovrebbe generare un file myLib.c nella directory myApp / app / src / main / jni con la chiamata della funzione JNI corretta. Dovrebbe assomigliare a questo:
#include <jni.h>
JNIEXPORT jstring JNICALL
Java_com_example_mydomain_myapp_MainActivity_getString(JNIEnv *env, jobject instance)
{
// TODO
return (*env)->NewStringUTF(env, returnValue);
}
Se non sembra così, il plugin non è stato configurato correttamente o l'NDK non è stato scaricato
Mostra tutte le attività del progetto gradle
gradlew tasks -- show all tasks
Android tasks
-------------
androidDependencies - Displays the Android dependencies of the project.
signingReport - Displays the signing info for each variant.
sourceSets - Prints out all the source sets defined in this project.
Build tasks
-----------
assemble - Assembles all variants of all applications and secondary packages.
assembleAndroidTest - Assembles all the Test applications.
assembleDebug - Assembles all Debug builds.
assembleRelease - Assembles all Release builds.
build - Assembles and tests this project.
buildDependents - Assembles and tests this project and all projects that depend on it.
buildNeeded - Assembles and tests this project and all projects it depends on.
classes - Assembles main classes.
clean - Deletes the build directory.
compileDebugAndroidTestSources
compileDebugSources
compileDebugUnitTestSources
compileReleaseSources
compileReleaseUnitTestSources
extractDebugAnnotations - Extracts Android annotations for the debug variant into the archive file
extractReleaseAnnotations - Extracts Android annotations for the release variant into the archive file
jar - Assembles a jar archive containing the main classes.
mockableAndroidJar - Creates a version of android.jar that's suitable for unit tests.
testClasses - Assembles test classes.
Build Setup tasks
-----------------
init - Initializes a new Gradle build. [incubating]
wrapper - Generates Gradle wrapper files. [incubating]
Documentation tasks
-------------------
javadoc - Generates Javadoc API documentation for the main source code.
Help tasks
----------
buildEnvironment - Displays all buildscript dependencies declared in root project 'LeitnerBoxPro'.
components - Displays the components produced by root project 'LeitnerBoxPro'. [incubating]
dependencies - Displays all dependencies declared in root project 'LeitnerBoxPro'.
dependencyInsight - Displays the insight into a specific dependency in root project 'LeitnerBoxPro'.
help - Displays a help message.
model - Displays the configuration model of root project 'LeitnerBoxPro'. [incubating]
projects - Displays the sub-projects of root project 'LeitnerBoxPro'.
properties - Displays the properties of root project 'LeitnerBoxPro'.
tasks - Displays the tasks runnable from root project 'LeitnerBoxPro' (some of the displayed tasks may belong to subprojects)
.
Install tasks
-------------
installDebug - Installs the Debug build.
installDebugAndroidTest - Installs the android (on device) tests for the Debug build.
uninstallAll - Uninstall all applications.
uninstallDebug - Uninstalls the Debug build.
uninstallDebugAndroidTest - Uninstalls the android (on device) tests for the Debug build.
uninstallRelease - Uninstalls the Release build.
Verification tasks
------------------
check - Runs all checks.
connectedAndroidTest - Installs and runs instrumentation tests for all flavors on connected devices.
connectedCheck - Runs all device checks on currently connected devices.
connectedDebugAndroidTest - Installs and runs the tests for debug on connected devices.
deviceAndroidTest - Installs and runs instrumentation tests using all Device Providers.
deviceCheck - Runs all device checks using Device Providers and Test Servers.
lint - Runs lint on all variants.
lintDebug - Runs lint on the Debug build.
lintRelease - Runs lint on the Release build.
test - Run unit tests for all variants.
testDebugUnitTest - Run unit tests for the debug build.
testReleaseUnitTest - Run unit tests for the release build.
Other tasks
-----------
assembleDefault
clean
jarDebugClasses
jarReleaseClasses
transformResourcesWithMergeJavaResForDebugUnitTest
transformResourcesWithMergeJavaResForReleaseUnitTest
Elimina automaticamente l'apk "non allineato"
Se non hai bisogno di file apk generati automaticamente con suffisso unaligned
(cosa che probabilmente non fai), puoi aggiungere il seguente codice al file build.gradle
:
// delete unaligned files
android.applicationVariants.all { variant ->
variant.assemble.doLast {
variant.outputs.each { output ->
println "aligned " + output.outputFile
println "unaligned " + output.packageApplication.outputFile
File unaligned = output.packageApplication.outputFile;
File aligned = output.outputFile
if (!unaligned.getName().equalsIgnoreCase(aligned.getName())) {
println "deleting " + unaligned.getName()
unaligned.delete()
}
}
}
}
Da qui
Ignorando la variante di costruzione
Per alcuni motivi potresti voler ignorare le varianti di costruzione. Ad esempio: hai "schernito" l'aroma del prodotto e lo utilizzi solo a scopo di debug, come i test di unità / strumentazione.
Ignoriamo la variante di mockRelease dal nostro progetto. Aprire il file build.gradle e scrivere:
// Remove mockRelease as it's not needed.
android.variantFilter { variant ->
if (variant.buildType.name.equals('release') && variant.getFlavors().get(0).name.equals('mock')) {
variant.setIgnore(true);
}
}
Vedere l'albero delle dipendenze
Usa le dipendenze delle attività. A seconda di come sono configurati i tuoi moduli, possono essere le ./gradlew dependencies
o vedere le dipendenze dell'app modulo utilizzare ./gradlew :app:dependencies
L'esempio seguente il file build.gradle
dependencies {
compile 'com.android.support:design:23.2.1'
compile 'com.android.support:cardview-v7:23.1.1'
compile 'com.google.android.gms:play-services:6.5.87'
}
produrrà il seguente grafico:
Parallel execution is an incubating feature.
:app:dependencies
------------------------------------------------------------
Project :app
------------------------------------------------------------
. . .
_releaseApk - ## Internal use, do not manually configure ##
+--- com.android.support:design:23.2.1
| +--- com.android.support:support-v4:23.2.1
| | \--- com.android.support:support-annotations:23.2.1
| +--- com.android.support:appcompat-v7:23.2.1
| | +--- com.android.support:support-v4:23.2.1 (*)
| | +--- com.android.support:animated-vector-drawable:23.2.1
| | | \--- com.android.support:support-vector-drawable:23.2.1
| | | \--- com.android.support:support-v4:23.2.1 (*)
| | \--- com.android.support:support-vector-drawable:23.2.1 (*)
| \--- com.android.support:recyclerview-v7:23.2.1
| +--- com.android.support:support-v4:23.2.1 (*)
| \--- com.android.support:support-annotations:23.2.1
+--- com.android.support:cardview-v7:23.1.1
\--- com.google.android.gms:play-services:6.5.87
\--- com.android.support:support-v4:21.0.0 -> 23.2.1 (*)
. . .
Qui puoi vedere che il progetto include direttamente com.android.support:design
versione 23.2.1, che a sua volta sta portando com.android.support:support-v4
con la versione 23.2.1. Tuttavia, com.google.android.gms:play-services
stessa hanno una dipendenza dallo stesso support-v4
ma con una versione precedente 21.0.0, che è un conflitto rilevato da gradle.
(*)
vengono utilizzati quando gradle salta la sottostruttura perché quelle dipendenze erano già elencate in precedenza.
Usa gradle.properties per versionnumber centrale / buildconfigurations
È possibile definire le informazioni di configurazione centrale in
- un gradle separato include il file Centralizzare le dipendenze tramite il file "dependencies.gradle"
- un file di proprietà autonomo Versionare i tuoi build tramite il file "version.properties"
oppure farlo con il file root gradle.properties
la struttura del progetto
root
+- module1/
| build.gradle
+- module2/
| build.gradle
+- build.gradle
+- gradle.properties
impostazione globale per tutti i sottomoduli in gradle.properties
# used for manifest
# todo increment for every release
appVersionCode=19
appVersionName=0.5.2.160726
# android tools settings
appCompileSdkVersion=23
appBuildToolsVersion=23.0.2
utilizzo in un sottomodulo
apply plugin: 'com.android.application'
android {
// appXXX are defined in gradle.properties
compileSdkVersion = Integer.valueOf(appCompileSdkVersion)
buildToolsVersion = appBuildToolsVersion
defaultConfig {
// appXXX are defined in gradle.properties
versionCode = Long.valueOf(appVersionCode)
versionName = appVersionName
}
}
dependencies {
...
}
Nota: se si desidera pubblicare la propria app nell'app store F-Droid, è necessario utilizzare numeri magici nel file gradle perché altrimenti il robot f-droid non può leggere il versionnumner corrente per rilevare / verificare le modifiche della versione.
Visualizza le informazioni di firma
In alcune circostanze (ad esempio, ottenere una chiave API di Google) è necessario trovare l'impronta digitale del keystore. Gradle ha un compito utile che visualizza tutte le informazioni sulla firma, incluse le impronte digitali del keystore:
./gradlew signingReport
Questo è un esempio di output:
:app:signingReport
Variant: release
Config: none
----------
Variant: debug
Config: debug
Store: /Users/user/.android/debug.keystore
Alias: AndroidDebugKey
MD5: 25:08:76:A9:7C:0C:19:35:99:02:7B:00:AA:1E:49:CA
SHA1: 26:BE:89:58:00:8C:5A:7D:A3:A9:D3:60:4A:30:53:7A:3D:4E:05:55
Valid until: Saturday 18 June 2044
----------
Variant: debugAndroidTest
Config: debug
Store: /Users/user/.android/debug.keystore
Alias: AndroidDebugKey
MD5: 25:08:76:A9:7C:0C:19:35:99:02:7B:00:AA:1E:49:CA
SHA1: 26:BE:89:58:00:8C:5A:7D:A3:A9:D3:60:4A:30:53:7A:3D:4E:05:55
Valid until: Saturday 18 June 2044
----------
Variant: debugUnitTest
Config: debug
Store: /Users/user/.android/debug.keystore
Alias: AndroidDebugKey
MD5: 25:08:76:A9:7C:0C:19:35:99:02:7B:00:AA:1E:49:CA
SHA1: 26:BE:89:58:00:8C:5A:7D:A3:A9:D3:60:4A:30:53:7A:3D:4E:05:55
Valid until: Saturday 18 June 2044
----------
Variant: releaseUnitTest
Config: none
----------
Definizione dei tipi di build
È possibile creare e configurare i tipi di build nel file build.gradle
livello di build.gradle
all'interno del blocco di android {}
.
android { ... defaultConfig {...} buildTypes { release { minifyEnabled true proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } debug { applicationIdSuffix ".debug" } } }