Gradle และปลั๊กอิน Android สำหรับ Gradle มีวิธีแบบยืดหยุ่นในการคอมไพล์ บิลด์ และแพ็กเกจแอปหรือไลบรารี Android หน้านี้รวบรวมเคล็ดลับและการกำหนดค่าที่มีประโยชน์เพื่อช่วยให้คุณได้รับประโยชน์สูงสุดจากบิลด์แต่ละรายการ หากต้องการดูวิธีทำให้บิลด์เร็วขึ้น โปรดอ่านเพิ่มประสิทธิภาพความเร็วในการสร้าง
หากคุณเพิ่งเริ่มใช้ Gradle โปรดดูข้อมูลเบื้องต้นโดยอ่านกำหนดค่าบิลด์ นอกจากนี้ คุณยังตรวจสอบเอกสารอ้างอิง DSL ของปลั๊กอิน Android เพื่อดูข้อมูลเพิ่มเติมเกี่ยวกับพร็อพเพอร์ตี้ที่ใช้ในหน้านี้ได้
จัดการโปรเจ็กต์และแหล่งที่มา
ต่อไปนี้เป็นการกำหนดค่าบางส่วนสำหรับจัดการโมดูลของโปรเจ็กต์และแหล่งที่มาของโมดูล ดูข้อมูลเพิ่มเติมเกี่ยวกับการสร้างและจัดการโปรเจ็กต์และข้อบังคับได้ที่ภาพรวมโปรเจ็กต์
เปลี่ยนการกำหนดค่าชุดแหล่งที่มาเริ่มต้น
คุณใช้การบล็อก
sourceSets
ในไฟล์ build.gradle
ระดับโมดูลเพื่อเปลี่ยนตำแหน่งที่ Gradle รวบรวมไฟล์สำหรับคอมโพเนนต์แต่ละรายการของชุดแหล่งที่มาได้
Groovy
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") ... } } } ...
จัดการไลบรารีและทรัพยากร Dependency
Gradle มีกลไกที่มีประสิทธิภาพในการจัดการการพึ่งพา ไม่ว่าจะเป็นไลบรารีระยะไกลหรือโมดูลไลบรารีในเครื่อง
กําหนดเป้าหมายบิลด์ที่เฉพาะเจาะจงด้วยการกําหนดค่าทรัพยากร Dependency
หากต้องการใช้การพึ่งพากับชุดแหล่งที่มาของตัวแปรบิลด์หรือชุดแหล่งที่มาของการทดสอบที่เฉพาะเจาะจงเท่านั้น ให้ใช้อักษรตัวพิมพ์ใหญ่สำหรับชื่อการกำหนดค่าการพึ่งพา แล้วใส่ชื่อตัวแปรบิลด์หรือชุดแหล่งที่มาของการทดสอบไว้ข้างหน้า
Groovy
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") }
สร้างแอปหลายเวอร์ชัน
Gradle และปลั๊กอิน Android ช่วยให้คุณสร้างแอปเวอร์ชันต่างๆ จากโมดูลเดียวได้โดยการกำหนดค่าตัวแปรของบิลด์
กำหนดค่ารหัสเวอร์ชันแบบไดนามิก
โดยค่าเริ่มต้น เมื่อ Gradle สร้าง APK สําหรับโปรเจ็กต์ของคุณ APK แต่ละรายการจะมีข้อมูลเวอร์ชันเดียวกันตามที่ระบุไว้ในไฟล์ build.gradle
ระดับโมดูล
เนื่องจาก Google Play Store ไม่อนุญาตให้มี APK หลายรายการสำหรับแอปเดียวกันซึ่งมีข้อมูลเวอร์ชันเหมือนกัน คุณจึงต้องตรวจสอบว่า APK แต่ละรายการมี versionCode ที่ไม่ซ้ำกันก่อนที่จะอัปโหลดไปยัง Play Store
ซึ่งทำได้โดยใช้ตรรกะการสร้างที่กำหนดเองซึ่งกำหนดรหัสเวอร์ชันที่แตกต่างกันให้กับ APK แต่ละรายการ ณ เวลาที่สร้าง ตัวอย่างเช่น เมื่อสร้าง APK แยกกันสำหรับ ABI แต่ละรายการ การกำหนดเวอร์ชัน APK อัตโนมัติจะมีลักษณะดังนี้
Groovy
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)) } } } }
รวมผลิตภัณฑ์หลายเวอร์ชันเข้าด้วยกัน
ในบางกรณี คุณอาจต้องการรวมการกําหนดค่าจากผลิตภัณฑ์หลายรุ่น โดยปลั๊กอิน Android สำหรับ Gradle ช่วยให้คุณสร้างกลุ่มของตัวแปรผลิตภัณฑ์ได้ ซึ่งเรียกว่ามิติข้อมูลตัวแปร
ตัวอย่างโค้ดต่อไปนี้ใช้พร็อพเพอร์ตี้
flavorDimensions
เพื่อสร้างมิติข้อมูลตัวแปร "mode" เพื่อจัดกลุ่มตัวแปรผลิตภัณฑ์ "full" และ "demo" และมิติข้อมูลตัวแปร "api" เพื่อจัดกลุ่มการกำหนดค่าตัวแปรผลิตภัณฑ์ตามระดับ API จากนั้น Gradle จะรวมรสชาติผลิตภัณฑ์จากมิติข้อมูล "mode" เข้ากับรสชาติผลิตภัณฑ์จากมิติข้อมูล "api"
ดึงดูด
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" ... } } } ...
กรองตัวแปร
คุณสามารถกรองตัวแปรการสร้างที่ไม่ต้องการได้โดยใช้บล็อก
variantFilter
ในไฟล์ build.gradle
ของโมดูล โค้ดตัวอย่างต่อไปนี้บอกให้ Gradle ไม่ให้สร้างตัวแปรที่รวม Flavour ผลิตภัณฑ์ "minApi21" และ "demo"
Groovy
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 } } } ...
ทดสอบแอป
ดูข้อมูลเพิ่มเติมเกี่ยวกับการเรียกใช้การทดสอบหน่วยแบบรวมและแบบภายในได้ที่บทความทดสอบแอป
กำหนดค่าตัวเลือก lint
คุณกำหนดค่าตัวเลือกบางอย่างของ Lint ได้โดยใช้บล็อก
lintOptions
ในไฟล์ build.gradle
ระดับโมดูล หากต้องการดูข้อมูลเพิ่มเติมเกี่ยวกับการใช้ Lint สำหรับโปรเจ็กต์ Android โปรดอ่านปรับปรุงโค้ดด้วย Lint
Groovy
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 } } ...
กำหนดการตั้งค่าไฟล์ Manifest ของเครื่องมือวัด
เมื่อ Gradle บิลด์ APK ทดสอบ ระบบจะสร้างไฟล์ AndroidManifest.xml
โดยอัตโนมัติและกำหนดค่าด้วยโหนด <instrumentation>
คุณเปลี่ยนการตั้งค่าบางอย่างสำหรับโหนดนี้ได้โดยการสร้างไฟล์ Manifest อีกไฟล์หนึ่งในชุดแหล่งที่มาทดสอบ หรือกำหนดค่าไฟล์ build.gradle
ระดับโมดูล ดังที่แสดงในตัวอย่างโค้ดต่อไปนี้
Groovy
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 } } ...
เปลี่ยนประเภทบิลด์ทดสอบ
โดยค่าเริ่มต้น การทดสอบทั้งหมดจะทำงานกับบิลด์การแก้ไขข้อบกพร่อง คุณสามารถเปลี่ยนประเภทบิลด์นี้ไปเป็นประเภทอื่นได้โดยใช้พร็อพเพอร์ตี้ testBuildType
ในไฟล์ build.gradle
ระดับโมดูล เช่น หากต้องการเรียกใช้การทดสอบกับประเภทบิลด์ "ระยะเตรียมความพร้อม" ให้แก้ไขไฟล์ตามที่แสดงในข้อมูลโค้ดต่อไปนี้
Groovy
android { ... testBuildType "staging" }
Kotlin
android { ... testBuildType "staging" }
กำหนดค่าตัวเลือกการทดสอบ Gradle
หากต้องการระบุตัวเลือกที่เปลี่ยนวิธีที่ Gradle เรียกใช้การทดสอบทั้งหมด ให้กำหนดค่าบล็อก
testOptions
ใน
build.gradle
ระดับโมดูล
Groovy
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" } }
หากต้องการระบุตัวเลือกสําหรับการทดสอบ 1 หน่วยในเครื่องเท่านั้น ให้กําหนดค่าบล็อก
testOptions.unitTests
Groovy
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' } } } } }
เพิ่มประสิทธิภาพบิลด์
ส่วนนี้จะแสดงการกำหนดค่าบางอย่างเพื่อช่วยเร่งความเร็วในการสร้างแบบสมบูรณ์และแบบเพิ่ม โปรดดูข้อมูลเพิ่มเติมที่หัวข้อเพิ่มประสิทธิภาพความเร็วของบิวด์
ย่อโค้ดของคุณ
Android Studio ใช้ R8 ซึ่งใช้ไฟล์กฎ ProGuard เพื่อลดขนาดโค้ด สำหรับโปรเจ็กต์ใหม่ Android Studio จะใช้ไฟล์การตั้งค่าเริ่มต้น (proguard-android.txt
) จาก tools/proguard/folder
ของ Android SDK หากต้องการลดขนาดโค้ดให้มากขึ้น ให้ลองใช้ไฟล์ proguard-android-optimize.txt
ที่อยู่ในตำแหน่งเดียวกัน
Groovy
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' } } ... } ...
หากต้องการเพิ่มกฎเฉพาะสำหรับตัวแปรการสร้างแต่ละรายการ ให้กำหนดค่าพร็อพเพอร์ตี้
proguardFiles
เพิ่มเติมสำหรับแต่ละตัวแปร ตัวอย่างเช่น ตัวอย่างต่อไปนี้จะเพิ่ม flavor2-rules.pro
ลงใน "flavor2" ตอนนี้เวอร์ชัน "flavor2" ที่เผยแพร่จะใช้ไฟล์กฎทั้ง 3 ไฟล์ เนื่องจากระบบจะใช้ไฟล์กฎจากบล็อกการเผยแพร่ด้วย
Groovy
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' } } } ...
เผยแพร่แอป
หากต้องการดูข้อมูลเพิ่มเติมเกี่ยวกับการเผยแพร่แอปไปยัง Google Play โปรดอ่านเผยแพร่แอปของคุณ
เซ็นชื่อบนแอปของคุณ
แม้ว่า Android Studio จะมีวิธีกำหนดค่าการรับรองสําหรับบิลด์รุ่นที่เผยแพร่จาก UI ที่ตรงไปตรงมา แต่คุณก็กําหนดค่าบล็อก
signingConfigs
ในไฟล์ build.gradle
ของโมดูลด้วยตนเองได้ ดังนี้
ดึงดูด
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 ... } } } ...
นำข้อมูลการลงนามส่วนตัวออกจากโปรเจ็กต์
โดยค่าเริ่มต้น ระบบจะบันทึกการกำหนดค่าการรับรองเป็นข้อความธรรมดาลงในไฟล์ build.gradle
ของโมดูล หากคุณทํางานร่วมกับทีมหรือโปรเจ็กต์โอเพนซอร์ส คุณสามารถย้ายข้อมูลที่ละเอียดอ่อนนี้ออกจากไฟล์บิลด์ได้โดยทําตามขั้นตอนต่อไปนี้
- สร้างไฟล์ชื่อ
keystore.properties
ในไดเรกทอรีรูทของโปรเจ็กต์ แล้วใส่ข้อมูลต่อไปนี้storePassword=myStorePassword keyPassword=myKeyPassword keyAlias=myKeyAlias storeFile=myStoreFileLocation
- ในไฟล์
build.gradle
ให้โหลดไฟล์keystore.properties
ดังนี้ (ต้องอยู่ก่อนการบล็อก Android)Groovy
// 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 { ... } ...
- ป้อนข้อมูลการลงนามที่จัดเก็บไว้ในออบเจ็กต์
keystoreProperties
Groovy
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'] } } ... } ...
- คลิกซิงค์เลยในแถบการแจ้งเตือน
ดูข้อมูลเพิ่มเติมเกี่ยวกับการรับรองแอปได้ที่รับรองแอป
ลดความซับซ้อนของการพัฒนาแอป
เคล็ดลับต่อไปนี้จะช่วยให้การพัฒนาแอป Android ง่ายขึ้น
แชร์ช่องที่กำหนดเองและค่าทรัพยากรกับโค้ดของแอป
ขณะสร้าง Gradle จะสร้างคลาส BuildConfig
เพื่อให้โค้ดแอปของคุณตรวจสอบข้อมูลเกี่ยวกับบิลด์ปัจจุบันได้ นอกจากนี้ คุณยังเพิ่มฟิลด์ที่กำหนดเองลงในคลาส BuildConfig
จากไฟล์การกำหนดค่าการสร้าง Gradle โดยใช้เมธอด buildConfigField()
และเข้าถึงค่าเหล่านั้นในโค้ดรันไทม์ของแอปได้ด้วย ในทํานองเดียวกัน คุณสามารถเพิ่มค่าทรัพยากรของแอปด้วย resValue()
Groovy
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") } } } ...
ในโค้ดแอป คุณจะเข้าถึงพร็อพเพอร์ตี้ได้ดังนี้
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));
แชร์พร็อพเพอร์ตี้กับไฟล์ Manifest
ในบางกรณี คุณอาจต้องประกาศพร็อพเพอร์ตี้เดียวกันทั้งในไฟล์ Manifest และโค้ด (เช่น เมื่อประกาศหน่วยงานสำหรับ FileProvider
)
แทนที่จะอัปเดตพร็อพเพอร์ตี้เดียวกันในหลายตำแหน่งเพื่อแสดงการเปลี่ยนแปลง ให้กำหนดพร็อพเพอร์ตี้เดียวในไฟล์ build.gradle
ของโมดูลเพื่อให้พร็อพเพอร์ตี้นั้นพร้อมใช้งานทั้งในไฟล์ Manifest และโค้ด ดังที่แสดงในตัวอย่างต่อไปนี้ อ่านข้อมูลเพิ่มเติมได้ที่แทรกตัวแปรบิลด์ลงในไฟล์ Manifest
ดึงดูด
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}\"") } ... } ...
ในไฟล์ Manifest ให้เข้าถึงตัวยึดตําแหน่งดังนี้
<manifest> ... <application> ... <provider android:name="android.support.v4.content.FileProvider" android:authorities="${filesAuthority}" android:exported="false" android:grantUriPermissions="true"> ... </provider> </application> </manifest>
การเข้าถึงช่อง FILES_AUTHORITY
ในโค้ดของแอปจะมีลักษณะดังนี้
Kotlin
... val contentUri: Uri = FileProvider.getUriForFile(context, BuildConfig.FILES_AUTHORITY, myFile)
Java
... Uri contentUri = FileProvider.getUriForFile(getContext(), BuildConfig.FILES_AUTHORITY, myFile);