Android
Gradle na Androida
Szukaj…
Wprowadzenie
Gradle to oparty na JVM system kompilacji, który umożliwia programistom pisanie skryptów wysokiego poziomu, których można użyć do automatyzacji procesu kompilacji i produkcji aplikacji. Jest to elastyczny system oparty na wtyczkach, który pozwala zautomatyzować różne aspekty procesu kompilacji; w tym kompilowanie i podpisywanie .jar
, pobieranie zewnętrznych zależności i zarządzanie nimi, wstrzykiwanie pól do AndroidManifest
lub wykorzystanie określonych wersji SDK.
Składnia
apply plugin
: wtyczki, które powinny być normalnie używane, to po prostu'com.android.application'
lub'com.android.library'
.android
: główna konfiguracja Twojej aplikacji-
compileSdkVersion
: wersja kompilowanegocompileSdkVersion
SDK -
buildToolsVersion
: wersja narzędzi do budowania -
defaultConfig
: Domyślne ustawienia, które można zastąpić smakami i typami kompilacji-
applicationId
: identyfikator aplikacji, którego używasz np. w PlayStore, w większości taki sam jak nazwa pakietu -
minSdkVersion
: minimalna wymagana wersjaminSdkVersion
SDK -
targetSdkVersion
: Wersja SDK, na której kompilujesz (zawsze powinna być najnowsza) -
versionCode
: wewnętrzny numer wersji, który musi być większy przy każdej aktualizacji -
versionName
: numer wersji, który użytkownik widzi na stronie szczegółów aplikacji
-
-
buildTypes
: Zobacz gdzie indziej (TODO)
-
dependencies
: zależność między aplikacją lokalną a lokalną-
compile
pojedynczą zależność -
testCompile
: zależność dla testów jednostkowych lub integracyjnych
-
Uwagi
Zobacz też
- Oficjalna strona główna stopni
- Jak skonfigurować kompilacje stopni
- Wtyczka dla Androida do gradle
- Android Gradle DSL
Gradle dla Androida - Dokumentacja rozszerzona:
Jest jeszcze jeden tag, w którym można znaleźć więcej tematów i przykładów na temat używania gradle w Androidzie.
http://www.riptutorial.com/topic/2092
Podstawowy plik build.gradle
To jest przykład domyślnego pliku build.gradle
w 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 (język specyficzny dla domeny)
Każdy blok w powyższym pliku nosi nazwę DSL
(język specyficzny dla domeny).
Wtyczki
W pierwszym wierszu apply plugin: 'com.android.application'
, zastosuje wtyczkę dla systemu Gradle do kompilacji i udostępni blok android {}
celu zadeklarowania opcji kompilacji specyficznych dla Androida.
W przypadku aplikacji na Androida :
apply plugin: 'com.android.application'
W przypadku biblioteki Androida :
apply plugin: 'com.android.library'
Zrozumienie DSL w powyższej próbce
Druga część, blok android {...}
Androida, to DSL
Androida, który zawiera informacje o twoim projekcie.
Na przykład możesz ustawić compileSdkVersion
który określa poziom interfejsu API systemu Android, który powinien być używany przez Gradle do kompilowania Twojej aplikacji.
defaultConfig
przechowuje wartości domyślne dla manifestu. Możesz je override
pomocą Smaków produktu .
Więcej informacji można znaleźć w tych przykładach:
Zależności
Blok dependencies
jest zdefiniowany poza blokiem android
{...}
: Oznacza to, że nie jest zdefiniowany przez wtyczkę Androida, ale jest to standardowy Gradle.
Blok dependencies
określa, jakie biblioteki zewnętrzne (zwykle biblioteki Androida, ale również biblioteki Java są prawidłowe), które chcesz uwzględnić w swojej aplikacji. Gradle automatycznie pobierze te zależności (jeśli nie ma dostępnej kopii lokalnej), wystarczy dodać podobne wiersze compile
, aby dodać kolejną bibliotekę.
Spójrzmy na jedną z linii tutaj obecnych:
compile 'com.android.support:design:25.3.1'
Ta linia w zasadzie mówi
dodaj do mojego projektu zależność od biblioteki projektów obsługi systemu Android.
Gradle zapewni, że biblioteka zostanie pobrana i zaprezentowana, dzięki czemu będziesz mógł jej używać w swojej aplikacji, a jej kod będzie również zawarty w Twojej aplikacji.
Jeśli znasz Maven, ta składnia to GroupId , dwukropek, ArtifactId , kolejny dwukropek, a następnie wersja zależności, którą chcesz uwzględnić, dając ci pełną kontrolę nad wersjonowaniem.
Chociaż możliwe jest określenie wersji artefaktu za pomocą znaku plus (+), najlepszą praktyką jest unikanie tego; może to prowadzić do problemów, jeśli biblioteka zostanie zaktualizowana z łamaniem zmian bez Twojej wiedzy, co prawdopodobnie doprowadzi do awarii w Twojej aplikacji.
Możesz dodać różnego rodzaju zależności:
Szczególną uwagę należy zwrócić na płaskie zależności .
Więcej informacji można znaleźć w tym temacie.
Uwaga na temat -v7 w appcompat-v7
compile 'com.android.support:appcompat-v7:25.3.1'
Oznacza to po prostu, że ta biblioteka ( appcompat
) jest zgodna z interfejsem API Androida w wersji 7 i appcompat
.
Uwaga na temat junit: junit: 4.12
Jest to zależność testowania dla testów jednostkowych.
Określanie zależności specyficznych dla różnych konfiguracji kompilacji
Możesz określić, że zależność powinna być używana tylko dla określonej konfiguracji kompilacji lub możesz zdefiniować różne zależności dla typów kompilacji lub smaków produktu (np. Debugowanie, test lub wydanie) za pomocą debugCompile
, testCompile
lub releaseCompile
zamiast zwykłej compile
.
Jest to pomocne w utrzymywaniu zależności związanych z testowaniem i debugowaniem z kompilacji wydania, dzięki czemu APK
wersji będzie możliwie jak najmniejszy i zapewni, że żadne informacje debugowania nie będą mogły zostać wykorzystane do uzyskania wewnętrznych informacji o aplikacji.
signingConfig
signingConfig
pozwala skonfigurować Gradle tak, aby zawierał informacje o signingConfig
keystore
i upewnić się, że signingConfig
APK zbudowany przy użyciu tych konfiguracji jest podpisany i gotowy do wydania w Play Store.
Tutaj znajdziesz dedykowany temat .
Uwaga : nie zaleca się jednak przechowywania poświadczeń podpisywania w pliku Gradle. Aby usunąć konfiguracje podpisywania, po prostu pomiń część signingConfigs
.
Możesz je określić na różne sposoby:
- przechowywanie w pliku zewnętrznym
- przechowywanie ich w ustawieniach zmiennych środowiskowych .
Aby uzyskać więcej informacji, zobacz ten temat: Podpisz APK bez ujawniania hasła do magazynu kluczy .
Więcej informacji na temat Gradle na Androida można znaleźć w dedykowanym temacie Gradle .
Definiowanie smaków produktu
Smaki produktu są zdefiniowane w pliku build.gradle
wewnątrz bloku android { ... }
jak pokazano poniżej.
...
android {
...
productFlavors {
free {
applicationId "com.example.app.free"
versionName "1.0-free"
}
paid {
applicationId "com.example.app.paid"
versionName "1.0-paid"
}
}
}
Dzięki temu mamy teraz dwa dodatkowe smaki produktu: free
i paid
. Każdy może mieć swoją własną konfigurację i atrybuty. Na przykład, oba nasze nowe smaki mają osobne applicationId
i versionName
niż nasz dotychczasowy main
smak (dostępny domyślnie, więc nie pokazany tutaj).
Dodanie zależności specyficznych dla smaku produktu
Zależności można dodać dla określonego smaku produktu , podobnie jak można je dodać dla określonych konfiguracji kompilacji.
W tym przykładzie załóżmy, że zdefiniowaliśmy już dwa smaki produktu o nazwie free
i paid
(więcej o definiowaniu smaków tutaj ).
Następnie możemy dodać zależność AdMob dla free
smaku i bibliotekę Picasso dla paid
sposób:
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'
}
...
Dodanie zasobów specyficznych dla smaku produktu
Można dodać zasoby dla określonego smaku produktu .
W tym przykładzie załóżmy, że zdefiniowaliśmy już dwa smaki produktu o nazwie free
i paid
. Aby dodać zasoby specyficzne dla smaku produktu, tworzymy dodatkowe foldery zasobów obok folderu main/res
, do których możemy następnie dodawać zasoby jak zwykle. W tym przykładzie zdefiniujemy ciąg, status
dla każdego smaku produktu:
/ 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>
Ciągi status
specyficzne dla smaku produktu zastąpią wartość status
dla main
smaku.
Zdefiniuj i użyj pól konfiguracji kompilacji
BuildConfigField
Gradle pozwala liniom buildConfigField
definiować stałe. Te stałe będą dostępne w czasie wykonywania jako pola statyczne klasy BuildConfig
. Można to wykorzystać do tworzenia smaków poprzez zdefiniowanie wszystkich pól w bloku defaultConfig
, a następnie zastąpienie ich dla indywidualnych smaków kompilacji w razie potrzeby.
W tym przykładzie zdefiniowano datę kompilacji i oflagowano kompilację dla produkcji zamiast testować:
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'
}
}
}
Automatycznie generowana <nazwa_pakietu>. BuildConfig
.java w folderze gen zawiera następujące pola na podstawie powyższej dyrektywy:
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";
}
Zdefiniowanych pól można teraz używać w aplikacji w czasie wykonywania, uzyskując dostęp do wygenerowanej klasy 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
resValue
w productFlavors
tworzy wartość zasobu. Może to być dowolny rodzaj zasobu ( string
, dimen
, color
itp.). Jest to podobne do definiowania zasobu w odpowiednim pliku: np. Definiowanie łańcucha w pliku strings.xml
. Zaletą jest to, że ten zdefiniowany w gradable można modyfikować w zależności od produktu Smak / buildVariant. Aby uzyskać dostęp do wartości, napisz ten sam kod, jakbyś miał dostęp do res z pliku zasobów:
getResources().getString(R.string.app_name)
Ważne jest to, że zasoby zdefiniowane w ten sposób nie mogą modyfikować istniejących zasobów zdefiniowanych w plikach. Mogą tworzyć tylko nowe wartości zasobów.
Niektóre biblioteki (takie jak Google Maps Android API) wymagają klucza API podanego w Manifeście jako meta-data
. Jeśli do debugowania i kompilacji produkcyjnych potrzebne są różne klucze, określ manifest zastępczy wypełniony przez Gradle.
W pliku AndroidManifest.xml
:
<meta-data
android:name="com.google.android.geo.API_KEY"
android:value="${MAPS_API_KEY}"/>
A następnie odpowiednio ustaw pole w swoim pliku build.gradle
:
android {
defaultConfig {
...
// Your development key
manifestPlaceholders = [ MAPS_API_KEY: "AIza..." ]
}
productFlavors {
prod {
// Your production key
manifestPlaceholders = [ MAPS_API_KEY: "AIza..." ]
}
}
}
System kompilacji dla Androida automatycznie generuje wiele pól i umieszcza je w BuildConfig.java
. Te pola to:
Pole | Opis |
---|---|
DEBUG | Boolean stwierdzający, czy aplikacja jest w trybie debugowania lub wydania |
APPLICATION_ID | String zawierający identyfikator aplikacji (np. com.example.app ) |
BUILD_TYPE | String zawierający typ kompilacji aplikacji (zwykle debug lub release ) |
FLAVOR | String zawierający konkretny smak kompilacji |
VERSION_CODE | int zawierający numer wersji (kompilacji). Jest to to samo, co versionCode w build.gradle lub versionCode w AndroidManifest.xml |
VERSION_NAME | String zawierający nazwę wersji (kompilacji). Jest to to samo, co versionName w build.gradle lub versionName w AndroidManifest.xml |
Oprócz powyższego, jeśli zdefiniowałeś wiele wymiarów smaku, to każdy wymiar będzie miał swoją wartość. Na przykład, jeśli masz dwa wymiary smaku color
i size
, będziesz mieć także następujące zmienne:
Pole | Opis |
---|---|
FLAVOR_color | String zawierający wartość smaku „kolorowego”. |
FLAVOR_size | String zawierający wartość smaku „rozmiar”. |
Centralizacja zależności za pomocą pliku „dependencies.gradle”
Podczas pracy z projektami wielomodułowymi pomocne jest scentralizowanie zależności w jednym miejscu zamiast rozłożenia ich na wiele plików kompilacji, szczególnie w przypadku popularnych bibliotek, takich jak biblioteki obsługi Androida i biblioteki Firebase .
Jednym z zalecanych sposobów jest oddzielenie plików kompilacji Gradle, z jednym build.gradle
na moduł, a także jednym w katalogu głównym projektu i drugim dla zależności, na przykład:
root
+- gradleScript/
| dependencies.gradle
+- module1/
| build.gradle
+- module2/
| build.gradle
+- build.gradle
Następnie wszystkie twoje zależności mogą być zlokalizowane w 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}",
];
}
Które można następnie zastosować z tego pliku w pliku build.gradle
najwyższego poziomu, tak jak to:
// Load dependencies
apply from: 'gradleScript/dependencies.gradle'
i w module1/build.gradle
tak:
// Module build file
dependencies {
// ...
compile supportDependencies.appCompat
compile supportDependencies.design
compile firebaseDependencies.crash
}
Inne podejście
Mniej szczegółowe podejście do centralizacji wersji zależności bibliotek można osiągnąć, zadeklarując raz numer wersji jako zmienną i używając go wszędzie.
W głównym katalogu roboczym build.gradle
dodaj to:
ext.v = [
supportVersion:'24.1.1',
]
I w każdym module korzystającym z tej samej biblioteki dodaj potrzebne biblioteki
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}"
Struktura katalogów dla zasobów specyficznych dla smaku
Różne wersje kompilacji aplikacji mogą zawierać różne zasoby. Aby utworzyć zasób specyficzny dla smaku, utwórz katalog z małą nazwą Twojego smaku w katalogu src
i dodaj swoje zasoby w taki sam sposób, jak normalnie.
Na przykład, jeśli miałeś smak Development
i chciałbyś podać dla niego odrębną ikonę uruchamiania, utworzyłbyś katalog src/development/res/drawable-mdpi
a wewnątrz tego katalogu ic_launcher.png
plik ic_launcher.png
z ikoną specyficzną dla rozwoju.
Struktura katalogów będzie wyglądać następująco:
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'
(Oczywiście w tym przypadku utworzyłbyś także ikony dla drawable-hdpi, drawable-xhdpi itp .).
Dlaczego w projekcie Android Studio są dwa pliki build.gradle?
<PROJECT_ROOT>\app\build.gradle
jest specyficzny dla modułu aplikacji .
<PROJECT_ROOT>\build.gradle
to „plik kompilacji najwyższego poziomu”, w którym można dodawać opcje konfiguracji wspólne dla wszystkich podprojektów / modułów.
Jeśli użyjesz innego modułu w swoim projekcie, jako bibliotekę lokalną miałbyś inny plik build.gradle
: <PROJECT_ROOT>\module\build.gradle
W pliku najwyższego poziomu możesz określić wspólne właściwości jako blok buildscript lub niektóre wspólne właściwości.
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"
}
W app\build.gradle
definiujesz tylko właściwości modułu:
apply plugin: 'com.android.application'
android {
compileSdkVersion rootProject.ext.compileSdkVersion
buildToolsVersion rootProject.ext.buildToolsVersion
}
dependencies {
//.....
}
Wykonywanie skryptu powłoki z poziomu
Skrypt powłoki to bardzo wszechstronny sposób na rozszerzenie twojej kompilacji do praktycznie wszystkiego, co tylko możesz wymyślić.
Jako przykład, oto prosty skrypt do kompilacji plików protobuf i dodania wynikowych plików Java do katalogu źródłowego w celu dalszej kompilacji:
def compilePb() {
exec {
// NOTICE: gradle will fail if there's an error in the protoc file...
executable "../pbScript.sh"
}
}
project.afterEvaluate {
compilePb()
}
Skrypt powłoki „pbScript.sh” dla tego przykładu, znajdujący się w folderze głównym projektu:
#!/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
Debugowanie błędów Gradle
Poniżej znajduje się fragment Gradle - Co to jest niezerowa wartość wyjściowa i jak to naprawić? zobacz całą dyskusję.
Załóżmy, że tworzysz aplikację i pojawia się błąd Gradle, który na ogół wygląda tak.
: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
Przeszukujesz tutaj na StackOverflow swój problem, a ludzie mówią, aby wyczyścić i odbudować projekt lub włączyć MultiDex , a kiedy spróbujesz, to po prostu nie rozwiązuje problemu.
Istnieją sposoby, aby uzyskać więcej informacji , ale samo wyjście Gradle powinno wskazywać na rzeczywisty błąd w kilku wierszach powyżej tego komunikatu między: module:someTask FAILED
a ostatnim :module:someOtherTask
który przeszedł. Dlatego jeśli zadajesz pytanie na temat błędu, edytuj pytania, aby uwzględnić więcej kontekstu błędu.
Otrzymujesz „niezerową wartość wyjściową”. Ta liczba jest dobrym wskaźnikiem tego, co powinieneś spróbować naprawić. Oto kilka najczęściej występujących.
-
1
to tylko ogólny kod błędu, a błąd prawdopodobnie występuje na wyjściu Gradle -
2
wydaje się mieć związek z nakładającymi się zależnościami lub błędną konfiguracją projektu. - Wygląda na to, że
3
zawiera zbyt wiele zależności lub problem z pamięcią.
Ogólne rozwiązania powyższego (po próbie czyszczenia i przebudowy projektu) to:
-
1
- Rozwiąż wspomniany błąd. Zasadniczo jest to błąd czasu kompilacji, co oznacza, że jakiś fragment kodu w projekcie jest nieprawidłowy. Obejmuje to zarówno XML, jak i Javę dla projektu Android. -
2
i3
- Wiele odpowiedzi tutaj mówi o włączeniu multidex . Chociaż może rozwiązać problem, najprawdopodobniej jest to obejście. Jeśli nie rozumiesz, dlaczego go używasz (patrz link), prawdopodobnie nie potrzebujesz go. Ogólne rozwiązania obejmują ograniczenie nadużywania zależności między bibliotekami (takich jak wszystkie Usługi Google Play, gdy potrzebujesz tylko jednej biblioteki, na przykład Mapy lub Logowanie).
Określanie różnych identyfikatorów aplikacji dla typów kompilacji i smaków produktów
Możesz określić różne identyfikatory aplikacji lub nazwy pakietów dla każdego buildType
lub productFlavor
za pomocą atrybutu konfiguracji applicationIdSuffix :
Przykład przyrostka applicationId
dla każdego 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"
}
}
Nasza wynikowa applicationIds
będzie teraz:
- com.package.android do
release
- com.package.android. dev dla
development
- com.package.android. qa do
testing
Można to zrobić również dla productFlavors
:
productFlavors {
free {
applicationIdSuffix ".free"
}
paid {
applicationIdSuffix ".paid"
}
}
Wynikowymi identyfikatorami applicationIds
byłyby:
- com.package.android. za darmo dla
free
smaku - com.package.android. zapłacono za
paid
smak
Podpisz APK bez ujawniania hasła do magazynu kluczy
Możesz zdefiniować konfigurację podpisywania, aby podpisać apk w pliku build.gradle
, używając następujących właściwości:
-
storeFile
: plik kluczy -
storePassword
: hasło dostorePassword
kluczy -
keyAlias
: nazwa aliasu klucza -
keyPassword
: Hasło aliasu klucza
W wielu przypadkach może być konieczne uniknięcie tego rodzaju informacji w pliku build.gradle
.
Metoda A: Skonfiguruj podpisywanie wersji za pomocą pliku keystore.properties
Możliwe jest skonfigurowanie build.gradle
aplikacji, aby odczytywała informacje o konfiguracji podpisywania z pliku właściwości, takiego jak keystore.properties
.
Konfigurowanie takiego podpisywania jest korzystne, ponieważ:
- Informacje o konfiguracji podpisywania są niezależne od pliku
build.gradle
- Nie musisz interweniować podczas procesu podpisywania, aby podać hasła do pliku kluczy
- Możesz łatwo wykluczyć plik
keystore.properties
z kontroli wersji
Najpierw utwórz plik o nazwie keystore.properties
w katalogu głównym projektu z taką treścią (zamieniając wartości na własne):
storeFile=keystore.jks
storePassword=storePassword
keyAlias=keyAlias
keyPassword=keyPassword
Teraz w pliku build.gradle
aplikacji skonfiguruj blok signingConfigs
w następujący sposób:
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']
}
}
}
}
To naprawdę wszystko, ale nie zapomnij wykluczyć zarówno pliku magazynu kluczy, jak i pliku keystore.properties
z kontroli wersji .
Kilka rzeczy do zapamiętania:
- Ścieżka
storeFile
określona w plikukeystore.properties
powinna być względna w stosunku do plikubuild.gradle
aplikacji. W tym przykładzie założono, że plik kluczy znajduje się w tym samym katalogu, co plikbuild.gradle
aplikacji. - W tym przykładzie plik
keystore.properties
w katalogu głównym projektu. Jeśli umieścisz go w innym miejscu, pamiętaj, aby zmienić wartość wrootProject.file('keystore.properties')
na swoją lokalizację względem katalogu głównego projektu.
Metoda B: przy użyciu zmiennej środowiskowej
To samo można osiągnąć również bez pliku właściwości, co utrudnia znalezienie hasła:
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
}
}
Zmienna środowiskowa "ps"
może być globalna, ale bezpieczniejszym podejściem może być dodanie jej tylko do powłoki Android Studio.
W systemie Linux można to zrobić, edytując Desktop Entry
Android Studio
Exec=sh -c "export ps=myPassword123 ; /path/to/studio.sh"
Więcej informacji można znaleźć w tym temacie .
Wersjonowanie swoich kompilacji za pomocą pliku „version.properties”
Możesz użyć narzędzia Gradle do automatycznego zwiększania wersji pakietu za każdym razem, gdy ją budujesz. W tym celu należy utworzyć plik version.properties
w tym samym katalogu, co plik build.gradle
o następującej treści:
VERSION_MAJOR=0
VERSION_MINOR=1
VERSION_BUILD=1
(Zmiana wartości dla dur i minor według własnego uznania). Następnie w swoim build.gradle
dodaj następujący kod do sekcji 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)
}
}
Informacje można uzyskać w Javie jako ciąg BuildConfig.VERSION_NAME
dla kompletnego BuildConfig.VERSION_NAME
{major}. { BuildConfig.VERSION_NAME
}. {Build} oraz jako liczbę całkowitą BuildConfig.VERSION_CODE
tylko dla numeru kompilacji.
Zmiana wyjściowej nazwy apk i dodanie nazwy wersji:
Jest to kod do zmiany nazwy pliku aplikacji wyjściowej (.apk). Nazwę można skonfigurować, przypisując inną wartość do 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 + "]");
}
}
}
Wyłącz kompresję obrazu dla mniejszego pliku APK
Jeśli ręcznie optymalizujesz wszystkie obrazy, wyłącz APT Cruncher dla mniejszego rozmiaru pliku APK.
android {
aaptOptions {
cruncherEnabled = false
}
}
Włącz Proguard za pomocą gradla
Aby włączyć konfiguracje Proguard dla aplikacji, musisz włączyć ją w pliku ocen na poziomie modułu. Musisz ustawić wartość minifyEnabled
na true
.
buildTypes {
release {
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
Powyższy kod zastosuje konfiguracje Proguard zawarte w domyślnym zestawie SDK systemu Android w połączeniu z plikiem „proguard-rules.pro” w module do wydanej aplikacji.
Włącz eksperymentalną obsługę wtyczek NDK dla Gradle i AndroidStudio
Włącz i skonfiguruj eksperymentalną wtyczkę Gradle, aby poprawić obsługę NDK w AndroidStudio. Sprawdź, czy spełniasz następujące wymagania:
- Stopień 2.10 (dla tego przykładu)
- Android NDK r10 lub nowszy
- Android SDK z narzędziami do kompilacji w wersji 19.0.0 lub nowszej
Skonfiguruj plik MyApp / build.gradle
Edytuj wiersz dependencies.classpath w build.gradle np
classpath 'com.android.tools.build:gradle:2.1.2'
do
classpath 'com.android.tools.build:gradle-experimental:0.7.2'
(v0.7.2 była najnowszą wersją w momencie pisania. Sprawdź najnowszą wersję i odpowiednio dostosuj swoją linię)
Plik build.gradle powinien wyglądać podobnie do tego:
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle-experimental:0.7.2'
}
}
allprojects {
repositories {
jcenter()
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
Skonfiguruj plik MyApp / app / build.gradle
Edytuj plik build.gradle, aby wyglądał podobnie do poniższego przykładu. Twoje numery wersji mogą wyglądać inaczej.
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'])
}
Przed kontynuowaniem zsynchronizuj i sprawdź, czy w plikach Gradle nie ma błędów.
Sprawdź, czy wtyczka jest włączona
Najpierw upewnij się, że pobrałeś moduł Android NDK. Następnie utwórz nową aplikację w AndroidStudio i dodaj następujące elementy do pliku ActivityMain:
public class MainActivity implements Activity {
onCreate() {
// Pregenerated code. Not important here
}
static {
System.loadLibrary("myLib");
}
public static native String getString();
}
Część getString()
powinna być podświetlona na czerwono, mówiąc, że nie można znaleźć odpowiedniej funkcji JNI. Najedź kursorem myszy na wywołanie funkcji, aż pojawi się czerwona żarówka. Kliknij żarówkę i wybierz opcję Utwórz create function JNI_...
Powinno to wygenerować plik myLib.c w katalogu myApp / app / src / main / jni z poprawnym wywołaniem funkcji JNI. Powinno to wyglądać podobnie do tego:
#include <jni.h>
JNIEXPORT jstring JNICALL
Java_com_example_mydomain_myapp_MainActivity_getString(JNIEnv *env, jobject instance)
{
// TODO
return (*env)->NewStringUTF(env, returnValue);
}
Jeśli tak nie wygląda, to wtyczka nie została poprawnie skonfigurowana lub NDK nie został pobrany
Pokaż wszystkie zadania projektowe
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
Automatycznie usuń „nieprzystosowany” apk
Jeśli nie potrzebujesz automatycznie generowanych plików APK z unaligned
przyrostkiem (czego prawdopodobnie nie potrzebujesz), możesz dodać następujący kod do pliku 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()
}
}
}
}
Ignorowanie wariantu kompilacji
Z niektórych powodów możesz zignorować warianty kompilacji. Na przykład: masz „próbny” smak produktu i używasz go tylko do celów debugowania, takich jak testy jednostkowe / instrumentacyjne.
Zignorujmy wariant mockRelease z naszego projektu. Otwórz plik build.gradle i napisz:
// 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);
}
}
Wyświetlanie drzewa zależności
Użyj zależności zadań. W zależności od konfiguracji modułów mogą to być ./gradlew dependencies
lub zobaczyć zależności użycia aplikacji modułu ./gradlew :app:dependencies
Przykład następujący po pliku 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'
}
wyświetli następujący wykres:
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 (*)
. . .
Tutaj możesz zobaczyć, że projekt bezpośrednio obejmuje com.android.support:design
wersji 23.2.1, który sam przynosi com.android.support:support-v4
z wersją 23.2.1. Jednak com.google.android.gms:play-services
są zależne od tego samego support-v4
ale ze starszą wersją 21.0.0, co jest konfliktem wykrywanym przez gradle.
(*)
są używane, gdy grad pomija poddrzewo, ponieważ te zależności były już wymienione wcześniej.
Użyj gradle.properties do centralnych numerów wersji / konfiguracji kompilacji
Możesz zdefiniować informacje o konfiguracji centralnej w
- osobna klasa zawiera plik Centralizowanie zależności za pomocą pliku „dependencies.gradle”
- samodzielny plik właściwości Wersjonowanie kompilacji za pomocą pliku „version.properties”
lub zrób to z gradle.properties
root gradle.properties
struktura projektu
root
+- module1/
| build.gradle
+- module2/
| build.gradle
+- build.gradle
+- gradle.properties
ustawienie globalne dla wszystkich submodułów w 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
użycie w 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 {
...
}
Uwaga: jeśli chcesz opublikować aplikację w sklepie z aplikacjami F-Droid, musisz użyć magicznych liczb w pliku stopni, ponieważ w przeciwnym razie robot f-droid nie będzie mógł odczytać aktualnego numeru wersji, aby wykryć / zweryfikować zmiany wersji.
Wyświetl informacje o podpisywaniu
W niektórych okolicznościach (na przykład uzyskanie klucza Google API) musisz znaleźć swój odcisk palca w magazynie kluczy. Gradle ma wygodne zadanie, które wyświetla wszystkie informacje o podpisywaniu, w tym odciski palców magazynu kluczy:
./gradlew signingReport
To jest przykładowy wynik:
: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
----------
Definiowanie typów kompilacji
Możesz tworzyć i konfigurować typy kompilacji w pliku build.gradle
poziomie modułu w bloku android {}
.
android { ... defaultConfig {...} buildTypes { release { minifyEnabled true proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } debug { applicationIdSuffix ".debug" } } }