Android
Gradle voor Android
Zoeken…
Invoering
Gradle is een JVM-gebaseerd buildsysteem waarmee ontwikkelaars scripts op hoog niveau kunnen schrijven die kunnen worden gebruikt om het compilatie- en applicatieproces te automatiseren. Het is een flexibel, op plug-ins gebaseerd systeem, waarmee u verschillende aspecten van het bouwproces kunt automatiseren; inclusief het compileren en ondertekenen van een .jar
, downloaden en beheren van externe afhankelijkheden, invoegen van velden in het AndroidManifest
of het gebruik van specifieke SDK-versies.
Syntaxis
apply plugin
: de plug-ins die normaal gesproken alleen'com.android.application'
of'com.android.library'
zouden moeten worden gebruikt.android
: de hoofdconfiguratie van uw app-
compileSdkVersion
: de compileer SDK-versie -
buildToolsVersion
: de versie vanbuildToolsVersion
-
defaultConfig
: de standaardinstellingen die kunnen worden overschreven door smaken endefaultConfig
-
applicationId
: de applicatie-ID die u bijvoorbeeld in de PlayStore gebruikt, is meestal dezelfde als uw pakketnaam -
minSdkVersion
: de minimaal vereiste SDK-versie -
targetSdkVersion
: De SDK-versie waarmee u compileert (moet altijd de nieuwste zijn) -
versionCode
: Het interne versienummer dat bij elke update groter moet zijn -
versionName
: het versienummer dat de gebruiker kan zien op de pagina met app-details
-
-
buildTypes
: Zie ergens anders (TODO)
-
dependencies
: de maven of lokale afhankelijkheden van uw app-
compile
een enkele afhankelijkheid -
testCompile
: een afhankelijkheid voor de unit- of integratietests
-
Opmerkingen
Zie ook
- De officiële gradle-startpagina
- Hoe gradle-builds te configureren
- De Android-plug-in voor gradle
- Android Gradle DSL
Gradle voor Android - Uitgebreide documentatie:
Er is nog een tag waar je meer onderwerpen en voorbeelden kunt vinden over het gebruik van gradle in Android.
http://www.riptutorial.com/topic/2092
Een eenvoudig build.gradle-bestand
Dit is een voorbeeld van een standaardbestand build.gradle
in een module.
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 (domeinspecifieke taal)
Elk blok in het bovenstaande bestand wordt een DSL
(domeinspecifieke taal) genoemd.
plugins
De eerste regel, apply plugin: 'com.android.application'
, past de Android-plug-in voor Gradle toe op de build en stelt het android {}
-blok beschikbaar om Android-specifieke build-opties te declareren.
Voor een Android-applicatie :
apply plugin: 'com.android.application'
Voor een Android-bibliotheek :
apply plugin: 'com.android.library'
Inzicht in de DSL's in het bovenstaande voorbeeld
Het tweede deel, het android {...}
-blok, is de Android DSL
die informatie over uw project bevat.
U kunt bijvoorbeeld de compileSdkVersion
die het Android API-niveau specificeert, dat door compileSdkVersion
moet worden gebruikt om uw app te compileren.
Het defaultConfig
bevat de standaardwaarden voor uw manifest. Je kunt ze override
met productaroma's .
U vindt meer info in deze voorbeelden:
afhankelijkheden
Het dependencies
wordt buiten het android
blok {...}
gedefinieerd: dit betekent dat het niet door de Android-plug-in wordt gedefinieerd, maar standaard Gradle is.
Het dependencies
geeft aan welke externe bibliotheken (meestal Android-bibliotheken, maar Java-bibliotheken ook geldig zijn) die u in uw app wilt opnemen. Gradle downloadt automatisch deze afhankelijkheden voor u (als er geen lokale kopie beschikbaar is), u hoeft alleen vergelijkbare compile
toe te voegen wanneer u nog een bibliotheek wilt toevoegen.
Laten we eens kijken naar een van de hier aanwezige regels:
compile 'com.android.support:design:25.3.1'
Deze regel zegt eigenlijk
een afhankelijkheid van de Android-ondersteuningsontwerpbibliotheek toevoegen aan mijn project.
Gradle zorgt ervoor dat de bibliotheek wordt gedownload en gepresenteerd, zodat u deze in uw app kunt gebruiken, en de code wordt ook opgenomen in uw app.
Als u bekend bent met Maven, is deze syntaxis de GroupId , een dubbele punt, ArtifactId , een andere dubbele punt, dan de versie van de afhankelijkheid die u wilt opnemen, waardoor u volledige controle hebt over versiebeheer.
Hoewel het mogelijk is om artefactversies op te geven met behulp van het plusteken (+), kunt u dit het beste vermijden; het kan tot problemen leiden als de bibliotheek zonder uw medeweten wordt bijgewerkt met het doorbreken van wijzigingen, wat waarschijnlijk zou leiden tot crashes in uw app.
U kunt verschillende soorten afhankelijkheden toevoegen:
Bijzondere aandacht moet worden besteed aan de aar flat afhankelijkheden .
U vindt meer informatie in dit onderwerp.
Opmerking over de -v7 in appcompat-v7
compile 'com.android.support:appcompat-v7:25.3.1'
Dit betekent eenvoudig dat deze bibliotheek ( appcompat
) compatibel is met Android API niveau 7 en hoger.
Opmerking over de junit: junit: 4.12
Dit is het testen van afhankelijkheid voor het testen van eenheden.
Specifieke afhankelijkheden opgeven voor verschillende buildconfiguraties
U kunt opgeven dat een afhankelijkheid alleen mag worden gebruikt voor een bepaalde build configuratie of kunt u verschillende afhankelijkheden definiëren voor de types te bouwen of het product smaken (bv debuggen, testen of release) door gebruik te maken debugCompile
, testCompile
of releaseCompile
plaats van de gebruikelijke compile
.
Dit is handig om test- en debuggerelateerde afhankelijkheden uit uw release-build te houden, waardoor uw release- APK
zo dun mogelijk blijft en ervoor zorgt dat eventuele foutopsporingsinformatie niet kan worden gebruikt om interne informatie over uw app te verkrijgen.
signingConfig
Met signingConfig
kunt u uw signingConfig
configureren om keystore
informatie op te nemen en ervoor te zorgen dat de APK die met deze configuraties is gebouwd, is ondertekend en klaar is voor Play Store-release.
Hier kunt u een specifiek onderwerp vinden .
Opmerking : het wordt echter niet aanbevolen om de inloggegevens in uw Gradle-bestand te bewaren. Als u de ondertekeningsconfiguraties wilt verwijderen, laat u het gedeelte signingConfigs
gewoon weg.
U kunt ze op verschillende manieren opgeven:
- opslaan in een extern bestand
- opslaan in omgevingsvariabelen instellen .
Zie dit onderwerp voor meer informatie: APK ondertekenen zonder keystore-wachtwoord bloot te leggen .
Meer informatie over Gradle voor Android vindt u in het speciale Gradle-onderwerp .
Productaroma's definiëren
Productaroma's worden gedefinieerd in het build.gradle
bestand in het android { ... }
-blok zoals hieronder te zien.
...
android {
...
productFlavors {
free {
applicationId "com.example.app.free"
versionName "1.0-free"
}
paid {
applicationId "com.example.app.paid"
versionName "1.0-paid"
}
}
}
Door dit te doen, hebben we nu twee extra productsmaken: free
en paid
. Elk kan zijn eigen specifieke configuratie en attributen hebben. Bijvoorbeeld, zowel van onze nieuwe smaken heeft een aparte applicationId
en versionName
dan onze bestaande main
smaak (standaard beschikbaar, dus hier niet afgebeeld).
Productspecifieke afhankelijkheden toevoegen
Afhankelijkheden kunnen worden toegevoegd voor een specifieke productsmaak , vergelijkbaar met hoe deze kunnen worden toegevoegd voor specifieke buildconfiguraties.
Neem in dit voorbeeld aan dat we al twee productaroma's hebben gedefinieerd die free
en paid
(meer over het definiëren van smaken hier ).
We kunnen vervolgens de AdMob-afhankelijkheid voor de free
smaak toevoegen, en de Picasso-bibliotheek voor de paid
smaak als volgt:
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'
}
...
Productspecifieke middelen toevoegen
Bronnen kunnen worden toegevoegd voor een specifieke productsmaak .
Neem in dit voorbeeld aan dat we al twee productsmaken hebben gedefinieerd: free
en paid
. Om aromaspecifieke bronnen voor producten toe te voegen, maken we extra bronmappen naast de hoofdmap main/res
map, waaraan we vervolgens zoals gewoonlijk bronnen kunnen toevoegen. Voor dit voorbeeld definiëren we een tekenreeks, status
, voor elke productsmaak:
/ 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>
De productsmaak specifieke status
tekenreeksen de waarde overschrijven status
in de main
smaak.
Definieer en gebruik Build Configuration Fields
BuildConfigField
Met buildConfigField
kunnen buildConfigField
lijnen constanten definiëren. Deze constanten zijn tijdens runtime toegankelijk als statische velden van de klasse BuildConfig
. Dit kan worden gebruikt om smaken te maken door alle velden in het defaultConfig
blok te definiëren en ze naar behoefte te vervangen voor individuele build-smaken.
Dit voorbeeld definieert de builddatum en markeert de build voor productie in plaats van 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'
}
}
}
De automatisch gegenereerde <pakketnaam>. BuildConfig
.java in de map gen bevat de volgende velden op basis van de bovenstaande instructie:
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";
}
De gedefinieerde velden kunnen nu tijdens runtime in de app worden gebruikt door toegang te krijgen tot de gegenereerde BuildConfig
klasse:
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
De resValue
in de productFlavors
creëert een resource-waarde. Het kan elk type resource zijn ( string
, dimen
, color
, etc.). Dit is vergelijkbaar met het definiëren van een bron in het juiste bestand: bijvoorbeeld het definiëren van tekenreeksen in een bestand strings.xml
. Het voordeel is dat degene die in gradle is gedefinieerd, kan worden aangepast op basis van uw productFlavour / buildVariant. Om toegang te krijgen tot de waarde, schrijft u dezelfde code alsof u toegang hebt tot een onderzoek uit het bronnenbestand:
getResources().getString(R.string.app_name)
Het belangrijkste is dat bronnen die op deze manier zijn gedefinieerd, bestaande bronnen die in bestanden zijn gedefinieerd niet kunnen wijzigen. Ze kunnen alleen nieuwe bronwaarden maken.
Sommige bibliotheken (zoals de Google Maps Android API) vereisen een API-sleutel die in het Manifest wordt verstrekt als een meta-data
. Als verschillende sleutels nodig zijn voor foutopsporing en productiebuilds, geeft u een manifestplaatsaanduiding op die is ingevuld door Gradle.
In uw AndroidManifest.xml
bestand:
<meta-data
android:name="com.google.android.geo.API_KEY"
android:value="${MAPS_API_KEY}"/>
En stel vervolgens het veld dienovereenkomstig in in uw build.gradle
bestand:
android {
defaultConfig {
...
// Your development key
manifestPlaceholders = [ MAPS_API_KEY: "AIza..." ]
}
productFlavors {
prod {
// Your production key
manifestPlaceholders = [ MAPS_API_KEY: "AIza..." ]
}
}
}
Het Android- BuildConfig.java
genereert automatisch een aantal velden en plaatst deze in BuildConfig.java
. Deze velden zijn:
Veld | Beschrijving |
---|---|
DEBUG | een Boolean waarin wordt vermeld of de app in de foutopsporings- of releasemodus staat |
APPLICATION_ID | een String die de ID van de toepassing bevat (bijvoorbeeld com.example.app ) |
BUILD_TYPE | een String die het buildtype van de toepassing bevat (meestal debug of release ) |
FLAVOR | een String die de specifieke smaak van de build bevat |
VERSION_CODE | een int met het versienummer (build). Dit is hetzelfde als versionCode in build.gradle of versionCode in AndroidManifest.xml |
VERSION_NAME | een String die de versie (build) naam bevat. Dit is hetzelfde als versionName in build.gradle of versionName in AndroidManifest.xml |
Als u naast het bovenstaande meerdere dimensies van smaak hebt gedefinieerd, heeft elke dimensie zijn eigen waarde. Als u bijvoorbeeld twee smaakdimensies voor color
en size
hebt u ook de volgende variabelen:
Veld | Beschrijving |
---|---|
FLAVOR_color | een String met de waarde voor de smaak 'kleur'. |
FLAVOR_size | een String met de waarde voor de smaak 'grootte'. |
Centralisatie van afhankelijkheden via het bestand "dependencies.gradle"
Wanneer u met multimodule-projecten werkt, is het handig om afhankelijkheden op één locatie te centraliseren in plaats van ze over meerdere buildbestanden te verspreiden, vooral voor veelgebruikte bibliotheken zoals de Android-ondersteuningsbibliotheken en de Firebase-bibliotheken .
Een aanbevolen manier is om de build.gradle
te scheiden, met één build.gradle
per module, evenals een in de project root en een andere voor de afhankelijkheden, bijvoorbeeld:
root
+- gradleScript/
| dependencies.gradle
+- module1/
| build.gradle
+- module2/
| build.gradle
+- build.gradle
Vervolgens kunnen al uw afhankelijkheden zich bevinden 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}",
];
}
Dat kan vervolgens worden toegepast vanuit dat bestand in het bestand build.gradle
op het hoogste niveau:
// Load dependencies
apply from: 'gradleScript/dependencies.gradle'
en in de module1/build.gradle
als volgt:
// Module build file
dependencies {
// ...
compile supportDependencies.appCompat
compile supportDependencies.design
compile firebaseDependencies.crash
}
Een andere benadering
Een minder uitgebreide benadering voor het centraliseren van versies van bibliotheekafhankelijkheid kan worden bereikt door het versienummer eenmaal als variabele te declareren en overal te gebruiken.
Voeg in de werkruimte root build.gradle
dit toe:
ext.v = [
supportVersion:'24.1.1',
]
En voeg in elke module die dezelfde bibliotheek gebruikt de benodigde bibliotheken toe
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}"
Directorystructuur voor smaakspecifieke bronnen
Verschillende smaken van applicatie-builds kunnen verschillende bronnen bevatten. Om een smaakspecifieke bron te maken, maakt u een map met de kleine letter van uw smaak in de map src
en voegt u uw bronnen op dezelfde manier toe als u normaal zou doen.
Bijvoorbeeld, als je had een smaak Development
en wilde een duidelijke launcher icoon voor het zou een map aan te maken bieden src/development/res/drawable-mdpi
en in die map aan te maken een ic_launcher.png
bestand met je ontwikkeling-specifiek pictogram.
De mapstructuur ziet er als volgt uit:
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'
(Natuurlijk zou u in dit geval ook pictogrammen maken voor drawable-hdpi, drawable-xhdpi enz. ).
Waarom zijn er twee build.gradle-bestanden in een Android Studio-project?
<PROJECT_ROOT>\app\build.gradle
is specifiek voor app-module .
<PROJECT_ROOT>\build.gradle
is een "Top-level build-bestand" waar u configuratie-opties kunt toevoegen die gemeenschappelijk zijn voor alle subprojecten / modules.
Als u een andere module in uw project gebruikt, zou u als lokale bibliotheek een ander build.gradle
bestand hebben: <PROJECT_ROOT>\module\build.gradle
In het hoofdbestand kunt u algemene eigenschappen opgeven als het buildscript-blok of enkele algemene eigenschappen.
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 de app\build.gradle
definieert u alleen de eigenschappen voor de module:
apply plugin: 'com.android.application'
android {
compileSdkVersion rootProject.ext.compileSdkVersion
buildToolsVersion rootProject.ext.buildToolsVersion
}
dependencies {
//.....
}
Een shellscript uitvoeren vanuit Gradle
Een shellscript is een zeer veelzijdige manier om je build uit te breiden tot vrijwel alles wat je maar kunt bedenken.
Als een voorbeeld is hier een eenvoudig script om protobuf-bestanden te compileren en de java-bestanden van de resultaten toe te voegen aan de bronmap voor verdere compilatie:
def compilePb() {
exec {
// NOTICE: gradle will fail if there's an error in the protoc file...
executable "../pbScript.sh"
}
}
project.afterEvaluate {
compilePb()
}
Het shellscript 'pbScript.sh' voor dit voorbeeld bevindt zich in de hoofdmap van het project:
#!/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
Foutopsporing van uw Gradle-fouten
Het volgende is een fragment uit Gradle - Wat is een exitwaarde die niet nul is en hoe kan ik deze oplossen? , zie het voor de volledige discussie.
Laten we zeggen dat u een applicatie ontwikkelt en dat u een Gradle-fout krijgt die lijkt en die er in het algemeen zo uitziet.
: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
U zoekt hier in StackOverflow naar uw probleem, en mensen zeggen dat u uw project moet opschonen en opnieuw opbouwen, of MultiDex moet inschakelen, en wanneer u dat probeert, lost het gewoon het probleem niet op.
Er zijn manieren om meer informatie te krijgen , maar de uitvoer van Gradle zelf moet wijzen op de werkelijke fout in de paar regels boven dat bericht tussen: module:someTask FAILED
en de laatste :module:someOtherTask
die is geslaagd. Daarom, als u een vraag over uw fout stelt, moet u uw vragen bewerken om meer context aan de fout toe te voegen.
U krijgt dus een 'niet-nul exit-waarde'. Welnu, dat aantal is een goede indicatie van wat u moet proberen op te lossen. Hier zijn er een paar die het meest voorkomen.
-
1
is slechts een algemene foutcode en de fout is waarschijnlijk in de uitvoer Gradle -
2
lijkt verband te houden met overlappende afhankelijkheden of projectconfiguratie. -
3
lijkt afkomstig te zijn van teveel afhankelijkheden, of een geheugenprobleem.
De algemene oplossingen voor het bovenstaande (na een poging tot opschonen en opnieuw opbouwen van het project) zijn:
-
1
- Los de genoemde fout op. Over het algemeen is dit een compilatiefout, wat betekent dat een stukje code in uw project niet geldig is. Dit omvat zowel XML als Java voor een Android-project. -
2
&3
- Veel antwoorden hier vertellen u dat u multidex moet inschakelen. Hoewel het het probleem kan oplossen, is het waarschijnlijk een oplossing. Als je niet begrijpt waarom je het gebruikt (zie de link), heb je het waarschijnlijk niet nodig. Algemene oplossingen omvatten het terugdringen van uw overmatig gebruik van bibliotheekafhankelijkheid (zoals alle Google Play-services, wanneer u slechts één bibliotheek hoeft te gebruiken, zoals Maps of Sign-In, bijvoorbeeld).
Verschillende toepassings-ID's opgeven voor buildtypen en productaroma's
U kunt verschillende applicatie-ID's of pakketnamen voor elk buildType
of productFlavor
met behulp van het configuratie-kenmerk applicationIdSuffix :
Voorbeeld van het achtervoegsel van de applicationId
voor elk 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"
}
}
Onze resulterende applicationIds
ID applicationIds
zouden nu zijn:
- com.package.android voor
release
- com.package.android. dev voor
development
- com.package.android. qa voor
testing
Dit kan ook worden gedaan voor productFlavors
:
productFlavors {
free {
applicationIdSuffix ".free"
}
paid {
applicationIdSuffix ".paid"
}
}
De resulterende applicationIds
ID applicationIds
zouden zijn:
- com.package.android. gratis voor de
free
smaak - com.package.android. betaald voor de
paid
smaak
Onderteken APK zonder het wachtwoord van de sleutelopslag bloot te leggen
U kunt de ondertekeningsconfiguratie definiëren om de apk in het bestand build.gradle
te ondertekenen met behulp van deze eigenschappen:
-
storeFile
: het keystore-bestand -
storePassword
: het sleutelarchiefwachtwoord -
keyAlias
: een belangrijke aliasnaam -
keyPassword
: een key alias-wachtwoord
In veel gevallen moet u dit soort informatie in het bestand build.gradle
.
Methode A: Configureer vrijgave ondertekenen met behulp van een bestand keystore.properties
Het is mogelijk om de build.gradle
uw app zo te configureren dat deze uw ondertekeningsconfiguratiegegevens leest uit een eigenschappenbestand zoals keystore.properties
.
Zo instellen is voordelig omdat:
- De configuratie-informatie van uw ondertekening staat los van uw
build.gradle
bestand - U hoeft niet in te grijpen tijdens het ondertekeningsproces om wachtwoorden voor uw keystore-bestand op te geven
- U kunt het bestand
keystore.properties
eenvoudig uitsluiten van versiebeheer
Maak eerst een bestand met de naam keystore.properties
in de root van uw project met inhoud zoals deze (vervang de waarden door die van uzelf):
storeFile=keystore.jks
storePassword=storePassword
keyAlias=keyAlias
keyPassword=keyPassword
Stel nu in het build.gradle
bestand van uw app het blok signingConfigs
als volgt in:
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']
}
}
}
}
Dat is echt alles, maar vergeet niet zowel uw keystore-bestand als uw keystore.properties
bestand uit te sluiten van versiebeheer .
Een paar dingen om op te merken:
- Het
storeFile
pad dat is opgegeven in het bestandkeystore.properties
moet relatief zijn ten opzichte van hetbuild.gradle
bestand van uw app. In dit voorbeeld wordt ervan uitgegaan dat het keystore-bestand zich in dezelfde map bevindt als hetbuild.gradle
bestand van de app. - Dit voorbeeld heeft het bestand
keystore.properties
in de root van het project. Als u het ergens anders plaatst, moet u de waarde inrootProject.file('keystore.properties')
in de locatie van uw, ten opzichte van de root van uw project.
Methode B: Door een omgevingsvariabele te gebruiken
Hetzelfde kan ook worden bereikt zonder een eigenschappenbestand, waardoor het wachtwoord moeilijker te vinden is:
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
}
}
De omgevingsvariabele "ps"
kan globaal zijn, maar een veiligere aanpak kan zijn door deze alleen aan de shell van Android Studio toe te voegen.
In Linux kan dit worden gedaan door de Desktop Entry
Android Studio te bewerken
Exec=sh -c "export ps=myPassword123 ; /path/to/studio.sh"
U vindt meer informatie in dit onderwerp .
Versiebeheer van uw builds via het bestand "version.properties"
U kunt Gradle gebruiken om uw pakketversie automatisch te verhogen telkens wanneer u deze bouwt. Maak hiervoor een version.properties
bestand in dezelfde map als uw build.gradle
met de volgende inhoud:
VERSION_MAJOR=0
VERSION_MINOR=1
VERSION_BUILD=1
(Naar eigen inzicht de waarden voor majeur en mineur wijzigen). Voeg vervolgens in je build.gradle
de volgende code toe aan het android
gedeelte:
// 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)
}
}
De informatie is toegankelijk in Java als een string BuildConfig.VERSION_NAME
voor het volledige {major}. {Minor}. {Build} nummer en als een geheel getal BuildConfig.VERSION_CODE
voor alleen het buildnummer.
Naam van output-apk wijzigen en versienaam toevoegen:
Dit is de code voor het wijzigen van de bestandsnaam van de uitvoertoepassing (.apk). De naam kan worden geconfigureerd door een andere waarde toe te newName
aan 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 + "]");
}
}
}
Schakel beeldcompressie uit voor een kleinere APK-bestandsgrootte
Als u alle afbeeldingen handmatig optimaliseert, schakelt u APT Cruncher uit voor een kleinere APK-bestandsgrootte.
android {
aaptOptions {
cruncherEnabled = false
}
}
Schakel Proguard in met behulp van gradle
Om Proguard-configuraties voor uw toepassing in te schakelen, moet u deze inschakelen in uw gradle-bestand op moduleniveau. U moet de waarde van minifyEnabled
op true
.
buildTypes {
release {
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
De bovenstaande code past uw Proguard-configuraties in de standaard Android SDK in combinatie met het bestand "proguard-rules.pro" op uw module toe op uw vrijgegeven apk.
Schakel experimentele NDK-plug-inondersteuning in voor Gradle en AndroidStudio
Schakel de experimentele Gradle-plug-in in en configureer deze om de NDK-ondersteuning van AndroidStudio te verbeteren. Controleer of u aan de volgende vereisten voldoet:
- Gradle 2.10 (voor dit voorbeeld)
- Android NDK r10 of hoger
- Android SDK met build tools v19.0.0 of hoger
Configureer het bestand MyApp / build.gradle
Bewerk de dependencies.classpath-regel in build.gradle van bijv
classpath 'com.android.tools.build:gradle:2.1.2'
naar
classpath 'com.android.tools.build:gradle-experimental:0.7.2'
(v0.7.2 was de nieuwste versie op het moment van schrijven. Controleer zelf de nieuwste versie en pas uw regel dienovereenkomstig aan)
Het bestand build.gradle zou er ongeveer zo uit moeten zien:
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle-experimental:0.7.2'
}
}
allprojects {
repositories {
jcenter()
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
Configureer het bestand MyApp / app / build.gradle
Bewerk het bestand build.gradle zodat het lijkt op het volgende voorbeeld. Uw versienummers kunnen er anders uitzien.
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'])
}
Synchroniseer en controleer of er geen fouten zijn in de Gradle-bestanden voordat u doorgaat.
Test of plug-in is ingeschakeld
Zorg er eerst voor dat je de Android NDK-module hebt gedownload. Maak vervolgens een nieuwe app in AndroidStudio en voeg het volgende toe aan het ActivityMain-bestand:
public class MainActivity implements Activity {
onCreate() {
// Pregenerated code. Not important here
}
static {
System.loadLibrary("myLib");
}
public static native String getString();
}
Het gedeelte getString()
moet rood worden gemarkeerd om aan te geven dat de bijbehorende JNI-functie niet is gevonden. Beweeg uw muis over de functieaanroep totdat een rode gloeilamp verschijnt. Klik op de lamp en selecteer create function JNI_...
Dit zou een myLib.c-bestand moeten genereren in de map myApp / app / src / main / jni met de juiste JNI-functie-aanroep. Het zou er ongeveer zo uit moeten zien:
#include <jni.h>
JNIEXPORT jstring JNICALL
Java_com_example_mydomain_myapp_MainActivity_getString(JNIEnv *env, jobject instance)
{
// TODO
return (*env)->NewStringUTF(env, returnValue);
}
Als het er niet zo uitziet, is de plug-in niet correct geconfigureerd of is de NDK niet gedownload
Toon alle gradle-projecttaken
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
Verwijder "niet-uitgelijnd" apk automatisch
Als u niet automatisch gegenereerde apk-bestanden met unaligned
achtervoegsel nodig hebt (wat u waarschijnlijk niet doet), kunt u de volgende code toevoegen aan het bestand 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()
}
}
}
}
Vanaf hier
Negeren van bouwvariant
Om sommige redenen wilt u misschien uw build-varianten negeren. Bijvoorbeeld: u hebt een 'nep' productsmaak en u gebruikt deze alleen voor foutopsporingsdoeleinden, zoals eenheids- / instrumentatietests.
Laten we de mockRelease- variant uit ons project negeren. Open het build.gradle- bestand en schrijf:
// 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);
}
}
Afhankelijkheidsboom zien
Gebruik de taakafhankelijkheden. Afhankelijk van hoe uw modules zijn ingesteld, kan het zijn ./gradlew dependencies
of om de afhankelijkheden van het gebruik van de module-app te zien ./gradlew :app:dependencies
Het voorbeeld na het build.gradle-bestand
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'
}
zal de volgende grafiek produceren:
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 kunt u zien dat het project direct com.android.support:design
versie 23.2.1 bevat, die zelf com.android.support:support-v4
met versie 23.2.1 brengt. com.google.android.gms:play-services
zelf is echter afhankelijk van dezelfde support-v4
maar met een oudere versie 21.0.0, een conflict dat door gradle wordt gedetecteerd.
(*)
worden gebruikt wanneer gradle de substructuur overslaat omdat die afhankelijkheden al eerder werden vermeld.
Gebruik gradle.properties voor centrale versienummer / buildconfiguraties
U kunt centrale configuratiegegevens definiëren in
- een apart gradle include-bestand Centraliseren van afhankelijkheden via het bestand "dependencies.gradle"
- een stand-alone eigenschappenbestand Versiebeheer van uw builds via het bestand "version.properties"
of doe het met root gradle.properties
bestand
de projectstructuur
root
+- module1/
| build.gradle
+- module2/
| build.gradle
+- build.gradle
+- gradle.properties
algemene instelling voor alle submodules 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
gebruik in een submodule
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 {
...
}
Opmerking: als u uw app in de F-Droid app store wilt publiceren, moet u magische getallen in het gradle-bestand gebruiken, omdat f-droid robot anders de huidige versienummer niet kan lezen om versiewijzigingen te detecteren / verifiëren.
Toon ondertekeningsinformatie
In sommige omstandigheden (bijvoorbeeld het verkrijgen van een Google API-sleutel) moet u de sleutelafdruk van uw sleutelarchief vinden. Gradle heeft een handige taak die alle ondertekeningsinformatie weergeeft, inclusief keystore-vingerafdrukken:
./gradlew signingReport
Dit is een voorbeelduitvoer:
: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 definiëren
U kunt configureren maken en types te bouwen in de module-niveau build.gradle
bestand in de android {}
block.
android { ... defaultConfig {...} buildTypes { release { minifyEnabled true proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } debug { applicationIdSuffix ".debug" } } }