Gradle i wtyczka na Androida do Gradle umożliwiają elastyczny sposób kompilowania, kompilowania i pakowania aplikacji lub biblioteki na Androida. Na tej stronie znajdziesz przydatne wskazówki i konfiguracje, które pomogą Ci w pełni wykorzystać możliwości każdej kompilacji. Jeśli chcesz dowiedzieć się, jak przyspieszyć kompilacje, przeczytaj artykuł Optymalizacja szybkości kompilacji.
Jeśli dopiero zaczynasz korzystać z Gradle, zapoznaj się z podstawowymi informacjami w artykule Skonfiguruj kompilację. Możesz też przejrzeć dokumentację DSSL wtyczki na Androida, by dowiedzieć się więcej o właściwościach używanych na tej stronie.
Zarządzaj projektami i źródłami
Poniżej znajdziesz konfiguracje, które pozwolą Ci zarządzać modułami projektu i ich źródłami. Aby dowiedzieć się więcej o tworzeniu projektów i modułów oraz o zarządzaniu nimi, przeczytaj omówienie projektów.
Zmiana domyślnych konfiguracji zestawu źródeł
Możesz użyć bloku
sourceSets
w pliku build.gradle
na poziomie modułu, aby zmienić miejsce, w którym Gradle szuka plików dla każdego komponentu zestawu źródłowego.
Odlotowy
android { ... sourceSets { // Encapsulates configurations for the main source set. main { // Changes the directory for Java sources. The default directory is // 'src/main/java'. java.srcDirs = ['other/java'] // When you list multiple directories, Gradle uses all of them to collect // sources. You should avoid specifying a directory which is a parent to one // or more other directories you specify. res.srcDirs = ['other/res1', 'other/res2'] // For each source set, you can specify only one Android manifest. // The following points Gradle to a different manifest for this source set. manifest.srcFile 'other/AndroidManifest.xml' ... } // Create additional blocks to configure other source sets. androidTest { // If all the files for a source set are located under a single root // directory, you can specify that directory using the setRoot property. // When gathering sources for the source set, Gradle looks only in locations // relative to the root directory you specify. For example, after applying // the configuration below for the androidTest source set, Gradle looks for // Java sources only in the src/tests/java/ directory. setRoot 'src/tests' ... } } } ...
Kotlin
android { ... sourceSets { // Encapsulates configurations for the main source set. getByName("main") { // Changes the directory for Java sources. The default directory is // 'src/main/java'. java.setSrcDirs("other/java") // When you list multiple directories, Gradle uses all of them to collect // sources. You should avoid specifying a directory which is a parent to one // or more other directories you specify. res.setSrcDirs("other/res1", "other/res2") // For each source set, you can specify only one Android manifest. // The following points Gradle to a different manifest for this source set. manifest.srcFile("other/AndroidManifest.xml") ... } // Create additional blocks to configure other source sets. androidTest { // If all the files for a source set are located under a single root // directory, you can specify that directory using the setRoot property. // When gathering sources for the source set, Gradle looks only in locations // relative to the root directory you specify. For example, after applying // the configuration below for the androidTest source set, Gradle looks for // Java sources only in the src/tests/java/ directory. setRoot("src/tests") ... } } } ...
Zarządzanie bibliotekami i zależnościami
Gradle zapewnia solidny mechanizm zarządzania zależnościami, niezależnie od tego, czy są to biblioteki zdalne, czy moduły bibliotek lokalnych.
Kierowanie na określone kompilacje z konfiguracjami zależności
Jeśli chcesz, aby zależność dotyczyła tylko określonego zbioru źródłowego wariant kompilacji lub testowego zbioru źródeł, wpisz wielką literą nazwę konfiguracji zależności i poprzedź ją nazwą wariantu kompilacji lub zestawu źródeł testowych.
Odlotowy
android {...} // Creates Gradle dependency configurations to use in the dependencies block. configurations { // For variants that combine a product flavor and build type, you need to // intitialize a placeholder for its dependency configuration. freeDebugRuntimeOnly{} ... } dependencies { // Adds an implementation dependency only to the "free" product flavor. freeImplementation 'com.google.firebase:firebase-ads:21.5.1' // Adds a runtimeOnly dependency only to the "freeDebug" build variant. freeDebugRuntimeOnly fileTree(dir: 'libs', include: ['*.jar']) // Adds a remote binary dependency only for local tests. testImplementation 'junit:junit:4.12' // Adds a remote binary dependency only for the instrumented test APK. androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.5.1' }
Kotlin
android {...} dependencies { // Use ""() notation for custom flavors and build types // Adds an implementation dependency only to the "free" product flavor. "freeImplementation"("com.google.firebase:firebase-ads:21.5.1") // Adds a runtimeOnly dependency only to the "freeDebug" build variant. "freeDebugRuntimeOnly"(fileTree("dir" to "libs", "include" to "*.jar")) // Adds a remote binary dependency only for local tests. testImplementation("junit:junit:4.12") // Adds a remote binary dependency only for the instrumented test APK. androidTestImplementation("com.android.support.test.espresso:espresso-core:3.5.1") }
Utwórz różne wersje aplikacji
Gradle i wtyczka na Androida umożliwiają tworzenie różnych wersji aplikacji z poziomu jednego modułu przez konfigurowanie wariantów kompilacji.
Konfigurowanie kodów wersji dynamicznych
Domyślnie, gdy Gradle generuje pliki APK dla Twojego projektu, każdy plik APK ma te same informacje o wersji, które są określone w pliku build.gradle
na poziomie modułu.
Sklep Google Play nie zezwala na publikowanie wielu plików APK tej samej aplikacji o tych samych informacjach o wersji. Zanim prześlesz plik do Sklepu Play, musisz zadbać o to, by każdy z nich miał unikalny kod versionCode.
Możesz to zrobić za pomocą niestandardowej logiki kompilacji, która przypisuje inny kod wersji do każdego pliku APK w czasie kompilacji. Na przykład podczas tworzenia osobnych plików APK dla każdego interfejsu ABI automatyczna obsługa wersji plików APK wygląda tak:
Odlotowy
android { ... defaultConfig { ... versionCode 4 } splits { ... } } // Map for the version code that gives each ABI a value. ext.abiCodes = ['armeabi-v7a':1, mips:2, x86:3] // For per-density APKs, create a similar map like this: // ext.densityCodes = ['hdpi': 1, 'xhdpi': 2, 'xxhdpi': 3, 'xxxhdpi': 4] import com.android.build.OutputFile // For each APK output variant, override versionCode with a combination of // ext.abiCodes * 1000 + variant.versionCode. In this example, variant.versionCode // is equal to defaultConfig.versionCode. If you configure product flavors that // define their own versionCode, variant.versionCode uses that value instead. android.applicationVariants.all { variant -> // Assigns a different version code for each output APK // other than the universal APK. variant.outputs.each { output -> // Stores the value of ext.abiCodes that is associated with the ABI for this variant. def baseAbiVersionCode = // Determines the ABI for this variant and returns the mapped value. project.ext.abiCodes.get(output.getFilter(OutputFile.ABI)) // Because abiCodes.get() returns null for ABIs that are not mapped by ext.abiCodes, // the following code does not override the version code for universal APKs. // However, because we want universal APKs to have the lowest version code, // this outcome is desirable. if (baseAbiVersionCode != null) { // Assigns the new version code to versionCodeOverride, which changes the version code // for only the output APK, not for the variant itself. Skipping this step simply // causes Gradle to use the value of variant.versionCode for the APK. output.versionCodeOverride = baseAbiVersionCode * 1000 + variant.versionCode } } }
Kotlin
android { ... defaultConfig { ... versionCode = 4 } splits { ... } } // Map for the version code that gives each ABI a value. val abiCodes = mapOf("armeabi-v7a" to 1, "mips" to 2, "x86" to 3) // For per-density APKs, create a similar map like this: // val densityCodes = mapOf("hdpi" to 1, "xhdpi" to 2, "xxhdpi" to 3, "xxxhdpi" to 4) import com.android.build.api.variant.FilterConfiguration.FilterType.* // For each APK output variant, override versionCode with a combination of // abiCodes * 1000 + variant.versionCode. In this example, variant.versionCode // is equal to defaultConfig.versionCode. If you configure product flavors that // define their own versionCode, variant.versionCode uses that value instead. androidComponents { onVariants { variant -> // Assigns a different version code for each output APK // other than the universal APK. variant.outputs.forEach { output -> val name = output.filters.find { it.filterType == ABI }?.identifier // Stores the value of abiCodes that is associated with the ABI for this variant. val baseAbiCode = abiCodes[name] // Because abiCodes.get() returns null for ABIs that are not mapped by ext.abiCodes, // the following code does not override the version code for universal APKs. // However, because we want universal APKs to have the lowest version code, // this outcome is desirable. if (baseAbiCode != null) { // Assigns the new version code to output.versionCode, which changes the version code // for only the output APK, not for the variant itself. output.versionCode.set(baseAbiCode * 1000 + (output.versionCode.get() ?: 0)) } } } }
Łączenie różnych smaków produktów
W niektórych przypadkach warto połączyć konfiguracje różnych typów usług. W tym celu wtyczka na Androida do obsługi Gradle umożliwia tworzenie grup rodzajów produktów, zwanych wymiarami smaku.
W poniższym przykładowym kodzie użyto właściwości
flavorDimensions
do utworzenia wymiaru smaku „mode” do grupowania smaków produktu „pełnego” i „demonstracyjnego” oraz wymiaru smaku „api” do grupowania konfiguracji smaku produktu na podstawie poziomu interfejsu API. Następnie Gradle łączy smaki usługi z wymiaru „tryb” z wymiarem „api”.
Odlotowy
android { ... buildTypes { debug {...} release {...} } // Specifies the flavor dimensions you want to use. The order in which you // list each dimension determines its priority, from highest to lowest, // when Gradle merges variant sources and configurations. You must assign // each product flavor you configure to one of the flavor dimensions. flavorDimensions "api", "mode" productFlavors { demo { // Assigns this product flavor to the "mode" flavor dimension. dimension "mode" ... } full { dimension "mode" ... } // Configurations in the "api" product flavors override those in "mode" // flavors and the defaultConfig block. Gradle determines the priority // between flavor dimensions based on the order in which they appear next // to the flavorDimensions property above--the first dimension has a higher // priority than the second, and so on. minApi24 { dimension "api" minSdkVersion '24' // To ensure the target device receives the version of the app with // the highest compatible API level, assign version codes in increasing // value with API level. To learn more about assigning version codes to // support app updates and uploading to Google Play, read Multiple APK Support versionCode 30000 + android.defaultConfig.versionCode versionNameSuffix "-minApi24" ... } minApi23 { dimension "api" minSdkVersion '23' versionCode 20000 + android.defaultConfig.versionCode versionNameSuffix "-minApi23" ... } minApi21 { dimension "api" minSdkVersion '21' versionCode 10000 + android.defaultConfig.versionCode versionNameSuffix "-minApi21" ... } } } ...
Kotlin
android { ... buildTypes { getByName("debug") {...} getByName("release") {...} } // Specifies the flavor dimensions you want to use. The order in which you // list each dimension determines its priority, from highest to lowest, // when Gradle merges variant sources and configurations. You must assign // each product flavor you configure to one of the flavor dimensions. flavorDimensions += listOf("api", "mode") productFlavors { create("demo") { // Assigns this product flavor to the "mode" flavor dimension. dimension = "mode" ... } create("full") { dimension = "mode" ... } // Configurations in the "api" product flavors override those in "mode" // flavors and the defaultConfig block. Gradle determines the priority // between flavor dimensions based on the order in which they appear next // to the flavorDimensions property above--the first dimension has a higher // priority than the second, and so on. create("minApi24") { dimension = "api" minSdkVersion(24) // To ensure the target device receives the version of the app with // the highest compatible API level, assign version codes in increasing // value with API level. To learn more about assigning version codes to // support app updates and uploading to Google Play, read Multiple APK Support versionCode = 30000 + android.defaultConfig.versionCode versionNameSuffix = "-minApi24" ... } create("minApi23") { dimension = "api" minSdkVersion(23) versionCode = 20000 + android.defaultConfig.versionCode versionNameSuffix = "-minApi23" ... } create("minApi21") { dimension = "api" minSdkVersion(21) versionCode = 10000 + android.defaultConfig.versionCode versionNameSuffix = "-minApi21" ... } } } ...
Filtruj warianty
Warianty kompilacji, których nie potrzebujesz, możesz filtrować, korzystając z bloku
variantFilter
w pliku build.gradle
modułu. Ten przykładowy kod informuje Gradle, aby nie tworzył żadnych wariantów, które łączą różne smaki produktu „minApi21” i „demo”:
Odlotowy
android { ... buildTypes {...} flavorDimensions "api", "mode" productFlavors { demo {...} full {...} minApi24 {...} minApi23 {...} minApi21 {...} } variantFilter { variant -> def names = variant.flavors*.name // To check for a certain build type, use variant.buildType.name == "<buildType>" if (names.contains("minApi21") && names.contains("demo")) { // Gradle ignores any variants that satisfy the conditions above. setIgnore(true) } } } ...
Kotlin
android { ... buildTypes {...} flavorDimensions "api", "mode" productFlavors { create("demo") {...} create("full") {...} create("minApi24") {...} create("minApi23") {...} create("minApi21") {...} } } androidComponents { beforeVariants { variantBuilder -> // To check for a certain build type, use variantBuilder.buildType == "<buildType>" if (variantBuilder.productFlavors.containsAll(listOf("api" to "minApi21", "mode" to "demo"))) { // Gradle ignores any variants that satisfy the conditions above. variantBuilder.enabled = false } } } ...
Testowanie aplikacji
Więcej informacji o przeprowadzaniu lokalnych i zintegrowanych testów jednostkowych znajdziesz w artykule Testowanie aplikacji.
Skonfiguruj opcje lint
Niektóre opcje lintowania możesz skonfigurować za pomocą bloku
lintOptions
w pliku build.gradle
na poziomie modułu. Więcej informacji o korzystaniu z Lint w projekcie na Androida znajdziesz w artykule Ulepsz swój kod przy użyciu Lint.
Odlotowy
android { ... lintOptions { // Turns off checks for the issue IDs you specify. disable 'TypographyFractions','TypographyQuotes' // Turns on checks for the issue IDs you specify. These checks are in // addition to the default lint checks. enable 'RtlHardcoded','RtlCompat', 'RtlEnabled' // To enable checks for only a subset of issue IDs and ignore all others, // list the issue IDs with the 'check' property instead. This property overrides // any issue IDs you enable or disable using the properties above. checkOnly 'NewApi', 'InlinedApi' // If set to true, turns off analysis progress reporting by lint. quiet true // if set to true (default), stops the build if errors are found. abortOnError false // if true, only report errors. ignoreWarnings true } } ...
Kotlin
android { ... lintOptions { // Turns off checks for the issue IDs you specify. disable("TypographyFractions") disable("TypographyQuotes") // Turns on checks for the issue IDs you specify. These checks are in // addition to the default lint checks. enable("RtlHardcoded") enable("RtlCompat") enable("RtlEnabled") // To enable checks for only a subset of issue IDs and ignore all others, // list the issue IDs with the 'check' property instead. This property overrides // any issue IDs you enable or disable using the properties above. checkOnly("NewApi", "InlinedApi") // If set to true, turns off analysis progress reporting by lint. quiet = true // if set to true (default), stops the build if errors are found. abortOnError = false // if true, only report errors. ignoreWarnings = true } } ...
Skonfiguruj ustawienia pliku manifestu narzędzi
Gdy Gradle skompiluje testowy pakiet APK, automatycznie generuje plik AndroidManifest.xml
i konfiguruje go w węźle <instrumentation>
. Niektóre ustawienia tego węzła możesz zmienić, tworząc inny plik manifestu w testowym zestawie źródłowym lub konfigurując plik build.gradle
na poziomie modułu zgodnie z poniższym przykładowym kodem.
Odlotowy
android { ... // Each product flavor you configure can override properties in the // defaultConfig block. To learn more, go to Configure Product Flavors. defaultConfig { ... // Specifies the application ID for the test APK. testApplicationId "com.test.foo" // Specifies the fully-qualified class name of the test instrumentation runner. testInstrumentationRunner "android.test.InstrumentationTestRunner" // If set to 'true', enables the instrumentation class to start and stop profiling. // If set to false (default), profiling occurs the entire time the instrumentation // class is running. testHandleProfiling true // If set to 'true', indicates that the Android system should run the instrumentation // class as a functional test. The default value is 'false' testFunctionalTest true } } ...
Kotlin
android { ... // Each product flavor you configure can override properties in the // defaultConfig block. To learn more, go to Configure Product Flavors. defaultConfig { ... // Specifies the application ID for the test APK. testApplicationId = "com.test.foo" // Specifies the fully-qualified class name of the test instrumentation runner. testInstrumentationRunner = "android.test.InstrumentationTestRunner" // If set to 'true', enables the instrumentation class to start and stop profiling. // If set to false (default), profiling occurs the entire time the instrumentation // class is running. testHandleProfiling = true // If set to 'true', indicates that the Android system should run the instrumentation // class as a functional test. The default value is 'false' testFunctionalTest = true } } ...
Zmień typ kompilacji testowej
Domyślnie wszystkie testy są przeprowadzane na typu kompilacji przeznaczonej do debugowania. Możesz zmienić ten typ kompilacji na inny, używając właściwości testBuildType
w pliku build.gradle
na poziomie modułu. Jeśli na przykład chcesz przeprowadzać testy na „etapowym” typie kompilacji, zmodyfikuj plik w sposób pokazany poniżej.
Odlotowy
android { ... testBuildType "staging" }
Kotlin
android { ... testBuildType "staging" }
Skonfiguruj opcje testu Gradle
Aby określić opcje, które zmieniają sposób uruchamiania wszystkich testów przez Gradle, skonfiguruj blok
testOptions
w build.gradle
na poziomie modułu.
Odlotowy
android { ... // Encapsulates options for running tests. testOptions { // Changes the directory where Gradle saves test reports. By default, Gradle saves test reports // in the path_to_your_project/module_name/build/outputs/reports/ directory. // '$rootDir' sets the path relative to the root directory of the current project. reportDir "$rootDir/test-reports" // Changes the directory where Gradle saves test results. By default, Gradle saves test results // in the path_to_your_project/module_name/build/outputs/test-results/ directory. // '$rootDir' sets the path relative to the root directory of the current project. resultsDir "$rootDir/test-results" } }
Kotlin
android { ... // Encapsulates options for running tests. testOptions { // Changes the directory where Gradle saves test reports. By default, Gradle saves test reports // in the path_to_your_project/module_name/build/outputs/reports/ directory. // '$rootDir' sets the path relative to the root directory of the current project. reportDir "$rootDir/test-reports" // Changes the directory where Gradle saves test results. By default, Gradle saves test results // in the path_to_your_project/module_name/build/outputs/test-results/ directory. // '$rootDir' sets the path relative to the root directory of the current project. resultsDir "$rootDir/test-results" } }
Aby określić opcje tylko dla testów jednostkowych lokalnych, skonfiguruj blok
testOptions.unitTests
.
Odlotowy
android { ... testOptions { ... // Encapsulates options for local unit tests. unitTests { // By default, local unit tests throw an exception any time the code you are testing tries to access // Android platform APIs (unless you mock Android dependencies yourself or with a testing // framework like Mockito). However, you can enable the following property so that the test // returns either null or zero when accessing platform APIs, rather than throwing an exception. returnDefaultValues true // Encapsulates options for controlling how Gradle executes local unit tests. For a list // of all the options you can specify, read Gradle's reference documentation. all { // Sets JVM argument(s) for the test JVM(s). jvmArgs '-XX:MaxPermSize=256m' // You can also check the task name to apply options to only the tests you specify. if (it.name == 'testDebugUnitTest') { systemProperty 'debug', 'true' } } } } }
Kotlin
android { ... testOptions { ... // Encapsulates options for local unit tests. unitTests { // By default, local unit tests throw an exception any time the code you are testing tries to access // Android platform APIs (unless you mock Android dependencies yourself or with a testing // framework like Mockito). However, you can enable the following property so that the test // returns either null or zero when accessing platform APIs, rather than throwing an exception. returnDefaultValues true // Encapsulates options for controlling how Gradle executes local unit tests. For a list // of all the options you can specify, read Gradle's reference documentation. all { // Sets JVM argument(s) for the test JVM(s). jvmArgs '-XX:MaxPermSize=256m' // You can also check the task name to apply options to only the tests you specify. if (it.name == 'testDebugUnitTest') { systemProperty 'debug', 'true' } } } } }
Zoptymalizuj kompilację
W tej sekcji znajdziesz konfiguracje, które pomogą Ci przyspieszyć pełne i przyrostowe kompilacje. Więcej informacji znajdziesz w artykule Optymalizowanie szybkości kompilacji.
Zmniejszanie kodu
Android Studio używa kodu R8, który zużywa pliki reguł ProGuard, aby zmniejszać kod. W nowych projektach Android Studio używa domyślnego pliku ustawień (proguard-android.txt
) z pakietu Android SDK tools/proguard/folder
. Aby jeszcze bardziej zmniejszyć kod, wypróbuj plik proguard-android-optimize.txt
, który znajduje się w tej samej lokalizacji.
Odlotowy
android { buildTypes { release { minifyEnabled true proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } ... } ...
Kotlin
android { buildTypes { release { minifyEnabled true proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } ... } ...
Aby dodać reguły specyficzne dla każdego wariantu kompilacji, skonfiguruj dodatkową właściwość
proguardFiles
dla każdego rodzaju. Na przykład ten przykładowy kod dodaje znacznik flavor2-rules.pro
do „smaku2”. Teraz wersja premierowa „smaku2” używa wszystkich 3 plików reguł, ponieważ są one również stosowane.
Odlotowy
android { ... buildTypes { release { minifyEnabled true proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } productFlavors { flavor1 { ... } flavor2 { proguardFile 'flavor2-rules.pro' } } } ...
Kotlin
android { ... buildTypes { release { minifyEnabled true proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } productFlavors { flavor1 { ... } flavor2 { proguardFile 'flavor2-rules.pro' } } } ...
Publikowanie aplikacji
Aby dowiedzieć się więcej o publikowaniu aplikacji w Google Play, przeczytaj artykuł Publikowanie aplikacji.
Podpisywanie aplikacji
Chociaż Android Studio zapewnia prosty sposób konfigurowania podpisywania na potrzeby kompilacji wersji z poziomu interfejsu użytkownika, możesz ręcznie skonfigurować blok
signingConfigs
w pliku build.gradle
modułu:
Odlotowy
android { ... defaultConfig { ... } // Encapsulates signing configurations. signingConfigs { // Creates a signing configuration called "release". release { // Specifies the path to your keystore file. storeFile file("my-release-key.jks") // Specifies the password for your keystore. storePassword "password" // Specifies the identifying name for your key. keyAlias "my-alias" // Specifies the password for your key. keyPassword "password" } } buildTypes { release { // Adds the "release" signing configuration to the release build type. signingConfig signingConfigs.release ... } } } ...
Kotlin
android { ... defaultConfig { ... } // Encapsulates signing configurations. signingConfigs { // Creates a signing configuration called "release". release { // Specifies the path to your keystore file. storeFile file("my-release-key.jks") // Specifies the password for your keystore. storePassword "password" // Specifies the identifying name for your key. keyAlias "my-alias" // Specifies the password for your key. keyPassword "password" } } buildTypes { release { // Adds the "release" signing configuration to the release build type. signingConfig signingConfigs.release ... } } } ...
Usuń z projektu informacje o prywatnym podpisywaniu
Domyślnie konfiguracje podpisywania są zapisywane zwykłym tekstem w pliku build.gradle
modułu. Jeśli współpracujesz z zespołem lub projektem open source, możesz przenieść te informacje poufne z plików kompilacji w następujący sposób.
- W katalogu głównym projektu utwórz plik o nazwie
keystore.properties
i podaj w nim te informacje:storePassword=myStorePassword keyPassword=myKeyPassword keyAlias=myKeyAlias storeFile=myStoreFileLocation
- W pliku
build.gradle
załaduj plikkeystore.properties
w ten sposób (musi to być przed zablokowaniem na Androida):Odlotowy
// Creates a variable called keystorePropertiesFile, and initializes it to the // keystore.properties file. def keystorePropertiesFile = rootProject.file("keystore.properties") // Initializes a new Properties() object called keystoreProperties. def keystoreProperties = new Properties() // Loads the keystore.properties file into the keystoreProperties object. keystoreProperties.load(new FileInputStream(keystorePropertiesFile)) android { ... } ...
Kotlin
// Creates a variable called keystorePropertiesFile, and initializes it to the // keystore.properties file. def keystorePropertiesFile = rootProject.file("keystore.properties") // Initializes a new Properties() object called keystoreProperties. def keystoreProperties = new Properties() // Loads the keystore.properties file into the keystoreProperties object. keystoreProperties.load(new FileInputStream(keystorePropertiesFile)) android { ... } ...
- Wpisz informacje o podpisach przechowywane w obiekcie
keystoreProperties
:Odlotowy
android { signingConfigs { config { keyAlias keystoreProperties['keyAlias'] keyPassword keystoreProperties['keyPassword'] storeFile file(keystoreProperties['storeFile']) storePassword keystoreProperties['storePassword'] } } ... } ...
Kotlin
android { signingConfigs { config { keyAlias keystoreProperties['keyAlias'] keyPassword keystoreProperties['keyPassword'] storeFile file(keystoreProperties['storeFile']) storePassword keystoreProperties['storePassword'] } } ... } ...
- Kliknij Synchronizuj teraz na pasku powiadomień.
Więcej informacji o podpisywaniu aplikacji znajdziesz w artykule Podpisywanie aplikacji.
Uprość tworzenie aplikacji
Poniższe wskazówki ułatwią Ci programowanie aplikacji na Androida.
Udostępniaj w kodzie aplikacji pola niestandardowe i wartości zasobów
W czasie kompilacji Gradle generuje klasę BuildConfig
, aby kod aplikacji mógł sprawdzić informacje o bieżącej kompilacji. Możesz też dodać pola niestandardowe do klasy BuildConfig
z pliku konfiguracji kompilacji Gradle za pomocą metody buildConfigField()
i uzyskać dostęp do tych wartości w kodzie środowiska wykonawczego aplikacji. Podobnie możesz dodawać wartości zasobów aplikacji za pomocą funkcji resValue()
.
Odlotowy
android { ... buildTypes { release { // These values are defined only for the release build, which // is typically used for full builds and continuous builds. buildConfigField("String", "BUILD_TIME", "\"${minutesSinceEpoch}\"") resValue("string", "build_time", "${minutesSinceEpoch}") ... } debug { // Use static values for incremental builds to ensure that // resource files and BuildConfig aren't rebuilt with each run. // If these rebuild dynamically, they can interfere with // Apply Changes as well as Gradle UP-TO-DATE checks. buildConfigField("String", "BUILD_TIME", "\"0\"") resValue("string", "build_time", "0") } } } ...
Kotlin
android { ... buildTypes { release { // These values are defined only for the release build, which // is typically used for full builds and continuous builds. buildConfigField("String", "BUILD_TIME", "\"${minutesSinceEpoch}\"") resValue("string", "build_time", "${minutesSinceEpoch}") ... } debug { // Use static values for incremental builds to ensure that // resource files and BuildConfig aren't rebuilt with each run. // If these rebuild dynamically, they can interfere with // Apply Changes as well as Gradle UP-TO-DATE checks. buildConfigField("String", "BUILD_TIME", "\"0\"") resValue("string", "build_time", "0") } } } ...
W kodzie aplikacji możesz uzyskać dostęp do tych właściwości:
Kotlin
... Log.i(TAG, BuildConfig.BUILD_TIME) Log.i(TAG, getString(R.string.build_time))
Java
... Log.i(TAG, BuildConfig.BUILD_TIME); Log.i(TAG, getString(R.string.build_time));
Udostępnianie właściwości za pomocą pliku manifestu
W niektórych przypadkach może być konieczne zadeklarowanie tej samej właściwości zarówno w pliku manifestu, jak i w kodzie (np. podczas deklarowania urzędów dla usługi FileProvider
). Zamiast aktualizować tę samą właściwość w kilku lokalizacjach w celu odzwierciedlenia zmian, zdefiniuj jedną właściwość w pliku build.gradle
modułu, aby była dostępna zarówno w pliku manifestu, jak i w Twoim kodzie, jak pokazujemy w przykładzie poniżej. Więcej informacji znajdziesz w sekcji Wstawianie zmiennych kompilacji do pliku manifestu.
Odlotowy
android { // For settings specific to a product flavor, configure these properties // for each flavor in the productFlavors block. defaultConfig { // Creates a property for the FileProvider authority. def filesAuthorityValue = applicationId + ".files" // Creates a placeholder property to use in the manifest. manifestPlaceholders = [filesAuthority: filesAuthorityValue] // Adds a new field for the authority to the BuildConfig class. buildConfigField("String", "FILES_AUTHORITY", "\"${filesAuthorityValue}\"") } ... } ...
Kotlin
android { // For settings specific to a product flavor, configure these properties // for each flavor in the productFlavors block. defaultConfig { // Creates a property for the FileProvider authority. val filesAuthorityValue = applicationId + ".files" // Creates a placeholder property to use in the manifest. manifestPlaceholders["filesAuthority"] = filesAuthorityValue // Adds a new field for the authority to the BuildConfig class. buildConfigField("String", "FILES_AUTHORITY", "\"${filesAuthorityValue}\"") } ... } ...
W pliku manifestu otwórz obiekt zastępczy w ten sposób:
<manifest> ... <application> ... <provider android:name="android.support.v4.content.FileProvider" android:authorities="${filesAuthority}" android:exported="false" android:grantUriPermissions="true"> ... </provider> </application> </manifest>
Dostęp do pola FILES_AUTHORITY
w kodzie aplikacji wygląda mniej więcej tak:
Kotlin
... val contentUri: Uri = FileProvider.getUriForFile(context, BuildConfig.FILES_AUTHORITY, myFile)
Java
... Uri contentUri = FileProvider.getUriForFile(getContext(), BuildConfig.FILES_AUTHORITY, myFile);