สร้าง APK หลายรายการ

ข้อควรระวัง: ตั้งแต่เดือนสิงหาคม 2021 เป็นต้นมา แอปใหม่ทั้งหมด ต้องเผยแพร่เป็น App Bundle หากเผยแพร่แอปไปยัง Google Play ให้สร้างและอัปโหลด Android App Bundle เมื่อทำเช่นนั้น Google Play จะสร้างและแสดง APK ที่เพิ่มประสิทธิภาพโดยอัตโนมัติสำหรับการกำหนดค่าอุปกรณ์ของผู้ใช้แต่ละราย เพื่อให้ผู้ใช้ดาวน์โหลดเฉพาะโค้ดและทรัพยากรที่จำเป็นในการเรียกใช้แอปของคุณ การเผยแพร่ APK หลายรายการจะมีประโยชน์หากคุณเผยแพร่ไปยังร้านค้าที่ไม่รองรับรูปแบบ AAB ในกรณีนี้ คุณ ต้องสร้าง ลงนาม และจัดการ APK แต่ละรายการด้วยตนเอง

แม้ว่าการสร้าง 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
หากตั้งค่าองค์ประกอบนี้เป็น true Gradle จะสร้าง APK หลายรายการ ตาม ABI ที่คุณกำหนด ค่าเริ่มต้นคือ false
exclude
ระบุรายการ ABI ที่คั่นด้วยคอมมาซึ่งคุณไม่ต้องการให้ Gradle สร้าง APK แยกต่างหาก ใช้ exclude หากต้องการสร้าง APK สำหรับ ABI ส่วนใหญ่ แต่ต้องยกเว้น ABI บางรายการที่แอปไม่รองรับ
reset()

ล้างรายการ ABI เริ่มต้น ใช้เมื่อรวมกับองค์ประกอบ include เพื่อระบุ ABI ที่ต้องการเพิ่มเท่านั้น

ข้อมูลโค้ดต่อไปนี้จะตั้งค่ารายการ ABI เป็น x86 และ x86_64 เท่านั้นโดยการเรียกใช้ reset() เพื่อล้างรายการ และ จากนั้นใช้ include

reset()                 // 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

Groovy

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

แผงตัวแปรของบิวด์
รูปที่ 1 แผงตัวแปรบิลด์มี 2 คอลัมน์สําหรับโปรเจ็กต์ที่ไม่มีโค้ด เนทีฟ/C++

ค่ารูปแบบบิลด์ที่ใช้งานอยู่สำหรับโมดูล จะกำหนดรูปแบบบิลด์ที่ได้รับการติดตั้งใช้งานและมองเห็นได้ในเอดิเตอร์ หากต้องการสลับระหว่างตัวแปร ให้คลิกเซลล์ตัวแปรบิลด์ที่ใช้งานอยู่สำหรับโมดูล แล้วเลือกตัวแปรที่ต้องการจากช่องรายการ

โปรเจ็กต์ที่มีโค้ดเนทีฟ/C++

สำหรับโปรเจ็กต์ที่มีโค้ด C++ หรือโค้ดเนทีฟ แผงตัวแปรบิลด์จะมี 3 คอลัมน์ ได้แก่ โมดูล ตัวแปรบิลด์ที่ใช้งานอยู่ และ ABI ที่ใช้งานอยู่ ดังที่แสดงในรูปที่ 2

รูปที่ 2 แผงตัวแปรบิลด์จะเพิ่มคอลัมน์ ABI ที่ใช้งานอยู่สำหรับ โปรเจ็กต์ที่มีโค้ด C++ หรือโค้ดเนทีฟ

ค่ารูปแบบบิลด์ที่ใช้งานอยู่สำหรับโมดูล จะกำหนดรูปแบบบิลด์ที่ได้รับการติดตั้งใช้งานและมองเห็นได้ในเอดิเตอร์ สําหรับโมดูลเนทีฟ ค่า Active ABI จะกําหนด ABI ที่เอดิเตอร์ ใช้ แต่จะไม่ส่งผลต่อสิ่งที่นําไปใช้งาน

วิธีเปลี่ยนประเภทบิลด์หรือ ABI

  1. คลิกเซลล์สำหรับคอลัมน์ตัวแปรบิลด์ที่ใช้งานอยู่ หรือABI ที่ใช้งานอยู่
  2. เลือกตัวแปรหรือ 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 สำหรับ x86 ABI จะได้รับ versionCode เป็น 2004 และ x86_64 ABI จะได้รับ versionCode เป็น 3004

การกำหนดรหัสเวอร์ชันโดยเพิ่มขึ้นครั้งละมากๆ เช่น 1000 จะช่วยให้คุณกำหนดรหัสเวอร์ชันที่ไม่ซ้ำกันได้ในภายหลังหากต้องการอัปเดตแอป ตัวอย่างเช่น หาก defaultConfig.versionCode เพิ่มขึ้นเป็น 5 ในการอัปเดตครั้งต่อๆ ไป Gradle จะกำหนด versionCode เป็น 2005 ให้กับ APK ของ x86 และ 3005 ให้กับ APK ของ x86_64

เคล็ดลับ: หากบิลด์มี APK สากล ให้กำหนด versionCode ที่ต่ำกว่า APK อื่นๆ เนื่องจาก Google Play Store จะติดตั้งแอปเวอร์ชันที่ทั้ง เข้ากันได้กับอุปกรณ์เป้าหมายและมี versionCode สูงสุด การกำหนด versionCode ที่ต่ำกว่าให้กับ APK สากลจะช่วยให้ Google Play Store พยายามติดตั้ง APK รายการใดรายการหนึ่งของคุณ ก่อนที่จะกลับไปใช้ APK สากล โค้ดตัวอย่างต่อไปนี้ จัดการปัญหานี้โดยไม่ลบล้างค่าเริ่มต้น versionCode ของ APK สากล

Groovy

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 ได้

Groovy

...
  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: มีโค้ดและทรัพยากรสำหรับ x86 ABI
  • app-X86_64-release.apk: มีโค้ดและทรัพยากรสำหรับ x86_64 ABI

เมื่อสร้าง APK หลายรายการตาม ABI, Gradle จะสร้าง APK ที่มีโค้ดและทรัพยากรสำหรับ ABI ทั้งหมดก็ต่อเมื่อคุณระบุ universalApk true ในบล็อก splits.abi ในไฟล์ build.gradle (สำหรับ Groovy) หรือ isUniversalApk = true ในบล็อก splits.abi ในไฟล์ build.gradle.kts (สำหรับสคริปต์ Kotlin)

รูปแบบชื่อไฟล์ APK

เมื่อสร้าง APK หลายรายการ Gradle จะสร้างชื่อไฟล์ APK โดยใช้รูปแบบต่อไปนี้ scheme:

modulename-ABI-buildvariant.apk

องค์ประกอบของรูปแบบมีดังนี้

modulename
ระบุชื่อโมดูลที่จะสร้าง
ABI

หากเปิดใช้ APK หลายรายการสำหรับ ABI ให้ระบุ ABI สำหรับ APK เช่น x86

buildvariant
ระบุตัวแปรของบิลด์ที่กำลังสร้าง เช่น debug