แม้ว่าการสร้าง APK เดียวเพื่อรองรับอุปกรณ์เป้าหมายทั้งหมดจะเป็นวิธีที่ดีกว่าเมื่อเป็นไปได้ แต่ก็อาจส่งผลให้ APK มีขนาดใหญ่มากเนื่องจากไฟล์ที่รองรับอินเทอร์เฟซแบบไบนารีของแอปพลิเคชัน (ABI) หลายรายการ วิธีหนึ่งในการลดขนาด APK คือการสร้าง APK หลายรายการที่มีไฟล์สำหรับ ABI ที่เฉพาะเจาะจง
Gradle สามารถสร้าง APK แยกต่างหากที่มีเฉพาะโค้ดและทรัพยากรที่เจาะจงสำหรับ ABI แต่ละรายการ หน้านี้จะอธิบายวิธีกำหนดค่าบิลด์เพื่อสร้าง APK หลายรายการ หากต้องการสร้างแอปหลายเวอร์ชันที่ไม่ได้อิงตาม ABI ให้ใช้ตัวแปรบิลด์แทน
กำหนดค่าบิลด์สำหรับ APK หลายรายการ
หากต้องการกำหนดค่าบิลด์สำหรับ APK หลายรายการ ให้เพิ่มบล็อก splits ลงในไฟล์ build.gradle ระดับโมดูล ภายในบล็อก splits ให้ระบุบล็อก abi ที่ระบุวิธีที่คุณต้องการให้ Gradle สร้าง APK ต่อ ABI
กำหนดค่า APK หลายรายการสำหรับ ABI
หากต้องการสร้าง APK แยกต่างหากสำหรับ ABI ที่แตกต่างกัน ให้เพิ่มบล็อก abi ไว้ในบล็อก splits ในบล็อก abi ให้ระบุรายการ ABI ที่คุณเลือก
ตัวเลือก Gradle DSL ต่อไปนี้ใช้เพื่อกำหนดค่า APK หลายรายการต่อ ABI
enableสำหรับ Groovy หรือisEnableสำหรับสคริปต์ Kotlin- หากคุณตั้งค่าองค์ประกอบนี้เป็น
trueGradle จะสร้าง APK หลายรายการตาม ABI ที่คุณกำหนด ค่าเริ่มต้นคือfalse exclude- ระบุรายการ ABI ที่คั่นด้วยคอมมาซึ่งคุณไม่ต้องการให้ Gradle สร้าง APK แยกต่างหาก ใช้
excludeหากต้องการสร้าง APK สำหรับ ABI ส่วนใหญ่ แต่ต้องยกเว้น ABI บางรายการที่แอปไม่รองรับ reset()ล้างรายการ ABI เริ่มต้น ใช้เฉพาะเมื่อใช้ร่วมกับองค์ประกอบ
includeเพื่อระบุ ABI ที่ต้องการเพิ่มข้อมูลโค้ดต่อไปนี้จะตั้งค่ารายการ ABI เป็น
x86และx86_64เท่านั้นโดยเรียกใช้reset()เพื่อล้างรายการ แล้วใช้includereset() // Clears the default list from all ABIs to no ABIs. include "x86", "x86_64" // Specifies the two ABIs we want to generate APKs for.includeระบุรายการ ABI ที่คั่นด้วยคอมมาซึ่งคุณต้องการให้ Gradle สร้าง APK ให้ ใช้ร่วมกับ
reset()เพื่อระบุรายการ ABI ที่แน่นอนเท่านั้นuniversalApkสำหรับ Groovy หรือisUniversalApkสำหรับสคริปต์ Kotlinหากเป็น
true, Gradle จะสร้าง APK สากลนอกเหนือจาก APK ต่อ ABI APK สากลมีโค้ดและทรัพยากรสำหรับ ABI ทั้งหมดใน APK เดียว ค่าเริ่มต้นคือfalse
ตัวอย่างต่อไปนี้จะสร้าง APK แยกต่างหากสำหรับ ABI แต่ละรายการ ได้แก่ x86 และ x86_64
ซึ่งทำได้โดยใช้ reset() เพื่อเริ่มต้นด้วยรายการ ABI ที่ว่างเปล่า ตามด้วย include พร้อมรายการ ABI ที่แต่ละรายการได้รับ APK
ดึงดูด
android { ... splits { // Configures multiple APKs based on ABI. abi { // Enables building multiple APKs per ABI. enable true // By default all ABIs are included, so use reset() and include to specify that you only // want APKs for x86 and x86_64. // Resets the list of ABIs for Gradle to create APKs for to none. reset() // Specifies a list of ABIs for Gradle to create APKs for. include "x86", "x86_64" // Specifies that you don't want to also generate a universal APK that includes all ABIs. universalApk false } } }
Kotlin
android { ... splits { // Configures multiple APKs based on ABI. abi { // Enables building multiple APKs per ABI. isEnable = true // By default all ABIs are included, so use reset() and include to specify that you only // want APKs for x86 and x86_64. // Resets the list of ABIs for Gradle to create APKs for to none. reset() // Specifies a list of ABIs for Gradle to create APKs for. include("x86", "x86_64") // Specifies that you don't want to also generate a universal APK that includes all ABIs. isUniversalApk = false } } }
ดูรายการ ABI ที่รองรับได้ที่หัวข้อ ABI ที่รองรับ
โปรเจ็กต์ที่ไม่มีโค้ดเนทีฟ/C++
สำหรับโปรเจ็กต์ที่ไม่มีโค้ดเนทีฟ/C++ แผงตัวแปรบิลด์จะมี 2 คอลัมน์ ได้แก่ โมดูลและตัวแปรบิลด์ที่ใช้งานอยู่ ดังที่แสดงในรูปที่ 1
ค่าตัวแปรบิลด์ที่ใช้งานอยู่สำหรับโมดูลจะกำหนดตัวแปรบิลด์ที่ติดตั้งใช้งานและมองเห็นได้ในเครื่องมือแก้ไข หากต้องการสลับระหว่างตัวแปร ให้คลิกเซลล์ตัวแปรบิลด์ที่ใช้งานอยู่สำหรับโมดูล แล้วเลือกตัวแปรที่ต้องการจากช่องรายการ
โปรเจ็กต์ที่มีโค้ดเนทีฟ/C++
สำหรับโปรเจ็กต์ที่มีโค้ดเนทีฟ/C++ แผงตัวแปรบิลด์จะมี 3 คอลัมน์ ได้แก่ โมดูล ตัวแปรบิลด์ที่ใช้งานอยู่ และ ABI ที่ใช้งานอยู่ ดังที่แสดงในรูปที่ 2
ค่าตัวแปรบิลด์ที่ใช้งานอยู่สำหรับโมดูลจะเป็นตัวกำหนดตัวแปรบิลด์ที่ติดตั้งใช้งานและมองเห็นได้ในเครื่องมือแก้ไข สำหรับโมดูลเนทีฟ ค่า Active ABI จะกำหนด ABI ที่เครื่องมือแก้ไขใช้ แต่จะไม่ส่งผลต่อสิ่งที่ติดตั้งใช้งาน
วิธีเปลี่ยนประเภทบิลด์หรือ ABI
- คลิกเซลล์ของคอลัมน์ตัวแปรบิลด์ที่ใช้งานอยู่หรือ ABI ที่ใช้งานอยู่
- เลือกตัวแปรหรือ ABI ที่คุณเลือกจากช่องรายการ การซิงค์ใหม่จะทำงานโดยอัตโนมัติ
การเปลี่ยนคอลัมน์ใดคอลัมน์หนึ่งสำหรับแอปหรือโมดูลไลบรารีจะมีผลกับการเปลี่ยนแปลงแถวที่เกี่ยวข้องทั้งหมด
กำหนดค่าการกำหนดเวอร์ชัน
โดยค่าเริ่มต้น เมื่อ Gradle สร้าง APK หลายรายการ APK แต่ละรายการจะมีข้อมูลเวอร์ชันเดียวกันตามที่ระบุไว้ในไฟล์ build.gradle หรือ build.gradle.kts ระดับโมดูล เนื่องจาก Google Play Store ไม่อนุญาตให้มี APK หลายรายการสำหรับแอปเดียวกันซึ่งมีข้อมูลเวอร์ชันเหมือนกัน คุณจึงต้องตรวจสอบว่า APK แต่ละรายการมี versionCode ที่ไม่ซ้ำกันก่อนที่จะอัปโหลดไปยัง Play Store
คุณสามารถกำหนดค่าไฟล์ build.gradle ระดับโมดูลเพื่อลบล้าง versionCode สำหรับ APK แต่ละรายการได้ การสร้างการแมปที่กำหนดค่าตัวเลขที่ไม่ซ้ำกันสำหรับ ABI แต่ละรายการที่คุณกำหนดค่า APK หลายรายการไว้จะช่วยให้คุณลบล้างรหัสเวอร์ชันเอาต์พุตด้วยค่าที่รวมรหัสเวอร์ชันที่กำหนดไว้ภายในบล็อก defaultConfig หรือ productFlavors กับค่าตัวเลขที่กำหนดให้กับ ABI ได้
ในตัวอย่างต่อไปนี้ APK สำหรับ ABI x86 จะได้รับ versionCode เป็น 2004 และ ABI x86_64 จะได้รับ versionCode เป็น 3004
การกำหนดรหัสเวอร์ชันโดยเพิ่มขึ้นทีละมากๆ เช่น 1000 จะช่วยให้คุณกำหนดรหัสเวอร์ชันที่ไม่ซ้ำกันได้ในภายหลังหากต้องการอัปเดตแอป ตัวอย่างเช่น หาก defaultConfig.versionCode เพิ่มขึ้นเป็น 5 ในการอัปเดตครั้งต่อมา Gradle จะกำหนด versionCode เป็น 2005 ให้กับ APK x86 และ 3005 ให้กับ APK x86_64
ดึงดูด
android { ... defaultConfig { ... versionCode 4 } splits { ... } } // Map for the version code that gives each ABI a value. ext.abiCodes = ['armeabi-v7a':1, x86:2, x86_64:3] 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 doesn't override the version code for universal APKs. // However, because you 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 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, "x86" to 2, "x86_64" to 3) 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 doesn't override the version code for universal APKs. // However, because you 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)) } } } }
ดูตัวอย่างเพิ่มเติมของรูปแบบรหัสเวอร์ชันอื่นได้ที่การกำหนดรหัสเวอร์ชัน
สร้าง APK หลายรายการ
เมื่อกำหนดค่าไฟล์ build.gradle หรือ build.gradle.kts ระดับโมดูลเพื่อสร้าง APK หลายรายการแล้ว ให้คลิกสร้าง > สร้าง APK เพื่อสร้าง APK ทั้งหมดสำหรับโมดูลที่เลือกในแผงโปรเจ็กต์ Gradle จะสร้าง APK สำหรับ ABI แต่ละรายการในไดเรกทอรี build/outputs/apk/ ของโปรเจ็กต์
Gradle จะสร้าง APK สำหรับ ABI แต่ละรายการที่คุณกำหนดค่า APK หลายรายการไว้
ตัวอย่างเช่น ข้อมูลโค้ด build.gradle ต่อไปนี้จะช่วยให้สร้าง APK หลายรายการสำหรับ ABI x86 และ x86_64 ได้
ดึงดูด
... splits { abi { enable true reset() include "x86", "x86_64" } }
Kotlin
... splits { abi { isEnable = true reset() include("x86", "x86_64") } }
เอาต์พุตจากการกำหนดค่าตัวอย่างประกอบด้วย APK 4 รายการต่อไปนี้
app-X86-release.apk: มีโค้ดและทรัพยากรสำหรับ ABIx86app-X86_64-release.apk: มีโค้ดและทรัพยากรสำหรับ ABIx86_64
เมื่อสร้าง APK หลายรายการโดยอิงตาม ABI แล้ว Gradle จะสร้างเฉพาะ APK ที่มีโค้ดและทรัพยากรสำหรับ ABI ทั้งหมดหากคุณระบุ universalApk true ในบล็อก splits.abi ในไฟล์ build.gradle (สำหรับ Groovy) หรือ isUniversalApk = true ในบล็อก splits.abi ในไฟล์ build.gradle.kts (สำหรับสคริปต์ Kotlin)
รูปแบบชื่อไฟล์ APK
เมื่อสร้าง APK หลายรายการ Gradle จะสร้างชื่อไฟล์ APK โดยใช้รูปแบบต่อไปนี้
modulename-ABI-buildvariant.apk
องค์ประกอบของรูปแบบมีดังนี้
modulename- ระบุชื่อโมดูลที่กำลังสร้าง
ABI- หากเปิดใช้ APK หลายรายการสำหรับ ABI ให้ระบุ ABI สำหรับ APK เช่น
x86 buildvariant- ระบุตัวแปรบิลด์ที่กำลังสร้าง เช่น
debug