Android
Gradle für Android
Suche…
Einführung
Gradle ist ein JVM-basiertes Buildsystem, mit dem Entwickler übergeordnete Skripts schreiben können, mit denen der Kompilierungs- und Anwendungsprozess automatisiert werden kann. Es ist ein flexibles Plugin-basiertes System, mit dem Sie verschiedene Aspekte des Erstellungsprozesses automatisieren können. einschließlich der Zusammenstellung und eine Unterzeichnung .jar
, Herunterladen und Verwalten von externen Abhängigkeiten, Injizieren Felder in die AndroidManifest
oder spezifische SDK - Versionen verwendet wird .
Syntax
apply plugin
: Die Plugins, die normalerweise verwendet werden sollten, sind nur'com.android.application'
oder'com.android.library'
.android
: Die Hauptkonfiguration Ihrer App-
compileSdkVersion
: Die kompilierte SDK-Version -
buildToolsVersion
: Die Version der Build-Tools -
defaultConfig
: Die Standardeinstellungen, die von Flavors und Build-Typen überschrieben werden können-
applicationId
: Die Anwendungs-ID, die Sie zB im PlayStore verwenden, stimmt im Wesentlichen mit Ihrem Paketnamen überein -
minSdkVersion
: Die minimal erforderliche SDK-Version -
targetSdkVersion
: Die SDK-Version, für die Sie kompilieren (sollte immer die neueste sein) -
versionCode
: Die interne Versionsnummer, die bei jedem Update größer sein muss -
versionName
: Die Versionsnummer, die der Benutzer auf der App-versionName
sehen kann
-
-
buildTypes
: Siehe woanders (TODO)
-
dependencies
: Die Maven oder lokalen Abhängigkeiten Ihrer App- eine einzelne Abhängigkeit
compile
-
testCompile
: eine Abhängigkeit für die Einheiten- oder Integrationstests
- eine einzelne Abhängigkeit
Bemerkungen
Siehe auch
- Die offizielle Gradle-Homepage
- So konfigurieren Sie Gradle-Builds
- Das Android-Plugin für Gradle
- Android Gradle DSL
Gradle für Android - Erweiterte Dokumentation:
Es gibt ein weiteres Tag, wo Sie weitere Themen und Beispiele zur Verwendung von Gradle in Android finden können.
http://www.riptutorial.com/topic/2092
Eine grundlegende build.gradle-Datei
Dies ist ein Beispiel für eine Standarddatei build.gradle
in einem Modul.
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 (domänenspezifische Sprache)
Jeder Block in der obigen Datei wird als DSL
(domänenspezifische Sprache) bezeichnet.
Plugins
Die erste Zeile, apply plugin: 'com.android.application'
, wendet das Android-Plugin für Gradle auf den Build an und macht den android {}
-Block verfügbar, um Android-spezifische Build-Optionen zu deklarieren.
Für eine Android-Anwendung :
apply plugin: 'com.android.application'
Für eine Android-Bibliothek :
apply plugin: 'com.android.library'
Die DSLs im obigen Beispiel verstehen
Der zweite Teil, der android {...}
Block android {...}
, ist der Android- DSL
der Informationen zu Ihrem Projekt enthält.
Sie können beispielsweise die compileSdkVersion
die die Android-API-Ebene angibt. compileSdkVersion
sollte von Gradle zum Kompilieren Ihrer App verwendet werden.
Der defaultConfig
enthält die defaultConfig
für Ihr Manifest. Sie können sie mit Produkt-Flavors override
.
Weitere Informationen finden Sie in diesen Beispielen:
Abhängigkeiten
Der dependencies
wird außerhalb des android
Blocks {...}
: Dies bedeutet, dass er nicht vom Android-Plugin definiert wird, sondern der Standardgradle.
Der dependencies
gibt an, welche externen Bibliotheken (normalerweise Android-Bibliotheken, aber auch Java-Bibliotheken sind gültig) in Ihre App aufgenommen werden sollen. Gradle lädt diese Abhängigkeiten automatisch herunter (wenn keine lokale Kopie verfügbar ist). Sie müssen nur ähnliche compile
hinzufügen compile
wenn Sie eine andere Bibliothek hinzufügen möchten.
Schauen wir uns eine der hier dargestellten Zeilen an:
compile 'com.android.support:design:25.3.1'
Diese Zeile sagt im Grunde
Fügen Sie meinem Projekt eine Abhängigkeit von der Android-Supportdesign-Bibliothek hinzu.
Gradle stellt sicher, dass die Bibliothek heruntergeladen und vorhanden ist, sodass Sie sie in Ihrer App verwenden können. Der Code wird auch in Ihre App aufgenommen.
Wenn Sie mit Maven vertraut sind, handelt es sich bei dieser Syntax um die GroupId , einen Doppelpunkt, ArtifactId , einen weiteren Doppelpunkt und die Version der Abhängigkeit, die Sie einschließen möchten. So haben Sie die vollständige Kontrolle über die Versionierung.
Es ist zwar möglich, Artefaktversionen mithilfe des Pluszeichens (+) anzugeben, dies sollte jedoch vermieden werden. Dies kann zu Problemen führen, wenn die Bibliothek ohne Ihr Wissen mit bahnbrechenden Änderungen aktualisiert wird, was zu Abstürzen in Ihrer App führen könnte.
Sie können verschiedene Arten von Abhängigkeiten hinzufügen:
Ein besonderes Augenmerk sollte den aflachen Abhängigkeiten gewidmet werden .
Weitere Details finden Sie in diesem Thema.
Hinweis zu -v7 in appcompat-v7
compile 'com.android.support:appcompat-v7:25.3.1'
Dies bedeutet einfach, dass diese Bibliothek ( appcompat
) mit der Android-API-Ebene 7 und weiter kompatibel ist.
Anmerkung zum junit: junit: 4.12
Dies ist die Testabhängigkeit für Unit-Tests.
Festlegen von Abhängigkeiten für verschiedene Build-Konfigurationen
Sie können angeben, dass eine Abhängigkeit nur für eine bestimmte Build-Konfiguration verwendet werden soll, oder Sie können andere Abhängigkeiten für die Build-Typen oder die Produktvarianten (z. B. Debug, Test oder Release) debugCompile
, indem Sie debugCompile
, testCompile
oder releaseCompile
anstelle der üblichen compile
.
Dies ist hilfreich, um Test- und Debug-abhängige Abhängigkeiten von Ihrem Release-Build fernzuhalten, wodurch Ihr Release- APK
so gering wie möglich gehalten wird und sichergestellt wird, dass Debug-Informationen nicht zum Abrufen interner Informationen über Ihre App verwendet werden können.
signingConfig
Mit der signingConfig
können Sie Ihren Gradle so konfigurieren, dass er keystore
Informationen enthält und sicherstellen, dass die mit diesen Konfigurationen erstellten APK signiert und für die Play Store-Veröffentlichung bereit sind.
Hier finden Sie ein eigenes Thema .
Hinweis : Es wird jedoch nicht empfohlen, die Signaturdaten in Ihrer Gradle-Datei zu speichern. Um die signingConfigs
zu entfernen, lassen Sie einfach den signingConfigs
Teil aus.
Sie können sie auf verschiedene Arten angeben:
- Speichern in einer externen Datei
- Speichern Sie sie in Umgebungsvariablen .
Weitere Informationen finden Sie in diesem Thema: Unterzeichnen Sie APK, ohne das Keystore-Kennwort verfügbar zu machen .
Weitere Informationen zu Gradle für Android finden Sie im entsprechenden Gradle-Thema .
Produktgeschmack definieren
Produktvarianten werden in der build.gradle
-Datei innerhalb des android { ... }
Blocks android { ... }
(siehe unten).
...
android {
...
productFlavors {
free {
applicationId "com.example.app.free"
versionName "1.0-free"
}
paid {
applicationId "com.example.app.paid"
versionName "1.0-paid"
}
}
}
Auf diese Weise haben wir jetzt zwei zusätzliche Produktvarianten: free
und paid
. Jeder kann seine spezifische Konfiguration und Attribute haben. Zum Beispiel hat unsere beiden neuen Geschmacksrichtungen einen separaten applicationId
und versionName
als unsere bestehenden main
Geschmack ( als Standard verfügbar sind , so hier nicht dargestellt).
Hinzufügen produktspezifischer Abhängigkeiten
Abhängigkeiten können für eine bestimmte Produktvariante hinzugefügt werden, ähnlich wie sie für bestimmte Build-Konfigurationen hinzugefügt werden können.
Nehmen Sie für dieses Beispiel an, dass wir bereits zwei Produktvarianten definiert haben, die als free
und paid
(mehr zur Definition von Geschmacksrichtungen hier ).
Wir können dann die AdMob-Abhängigkeit für die free
Variante und die Picasso-Bibliothek für die paid
Version hinzufügen:
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'
}
...
Hinzufügen produktspezifischer Ressourcen
Ressourcen können für einen bestimmten Produktgeschmack hinzugefügt werden.
Nehmen Sie für dieses Beispiel an, dass wir bereits zwei Produktvarianten definiert haben, die als free
und paid
. Um produktspezifische Ressourcen hinzuzufügen, erstellen wir neben dem main/res
Ordner weitere Ressourcenordner, die Sie wie üblich hinzufügen können. In diesem Beispiel definieren wir eine Zeichenfolge ( status
) für jede Produktvariante:
/ 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 / bezahlt /res/values/strings.xml
<resources>
<string name="status">Paid</string>
</resources>
Die produktgeschmacksspezifischen status
überschreiben den Wert für den status
im main
.
Definieren und Verwenden von Build-Konfigurationsfeldern
BuildConfigField
Mit Gradle können buildConfigField
mit buildConfigField
Linien Konstanten definieren. Auf diese Konstanten kann während der Laufzeit als statische Felder der BuildConfig
Klasse BuildConfig
. Dies kann zum Erstellen von Flavors verwendet werden, indem alle Felder im defaultConfig
Block definiert und bei Bedarf für einzelne Build-Flavors überschrieben werden.
In diesem Beispiel wird das Erstellungsdatum definiert und der Build für die Produktion und nicht für den Test markiert:
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'
}
}
}
Der automatisch generierte <Paketname>. BuildConfig
.java im Ordner gen enthält folgende Felder, die auf der obigen Anweisung basieren:
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";
}
Die definierten Felder können jetzt zur Laufzeit innerhalb der App verwendet werden, indem auf die generierte BuildConfig
Klasse BuildConfig
:
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
Der resValue
in den productFlavors
erstellt einen Ressourcenwert. Dabei kann es sich um einen beliebigen Ressourcentyp handeln ( string
, dimen
, color
usw.). Dies ist vergleichbar mit dem Definieren einer Ressource in der entsprechenden Datei: z. B. Definieren einer Zeichenfolge in einer Datei strings.xml
. Der Vorteil besteht darin, dass der in Gradle definierte Wert basierend auf Ihrem productFlavor / buildVariant geändert werden kann. Um auf den Wert zuzugreifen, schreiben Sie den gleichen Code, als würden Sie aus der Ressourcendatei auf ein Res zugreifen:
getResources().getString(R.string.app_name)
Das Wichtigste ist, dass auf diese Weise definierte Ressourcen die in Dateien definierten Ressourcen nicht ändern können. Sie können nur neue Ressourcenwerte erstellen.
Einige Bibliotheken (z. B. Google Maps Android API) erfordern einen API-Schlüssel, der im Manifest als meta-data
Tag bereitgestellt wird. Wenn für das Debugging und die Erstellung von Builds andere Schlüssel erforderlich sind, geben Sie einen durch Gradle ausgefüllten Platzhalter für Manifest an.
In Ihrer AndroidManifest.xml
Datei:
<meta-data
android:name="com.google.android.geo.API_KEY"
android:value="${MAPS_API_KEY}"/>
build.gradle
dann das Feld in Ihrer build.gradle
-Datei entsprechend ein:
android {
defaultConfig {
...
// Your development key
manifestPlaceholders = [ MAPS_API_KEY: "AIza..." ]
}
productFlavors {
prod {
// Your production key
manifestPlaceholders = [ MAPS_API_KEY: "AIza..." ]
}
}
}
Das Android-Buildsystem generiert eine Reihe von Feldern automatisch und platziert sie in BuildConfig.java
. Diese Felder sind:
Feld | Beschreibung |
---|---|
DEBUG | Ein Boolean Wert, der angibt, ob sich die App im Debug- oder Freigabemodus befindet |
APPLICATION_ID | einen String mit der ID der Anwendung (zB com.example.app ) |
BUILD_TYPE | ein String , der den Build-Typ der Anwendung enthält (normalerweise debug oder release ) |
FLAVOR | Eine String die den bestimmten Geschmack des Builds enthält |
VERSION_CODE | ein int das die Versionsnummer (Build-Nummer) enthält. Dies ist die gleiche wie versionCode in build.gradle oder versionCode in AndroidManifest.xml |
VERSION_NAME | Ein String , der den Versionsnamen (Build) enthält. Dies ist das gleiche wie versionName in build.gradle oder versionName in AndroidManifest.xml |
Wenn Sie mehrere Flavordimensionen definiert haben, hat jede Dimension ihren eigenen Wert. Wenn Sie zum Beispiel zwei Geschmacksdimensionen für color
und size
Sie auch die folgenden Variablen:
Feld | Beschreibung |
---|---|
FLAVOR_color | eine String die den Wert für den Farbton enthält. |
FLAVOR_size | eine String die den Wert für den 'size'-Flavor enthält. |
Abhängigkeiten über "dependencies.gradle" -Datei zentralisieren
Bei der Arbeit mit Projekten mit mehreren Modulen ist es hilfreich, Abhängigkeiten an einem einzigen Ort zu zentralisieren, anstatt sie auf viele Build-Dateien zu verteilen, insbesondere für gängige Bibliotheken wie die Android-Support-Bibliotheken und die Firebase-Bibliotheken .
Eine empfohlene Methode besteht darin, die Gradle-Build-Dateien mit einem build.gradle
pro Modul sowie einer im Projektstammverzeichnis und einer für die Abhängigkeiten voneinander zu trennen. Beispiel:
root
+- gradleScript/
| dependencies.gradle
+- module1/
| build.gradle
+- module2/
| build.gradle
+- build.gradle
Alle Ihre Abhängigkeiten können sich dann 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}",
];
}
Die kann dann aus dieser Datei in der obersten Datei build.gradle
wie build.gradle
werden:
// Load dependencies
apply from: 'gradleScript/dependencies.gradle'
und in der module1/build.gradle
so:
// Module build file
dependencies {
// ...
compile supportDependencies.appCompat
compile supportDependencies.design
compile firebaseDependencies.crash
}
Ein anderer Ansatz
Ein weniger ausführlicher Ansatz zur Zentralisierung von Bibliotheksabhängigkeitsversionen kann erreicht werden, indem die Versionsnummer einmal als Variable deklariert und überall verwendet wird.
build.gradle
Sie im Arbeitsbereich root build.gradle
hinzu:
ext.v = [
supportVersion:'24.1.1',
]
Fügen Sie in jedem Modul, das dieselbe Bibliothek verwendet, die benötigten Bibliotheken hinzu
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}"
Verzeichnisstruktur für geschmacksspezifische Ressourcen
Verschiedene Arten von Anwendungserstellungen können unterschiedliche Ressourcen enthalten. Um eine Flavour-spezifische Ressource zu erstellen, erstellen Sie im src
Verzeichnis ein Verzeichnis mit dem Kleinbuchstaben Ihrer Flavour und fügen Sie Ihre Ressourcen auf die gleiche Weise hinzu, wie Sie es normalerweise tun würden.
Zum Beispiel hatten , wenn Sie einen Geschmack Development
und wollten ein deutliches Launcher - Symbol dafür zur Verfügung zu stellen Sie ein Verzeichnis erstellen würden src/development/res/drawable-mdpi
und in diesem Verzeichnis eine erstellen ic_launcher.png
Datei mit entwicklungsspezifischen Symbol.
Die Verzeichnisstruktur sieht folgendermaßen aus:
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'
(In diesem Fall würden Sie natürlich auch Symbole für drawable-hdpi, drawable-xhdpi usw. erstellen).
Warum gibt es in einem Android Studio-Projekt zwei build.gradle-Dateien?
<PROJECT_ROOT>\app\build.gradle
ist spezifisch für das App-Modul .
<PROJECT_ROOT>\build.gradle
ist eine "Build-Datei der obersten Ebene", in der Sie Konfigurationsoptionen hinzufügen können, die für alle Unterprojekte / Module gelten.
Wenn Sie ein anderes Modul in Ihrem Projekt verwenden, haben Sie als lokale Bibliothek eine andere Datei build.gradle
: <PROJECT_ROOT>\module\build.gradle
In der Datei der obersten Ebene können Sie allgemeine Eigenschaften als Buildscript-Block oder einige allgemeine Eigenschaften angeben.
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"
}
In app\build.gradle
definieren Sie nur die Eigenschaften für das Modul:
apply plugin: 'com.android.application'
android {
compileSdkVersion rootProject.ext.compileSdkVersion
buildToolsVersion rootProject.ext.buildToolsVersion
}
dependencies {
//.....
}
Ein Shell-Skript von Gradle ausführen
Ein Shellskript ist eine sehr vielseitige Möglichkeit, Ihren Build auf alles zu erweitern, was Sie sich vorstellen können.
Als Beispiel sei hier ein einfaches Skript zum Kompilieren von Protobuf-Dateien und zum Hinzufügen der Ergebnis-Java-Dateien zum Quellverzeichnis für die weitere Kompilierung aufgeführt:
def compilePb() {
exec {
// NOTICE: gradle will fail if there's an error in the protoc file...
executable "../pbScript.sh"
}
}
project.afterEvaluate {
compilePb()
}
Das Shell-Skript 'pbScript.sh' für dieses Beispiel, das sich im Stammordner des Projekts befindet:
#!/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
Debuggen Ihrer Gradle-Fehler
Das Folgende ist ein Auszug aus Gradle - Was ist ein Exit-Wert ungleich Null und wie kann ich ihn beheben? Sehen Sie es für die vollständige Diskussion.
Nehmen wir an, Sie entwickeln eine Anwendung und erhalten einen Gradle-Fehler, der im Allgemeinen so aussieht.
: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
Sie suchen hier auf StackOverflow nach Ihrem Problem, und die Leute sagen, dass Sie Ihr Projekt bereinigen und neu erstellen oder MultiDex aktivieren sollten . Wenn Sie es versuchen, wird das Problem dadurch nicht behoben .
Es gibt Möglichkeiten, mehr Informationen zu erhalten , aber die Gradle-Ausgabe selbst sollte auf den tatsächlichen Fehler in den wenigen Zeilen über dieser Meldung zwischen: module:someTask FAILED
und dem letzten :module:someOtherTask
, die bestanden haben. Wenn Sie also eine Frage zu Ihrem Fehler stellen, bearbeiten Sie Ihre Fragen, um dem Fehler mehr Kontext hinzuzufügen.
Sie erhalten also einen Exit-Wert ungleich Null. Nun, diese Zahl ist ein guter Indikator dafür, was Sie beheben sollten. Hier kommen einige am häufigsten vor.
-
1
ist nur ein allgemeiner Fehlercode und der Fehler ist wahrscheinlich in der Gradle-Ausgabe -
2
scheint mit überlappenden Abhängigkeiten oder falscher Projektkonfiguration zu tun zu haben. -
3
scheint zu viele Abhängigkeiten oder ein Speicherproblem zu haben.
Die allgemeinen Lösungen für das Vorstehende (nach dem Versuch eines Clean and Rebuild des Projekts) sind:
-
1
- Beheben Sie den genannten Fehler. Im Allgemeinen ist dies ein Fehler bei der Kompilierung, was bedeutet, dass ein Teil des Codes in Ihrem Projekt nicht gültig ist. Dies umfasst sowohl XML als auch Java für ein Android-Projekt. -
2
&3
- Viele Antworten geben an, Multidex zu aktivieren. Das Problem kann zwar behoben werden, es ist jedoch höchstwahrscheinlich eine Problemumgehung. Wenn Sie nicht verstehen, warum Sie es verwenden (siehe den Link), benötigen Sie es wahrscheinlich nicht. Bei allgemeinen Lösungen müssen Sie die übermäßige Nutzung von Bibliotheksabhängigkeiten reduzieren (z. B. alle Google Play-Services, wenn Sie nur eine Bibliothek verwenden müssen, wie z. B. Maps oder Anmelden).
Angeben verschiedener Anwendungs-IDs für Buildtypen und Produktvarianten
Sie können für jedes buildType
oder productFlavor
andere Anwendungs-IDs oder Paketnamen productFlavor
indem Sie das Konfigurationsattribut applicationIdSuffix verwenden:
Beispiel für ein Suffix der applicationId
für jeden 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"
}
}
Unsere resultierenden applicationIds
wären jetzt:
- com.package.android zur
release
- com.package.android. dev für die
development
- com.package.android. qa zum
testing
Dies kann auch für productFlavors
werden:
productFlavors {
free {
applicationIdSuffix ".free"
}
paid {
applicationIdSuffix ".paid"
}
}
Die resultierenden applicationIds
wären:
- com.package.android. kostenlos für den
free
Geschmack - com.package.android. für den bezahlten
paid
Geschmack
APK unterzeichnen, ohne das Keystore-Passwort freizulegen
Sie können die Signaturkonfiguration definieren, um die apk in der Datei build.gradle
mit den folgenden Eigenschaften zu signieren:
-
storeFile
: die Keystore-Datei -
storePassword
: das Schlüsselspeicherkennwort -
keyAlias
: ein Aliasname -
keyPassword
: Ein Schlüsselalias-Kennwort
In vielen Fällen müssen Sie diese Art von Informationen in der Datei build.gradle
möglicherweise vermeiden.
Methode A: Konfigurieren Sie die Versionssignatur mit einer Datei keystore.properties
Es ist möglich , Ihre App zu konfigurieren build.gradle
, so dass es Ihre Signatur - Konfigurationsinformationen von einer Eigenschaft wie Datei lesen keystore.properties
.
Das Einrichten einer solchen Unterschrift ist vorteilhaft, weil:
- Die Informationen zur Signierungskonfiguration sind von Ihrer
build.gradle
Datei getrennt - Sie müssen während des Signaturvorgangs nicht eingreifen, um Kennwörter für Ihre Keystore-Datei anzugeben
- Sie können die Datei
keystore.properties
problemlos von der Versionskontrolle ausschließen
Erstellen Sie zunächst eine Datei mit dem Namen keystore.properties
im Stammverzeichnis Ihres Projekts mit folgendem Inhalt (Ersetzen der Werte durch Ihre eigenen):
storeFile=keystore.jks
storePassword=storePassword
keyAlias=keyAlias
keyPassword=keyPassword
build.gradle
den signingConfigs
Block nun in der build.gradle
Datei Ihrer App wie folgt ein:
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']
}
}
}
}
Das ist wirklich alles, aber vergessen Sie nicht, sowohl Ihre Keystore-Datei als auch Ihre keystore.properties
Datei von der Versionskontrolle auszuschließen .
Ein paar Dinge zu beachten:
- Der
storeFile
Pfad in der angegebenenkeystore.properties
Datei sollte zu Ihrer App relativ seinebuild.gradle
Datei. In diesem Beispiel wird davonbuild.gradle
dass sich die Keystore-Datei im selben Verzeichnis wie diebuild.gradle
-Datei der Appbuild.gradle
. - In diesem Beispiel befindet sich die Datei
keystore.properties
im Stammverzeichnis des Projekts. Wenn Sie es an einer anderen StellerootProject.file('keystore.properties')
, müssen Sie den Wert inrootProject.file('keystore.properties')
relativ zum Stammverzeichnis Ihres Projekts inrootProject.file('keystore.properties')
ändern.
Methode B: Mit einer Umgebungsvariablen
Dasselbe kann auch ohne eine Eigenschaftsdatei erreicht werden, wodurch das Passwort schwieriger zu finden ist:
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
}
}
Die Umgebungsvariable "ps"
kann global sein, es ist jedoch sicherer, sie nur der Shell von Android Studio hinzuzufügen.
In Linux kann dies durch Bearbeiten des Desktop Entry
Eintrags von Android Studio erfolgen
Exec=sh -c "export ps=myPassword123 ; /path/to/studio.sh"
Weitere Details finden Sie in diesem Thema .
Versionierung Ihrer Builds über die Datei "version.properties"
Sie können Gradle verwenden, um die Paketversion bei jeder Erstellung automatisch zu erhöhen. Erstellen Sie dazu eine version.properties
Datei in demselben Verzeichnis wie Ihr build.gradle
mit dem folgenden Inhalt:
VERSION_MAJOR=0
VERSION_MINOR=1
VERSION_BUILD=1
(Ändern Sie die Werte für Dur und Minor nach Ihren Wünschen). build.gradle
Sie dann in Ihrem build.gradle
den folgenden Code zum android
Abschnitt hinzu:
// 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)
}
}
Auf die Informationen kann in Java als String BuildConfig.VERSION_NAME
für die vollständige {major}. {Minor}. {Build} BuildConfig.VERSION_CODE
und als Ganzzahl BuildConfig.VERSION_CODE
nur für die Build-Nummer BuildConfig.VERSION_CODE
.
Ändern des Ausgabe-APK-Namens und Hinzufügen des Versionsnamens:
Dies ist der Code zum Ändern des Dateinamens der Ausgabeanwendung (.apk). Der Name kann konfiguriert werden, indem Sie newName
einen anderen Wert 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 + "]");
}
}
}
Deaktivieren Sie die Bildkomprimierung für eine kleinere APK-Dateigröße
Wenn Sie alle Bilder manuell optimieren, deaktivieren Sie APT Cruncher für eine kleinere APK-Dateigröße.
android {
aaptOptions {
cruncherEnabled = false
}
}
Aktivieren Sie Proguard mit Gradle
Um die Proguard-Konfigurationen für Ihre Anwendung zu aktivieren, müssen Sie sie in der Gradle-Datei auf Modulebene aktivieren. Sie müssen den Wert von minifyEnabled
auf true
.
buildTypes {
release {
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
Mit dem obigen Code werden Ihre Proguard-Konfigurationen, die im Standard-Android-SDK in Kombination mit der Datei "proguard-rules.pro" in Ihrem Modul enthalten sind, auf Ihre freigegebene apk-Datei angewendet.
Aktivieren Sie die experimentelle Unterstützung für das NDK-Plugin für Gradle und AndroidStudio
Aktivieren und konfigurieren Sie das experimentelle Gradle-Plugin, um die NDK-Unterstützung von AndroidStudio zu verbessern. Stellen Sie sicher, dass Sie die folgenden Anforderungen erfüllen:
- Gradle 2.10 (für dieses Beispiel)
- Android NDK R10 oder höher
- Android SDK mit Build-Tools v19.0.0 oder höher
Konfigurieren Sie die Datei MyApp / build.gradle
Bearbeiten Sie die Zeile dependencies.classpath in build.gradle von zB
classpath 'com.android.tools.build:gradle:2.1.2'
zu
classpath 'com.android.tools.build:gradle-experimental:0.7.2'
(v0.7.2 war zum Zeitpunkt des Schreibens die neueste Version. Prüfen Sie die aktuelle Version selbst und passen Sie Ihre Zeile entsprechend an.)
Die build.gradle-Datei sollte folgendermaßen aussehen:
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle-experimental:0.7.2'
}
}
allprojects {
repositories {
jcenter()
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
Konfigurieren Sie die Datei MyApp / app / build.gradle
Bearbeiten Sie die Datei build.gradle so, dass sie dem folgenden Beispiel ähnelt. Ihre Versionsnummern können anders aussehen.
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'])
}
Synchronisieren Sie und überprüfen Sie, ob die Gradle-Dateien fehlerfrei sind, bevor Sie fortfahren.
Testen Sie, ob das Plugin aktiviert ist
Stellen Sie zunächst sicher, dass Sie das Android NDK-Modul heruntergeladen haben. Erstellen Sie dann eine neue App in AndroidStudio und fügen Sie der ActivityMain-Datei Folgendes hinzu:
public class MainActivity implements Activity {
onCreate() {
// Pregenerated code. Not important here
}
static {
System.loadLibrary("myLib");
}
public static native String getString();
}
Der getString()
Teil sollte rot hervorgehoben werden, um getString()
, dass die entsprechende JNI-Funktion nicht gefunden werden konnte. Bewegen Sie die Maus über den Funktionsaufruf, bis eine rote Glühbirne erscheint. Klicken Sie auf die Birne und wählen Sie create function JNI_...
. Dies sollte eine myLib.c-Datei im Verzeichnis myApp / app / src / main / jni mit dem richtigen JNI-Funktionsaufruf generieren. Es sollte ähnlich aussehen:
#include <jni.h>
JNIEXPORT jstring JNICALL
Java_com_example_mydomain_myapp_MainActivity_getString(JNIEnv *env, jobject instance)
{
// TODO
return (*env)->NewStringUTF(env, returnValue);
}
Wenn es nicht so aussieht, wurde das Plugin nicht richtig konfiguriert oder der NDK wurde nicht heruntergeladen
Zeige alle gradle Projektaufgaben
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
Löschen Sie "nicht ausgerichtet" automatisch
Wenn Sie keine automatisch generierten APK-Dateien mit unaligned
Suffix benötigen (was Sie wahrscheinlich nicht tun), können Sie den folgenden Code zur build.gradle
Datei 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()
}
}
}
}
Von hier aus
Build-Variante ignorieren
Aus einigen Gründen möchten Sie möglicherweise Ihre Build-Varianten ignorieren. Zum Beispiel: Sie haben ein "Mock" -Produktaroma und verwenden es nur für Debugging-Zwecke, wie z. B. Unit- / Instrumentationstests.
Lassen Sie uns die mockRelease- Variante aus unserem Projekt ignorieren. Öffnen Sie die Datei build.gradle und schreiben Sie:
// 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);
}
}
Abhängigkeitsbaum sehen
Verwenden Sie die Aufgabenabhängigkeiten. Abhängig davon, wie Ihre Module eingerichtet sind, kann es sich entweder um ./gradlew dependencies
oder um die Abhängigkeiten der Modul-App zu sehen ./gradlew :app:dependencies
Das Beispiel folgt der build.gradle -Datei
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'
}
erzeugt die folgende Grafik:
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 (*)
. . .
Hier können Sie sehen, dass das Projekt direkt com.android.support:design
Version 23.2.1 enthält, das selbst com.android.support:support-v4
mit Version 23.2.1 enthält. com.google.android.gms:play-services
selbst hängt jedoch von derselben support-v4
Version support-v4
jedoch von einer älteren Version 21.0.0, die von gradle erkannt wird.
(*)
werden verwendet, wenn Gradle den Teilbaum überspringt, da diese Abhängigkeiten bereits zuvor aufgeführt wurden.
Verwenden Sie gradle.properties für zentrale Versionsnummern- / Buildkonfigurationen
Sie können zentrale Konfigurationsinformationen in definieren
- eine separate gradle include-Datei Zentralisierung von Abhängigkeiten über die Datei "dependencies.gradle"
- eine eigenständige Eigenschaftendatei Versionierung Ihrer Builds über die Datei "version.properties"
oder machen Sie es mit der root gradle.properties
Datei
die Projektstruktur
root
+- module1/
| build.gradle
+- module2/
| build.gradle
+- build.gradle
+- gradle.properties
globale Einstellung für alle Submodule 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
Verwendung in einem Submodul
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 {
...
}
Hinweis: Wenn Sie Ihre App im F-Droid App Store veröffentlichen möchten, müssen Sie in der Gradle-Datei magische Zahlen verwenden, da der f-Droid-Roboter die aktuelle Versionsnummer nicht lesen kann, um Versionsänderungen zu erkennen / zu überprüfen.
Signaturinformationen anzeigen
Unter bestimmten Umständen (z. B. beim Erwerb eines Google-API-Schlüssels) müssen Sie den Fingerabdruck Ihres Keystores ermitteln. Gradle hat eine praktische Aufgabe, die alle Signaturinformationen einschließlich der Fingerabdrücke des Keystores anzeigt:
./gradlew signingReport
Dies ist eine Beispielausgabe:
: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
----------
Build-Typen definieren
Sie können Build-Typen in der build.gradle
Datei auf build.gradle
im android {}
-Block erstellen und konfigurieren.
android { ... defaultConfig {...} buildTypes { release { minifyEnabled true proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } debug { applicationIdSuffix ".debug" } } }