Ostrzeżenie: od sierpnia 2021 r. wszystkie nowe aplikacje muszą być publikowane jako pakiety aplikacji. Jeśli publikujesz aplikację w Google Play, utwórz i prześlij pakiet aplikacji na Androida. Gdy to zrobisz, Google Play automatycznie wygeneruje i udostępni zoptymalizowane pliki APK dla każdej konfiguracji urządzenia użytkownika, dzięki czemu pobierze on tylko kod i zasoby potrzebne do uruchomienia Twojej aplikacji. Publikowanie wielu plików APK jest przydatne, jeśli publikujesz aplikację w sklepie, który nie obsługuje formatu AAB. W takim przypadku musisz samodzielnie tworzyć, podpisywać i zarządzać każdym plikiem APK.
Chociaż w miarę możliwości lepiej jest tworzyć jeden plik APK obsługujący wszystkie urządzenia docelowe, może to spowodować, że plik APK będzie bardzo duży ze względu na pliki obsługujące wiele interfejsów binarnych aplikacji (ABI). Jednym ze sposobów na zmniejszenie rozmiaru pliku APK jest utworzenie kilku plików APK, które zawierają pliki dla konkretnych interfejsów ABI.
Gradle może tworzyć osobne pliki APK, które zawierają tylko kod i zasoby specyficzne dla każdego interfejsu ABI. Na tej stronie opisaliśmy, jak skonfigurować kompilację, aby generować wiele plików APK. Jeśli chcesz utworzyć różne wersje aplikacji, które nie są oparte na interfejsie ABI, użyj wariantów kompilacji.
Konfigurowanie kompilacji pod kątem wielu plików APK
Aby skonfigurować kompilację dla wielu plików APK, dodaj blok
splits do pliku build.gradle na poziomie modułu. W bloku splits podaj blok abi, który określa, jak Gradle ma generować pakiety APK dla poszczególnych interfejsów ABI.
Konfigurowanie wielu plików APK dla interfejsów ABI
Aby utworzyć osobne pliki APK dla różnych interfejsów ABI, dodaj blok abi w bloku splits. W bloku abi podaj listę
odpowiednich interfejsów ABI.
Do konfigurowania wielu plików APK na ABI służą te opcje Gradle DSL:
-
enablew przypadku skryptu Groovy lubisEnablew przypadku skryptu Kotlin. - Jeśli ustawisz ten element na
true, Gradle wygeneruje wiele plików APK na podstawie zdefiniowanych przez Ciebie interfejsów ABI. Wartością domyślną jestfalse. -
exclude -
Określa rozdzieloną przecinkami listę interfejsów ABI, dla których Gradle nie ma generować osobnych plików APK. Użyj
exclude, jeśli chcesz wygenerować pliki APK dla większości interfejsów ABI, ale musisz wykluczyć kilka interfejsów ABI, których Twoja aplikacja nie obsługuje. -
reset() -
Czyści domyślną listę interfejsów ABI. Używaj tylko w połączeniu z elementem
include, aby określić interfejsy ABI, które chcesz dodać.Poniższy fragment kodu ustawia listę interfejsów ABI na
x86ix86_64, wywołującreset(), aby wyczyścić listę, a następnie używającinclude: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 -
Określa rozdzieloną przecinkami listę interfejsów ABI, dla których Gradle ma generować pakiety APK. Używaj tylko w połączeniu z
reset(), aby określić dokładną listę interfejsów ABI. -
universalApkw przypadku skryptu Groovy lubisUniversalApkw przypadku skryptu Kotlin. -
Jeśli
true, Gradle generuje uniwersalny plik APK oprócz plików APK dla poszczególnych interfejsów ABI. Uniwersalny plik APK zawiera kod i zasoby dla wszystkich interfejsów ABI w jednym pliku APK. Wartością domyślną jestfalse.
Poniższy przykład generuje osobny pakiet APK dla każdego interfejsu ABI: x86 i x86_64. W tym celu użyj reset()
, aby zacząć od pustej listy interfejsów ABI, a potem include z listą interfejsów ABI, z których każdy otrzymuje plik 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 } } }
Listę obsługiwanych interfejsów ABI znajdziesz w artykule Obsługiwane interfejsy ABI.
Projekty bez kodu natywnego lub C++
W przypadku projektów bez kodu natywnego lub C++ panel Warianty kompilacji ma 2 kolumny: Moduł i Aktywny wariant kompilacji, jak pokazano na rysunku 1.

