Gradle i wtyczka Androida do obsługi Gradle zapewniają elastyczny sposób kompilowania, tworzenia i pakowania aplikacji na Androida lub biblioteki. Na tej stronie znajdziesz kilka przydatnych wskazówek i konfiguracji, które pomogą Ci w pełni wykorzystać każdą kompilację. Jeśli chcesz dowiedzieć się, jak przyspieszyć kompilacje, przeczytaj Optymalizowanie szybkości kompilacji.
Jeśli dopiero zaczynasz korzystać z Gradle, zapoznaj się z podstawami, czytając artykuł Konfigurowanie kompilacji. Możesz też zapoznać się z dokumentacją referencyjną DSL wtyczki Androida, aby dowiedzieć się więcej o właściwościach używanych na tej stronie.
Zarządzanie projektami i źródłami
Oto kilka konfiguracji, które pomogą Ci zarządzać modułami projektu i ich źródłami. Więcej informacji o tworzeniu projektów i modułów oraz zarządzaniu nimi znajdziesz w artykule Omówienie projektów.
Zmienianie domyślnych konfiguracji zbioru ź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ódeł.
Dynamiczny
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 niezawodny mechanizm zarządzania zależnościami, niezależnie od tego, czy są to biblioteki zdalne, czy lokalne moduły bibliotek.
Kierowanie na określone kompilacje za pomocą konfiguracji zależności
Jeśli chcesz, aby zależność dotyczyła tylko określonego wariantu kompilacji zbioru źródeł lub testowego zbioru źródeł, napisz nazwę konfiguracji zależności wielkimi literami i dodaj przed nią nazwę wariantu kompilacji lub testowego zbioru źródeł.
Dynamiczny
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.6.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.6.1") }
Tworzenie różnych wersji aplikacji
Gradle i wtyczka Androida umożliwiają tworzenie różnych wersji Twojej aplikacji z jednego modułu przez skonfigurowanie wariantów kompilacji.
Konfigurowanie dynamicznych kodów wersji
Domyślnie, gdy Gradle generuje pliki APK dla Twojego projektu, każdy plik APK ma te same informacje o wersji określone w pliku build.gradle na poziomie modułu.
Ponieważ Sklep Google Play nie zezwala na przesyłanie wielu plików APK tej samej aplikacji
, które mają te same informacje o wersji, przed przesłaniem do Sklepu Play musisz się upewnić, że każdy plik APK ma
swój unikalny kod wersji przed
przesłaniem do Sklepu Play.
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 pakietów APK dla każdego interfejsu ABI automatyczne określanie wersji pakietu APK wygląda tak:
Dynamiczny
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 wielu wariantów produktu
W niektórych przypadkach możesz chcieć połączyć konfiguracje z kilku wariantów produktu. Aby to zrobić, wtyczka Androida do obsługi Gradle umożliwia tworzenie grup wariantów produktu, zwanych wymiarami wariantów.
Poniższy przykładowy kod używa właściwości
flavorDimensions do utworzenia wymiaru rodzajów "mode" (tryb), aby pogrupować
warianty usługi "full" (pełny) i "demo" (demonstracyjny), oraz wymiaru rodzajów "api" (interfejs API), aby pogrupować
konfiguracje wariantów usługi na podstawie poziomu [interfejsu] API. Gradle łączy następnie
warianty produktu z wymiaru "mode" z wariantami z wymiaru "api".
Dynamiczny
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" ... } } } ...
Filtrowanie wariantów
Możesz filtrować
warianty kompilacji, których nie chcesz używać, za pomocą bloku
variantFilter w pliku build.gradle modułu. Poniższy przykładowy kod informuje Gradle, aby nie tworzył żadnych wariantów, które łączą
warianty produktu „minApi21” i „demo”:
Dynamiczny
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 uruchamianiu lokalnych i zintegrowanych testów jednostkowych znajdziesz w artykule Testowanie aplikacji.
Konfigurowanie opcji lintera
Niektóre opcje lintera możesz skonfigurować za pomocą bloku
lintOptions w pliku build.gradle na poziomie modułu. Więcej informacji o używaniu lintera w projekcie aplikacji na Androida znajdziesz w artykule Ulepszanie kodu za pomocą lintera.
Dynamiczny
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 } } ...
Konfigurowanie ustawień manifestu instrumentacji
Gdy Gradle tworzy testowy plik APK, automatycznie generuje plik AndroidManifest.xml i
konfiguruje go za pomocą węzła <instrumentation>. Niektóre ustawienia tego węzła możesz zmienić, tworząc
inny plik manifestu w zestawie źródeł testowych lub
konfigurując plik na poziomie modułu build.gradle, jak pokazano w
poniższym przykładowym kodzie.
Dynamiczny
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 } } ...
Zmienianie rodzaju kompilacji testowej
Domyślnie wszystkie testy są uruchamiane w przypadku rodzaju kompilacji do debugowania. Możesz to zmienić
na inny rodzaj kompilacji, używając właściwości testBuildType w
pliku build.gradle na poziomie modułu. Jeśli na przykład chcesz
uruchomić testy w przypadku rodzaju kompilacji „staging” (wersja testowa), edytuj plik tak, jak pokazano w
tym fragmencie kodu.
Dynamiczny
android { ... testBuildType "staging" }
Kotlin
android { ... testBuildType "staging" }
Konfigurowanie opcji testów Gradle
Aby określić opcje, które zmieniają sposób uruchamiania wszystkich testów przez Gradle, skonfiguruj blok
testOptions w pliku
build.gradle na poziomie modułu.
Dynamiczny
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 lokalnych testów jednostkowych, skonfiguruj blok
testOptions.unitTests.
Dynamiczny
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' } } } } }
Optymalizowanie kompilacji
W tej sekcji znajdziesz kilka konfiguracji, które pomogą przyspieszyć pełne i przyrostowe kompilacje. Więcej informacji znajdziesz w artykule Optymalizowanie szybkości kompilacji.
Zmniejszanie rozmiaru kodu
Android Studio używa narzędzia R8, które korzysta z plików reguł ProGuard, aby zmniejszyć rozmiar kodu. W przypadku nowych
projektów Android Studio używa domyślnego pliku ustawień (proguard-android.txt) z
pakietu Android SDK tools/proguard/folder. Aby jeszcze bardziej zmniejszyć rozmiar kodu, wypróbuj plik
proguard-android-optimize.txt, który znajduje się w tej samej lokalizacji.
Dynamiczny
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, które są specyficzne dla każdego wariantu kompilacji, skonfiguruj
dodatkową
proguardFiles właściwość dla każdego wariantu. Na przykład poniższy przykład dodaje flavor2-rules.pro do wariantu „flavor2”. Teraz wersja do publikacji „flavor2” używa wszystkich 3 plików reguł, ponieważ stosowane są też reguły z bloku release.
Dynamiczny
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
Więcej informacji o publikowaniu aplikacji w Google Play znajdziesz w artykule Publikowanie aplikacji.
Podpisywanie aplikacji
Chociaż Android Studio zapewnia prosty sposób na skonfigurowanie podpisywania kompilacji wersji
z interfejsu, możesz ręcznie skonfigurować blok
signingConfigs w pliku build.gradle
modułu:
Dynamiczny
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 ... } } } ...
Usuwanie prywatnych informacji o podpisywaniu z projektu
Domyślnie konfiguracje podpisywania są zapisywane w postaci zwykłego tekstu w pliku
build.gradle modułu. Jeśli pracujesz w zespole lub nad projektem open source, możesz przenieść te poufne informacje z plików kompilacji, wykonując te czynności:
- W katalogu głównym projektu utwórz plik o nazwie
keystore.propertiesi dodaj te informacje:storePassword=myStorePassword keyPassword=myKeyPassword keyAlias=myKeyAlias storeFile=myStoreFileLocation
- W pliku
build.gradlewczytaj plikkeystore.propertiesw ten sposób (musi to być przed blokiem android):Dynamiczny
// 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 { ... } ...
- Wprowadź informacje o podpisywaniu przechowywane w obiekcie
keystoreProperties:Dynamiczny
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'] } } ... } ...
- Na pasku powiadomień kliknij Sync Now (Synchronizuj teraz).
Więcej informacji o podpisywaniu aplikacji znajdziesz w artykule Podpisywanie aplikacji.
Upraszczanie tworzenia aplikacji
Te wskazówki ułatwią Ci tworzenie aplikacji na Androida.
Udostępnianie pól niestandardowych i wartości zasobów w kodzie aplikacji
W czasie kompilacji Gradle generuje klasę BuildConfig, dzięki czemu kod aplikacji może sprawdzać 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 dodać wartości zasobów aplikacji za pomocą metody resValue().
Dynamiczny
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 właściwości w ten sposób:
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 w manifeście
W niektórych przypadkach może być konieczne zadeklarowanie tej samej właściwości zarówno w
manifeście, jak i w kodzie (np. podczas deklarowania uprawnień dla
FileProvider).
Zamiast aktualizować tę samą właściwość w wielu miejscach, aby odzwierciedlić
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 kodzie, jak pokazano w tym
przykładzie. Więcej informacji znajdziesz w artykule Wstrzykiwanie zmiennych kompilacji do pliku manifestu.
Dynamiczny
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 możesz uzyskać dostęp do zmiennej 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);