Rysunek 1. Panel Build Variants (Warianty kompilacji) ma 2 kolumny w przypadku projektów bez kodu natywnego lub C++.
Wartość Aktywny wariant kompilacji modułu określa wariant kompilacji, który jest wdrażany i widoczny w edytorze. Aby przełączać się między wariantami, kliknij komórkę Aktywny wariant kompilacji w przypadku modułu i wybierz odpowiedni wariant z pola listy.
Projekty z kodem natywnym lub C++
W przypadku projektów z kodem natywnym lub C++ panel Warianty kompilacji ma 3 kolumny: Moduł, Aktywny wariant kompilacji i Aktywny interfejs ABI, jak pokazano na rysunku 2.
Rysunek 2. W panelu Warianty kompilacji w przypadku projektów z kodem natywnym lub C++ dodawana jest kolumna Aktywny ABI.
Wartość Aktywna odmiana kompilacji modułu określa odmianę kompilacji, która jest wdrażana i widoczna w edytorze. W przypadku modułów natywnych wartość Aktywny interfejs ABI określa interfejs ABI używany przez edytor, ale nie ma wpływu na to, co jest wdrażane.
Aby zmienić typ kompilacji lub ABI:
- Kliknij komórkę w kolumnie Aktywny wariant kompilacji lub Aktywny interfejs ABI.
- Wybierz z listy odpowiedni wariant lub ABI. Automatycznie uruchomi się nowa synchronizacja.
Zmiana dowolnej kolumny w przypadku aplikacji lub modułu biblioteki powoduje zastosowanie zmiany do wszystkich wierszy zależnych.
Konfigurowanie wersji
Domyślnie, gdy Gradle generuje wiele plików APK, każdy z nich ma te same informacje o wersji określone w pliku build.gradle lub build.gradle.kts na poziomie modułu. Sklep Google Play nie zezwala na przesyłanie wielu plików APK tej samej aplikacji, które mają te same informacje o wersji. Dlatego przed przesłaniem do Sklepu Play musisz zadbać o to, aby każdy plik APK miał unikalny
versionCode.
Możesz skonfigurować plik build.gradle na poziomie modułu, aby zastąpić versionCode dla każdego pliku APK. Tworząc mapowanie, które przypisuje unikalną wartość liczbową do każdego interfejsu ABI, dla którego konfigurujesz wiele plików APK, możesz zastąpić wyjściowy kod wersji wartością, która łączy kod wersji zdefiniowany w bloku defaultConfig lub productFlavors z wartością liczbową przypisaną do interfejsu ABI.
W tym przykładzie pakiet APK dla interfejsu x86 ABI
ma versionCode 2004, a interfejs x86_64 ABI
ma versionCode 3004.
Przypisanie kodów wersji w dużych odstępach, np. 1000, umożliwia późniejsze przypisanie unikalnych kodów wersji, jeśli zajdzie potrzeba zaktualizowania aplikacji. Jeśli na przykład w kolejnej aktualizacji wartość defaultConfig.versionCode wzrośnie do 5, Gradle przypisze wartość versionCode = 2005 do pliku APK x86 i 3005 do pliku APK x86_64.
Wskazówka: jeśli kompilacja zawiera uniwersalny plik APK, przypisz mu kod wersji versionCode, który jest niższy niż kody wersji pozostałych plików APK.
Sklep Google Play instaluje wersję aplikacji, która jest zgodna z urządzeniem docelowym i ma najwyższy versionCode. Przypisanie niższego versionCode do uniwersalnego pliku APK sprawia, że Sklep Google Play próbuje zainstalować jeden z plików APK, zanim przejdzie do uniwersalnego pliku APK. Poniższy przykładowy kod
rozwiązuje ten problem, nie zastępując domyślnego versionCode uniwersalnego pakietu 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)) } } } }
Więcej przykładów alternatywnych schematów kodów wersji znajdziesz w artykule Przypisywanie kodów wersji.
Tworzenie wielu plików APK
Po skonfigurowaniu pliku build.gradle lub build.gradle.kts na poziomie modułu w celu utworzenia wielu plików APK kliknij Build > Build APK (Utwórz > Utwórz plik APK), aby utworzyć wszystkie pliki APK dla aktualnie wybranego modułu w okienku Project (Projekt). Gradle tworzy pliki APK dla każdego interfejsu ABI w katalogu build/outputs/apk/ projektu.
Gradle tworzy plik APK dla każdego interfejsu ABI, dla którego skonfigurujesz wiele plików APK.
Na przykład ten fragment kodu build.gradle umożliwia tworzenie wielu plików APK dla interfejsów x86 i x86_64:
Groovy
... splits { abi { enable true reset() include "x86", "x86_64" } }
Kotlin
... splits { abi { isEnable = true reset() include("x86", "x86_64") } }
Dane wyjściowe z przykładowej konfiguracji obejmują te 4 pliki APK:
app-X86-release.apk: zawiera kod i zasoby interfejsux86ABI.app-X86_64-release.apk: zawiera kod i zasoby interfejsux86_64ABI.
Podczas tworzenia wielu plików APK na podstawie interfejsu ABI Gradle generuje plik APK zawierający kod i zasoby dla wszystkich interfejsów ABI tylko wtedy, gdy w bloku universalApk true w pliku splits.abi (w przypadku Groovy) lub w bloku universalApk true w pliku build.gradle.kts (w przypadku skryptu Kotlin) określisz build.gradle.splits.abiisUniversalApk = true
Format nazwy pliku APK
Podczas tworzenia wielu plików APK Gradle generuje nazwy plików APK zgodnie z tym schematem:
modulename-ABI-buildvariant.apk
Komponenty programu to:
-
modulename - Określa nazwę tworzonego modułu.
-
ABI -
Jeśli włączonych jest wiele plików APK dla ABI, określa ABI dla pliku APK, np.
x86. -
buildvariant -
Określa kompilowaną odmianę kompilacji, np.
debug.