Uwaga: 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 konfiguracji urządzenia każdego użytkownika, aby pobierał tylko kod i zasoby potrzebne do uruchomienia aplikacji. Publikowanie wielu plików APK jest przydatne, jeśli publikujesz w sklepie, który nie obsługuje formatu AAB. W takim przypadku musisz samodzielnie tworzyć, podpisywać i zarządzać plikami APK.
Chociaż w miarę możliwości lepiej jest utworzyć jeden plik APK, który będzie obsługiwał wszystkie urządzenia docelowe, może to spowodować, że plik APK będzie bardzo duży z powodu plików obsługujących różne gęstości ekranu lub interfejsów binarnych aplikacji (ABI). Jednym ze sposobów zmniejszenia rozmiaru pliku APK jest utworzenie kilku plików APK zawierających pliki przeznaczone do określonych gęstości ekranu lub ABI.
Gradle może tworzyć osobne APK-i zawierające tylko kod i zasoby przeznaczone dla każdej gęstości lub 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 gęstości ekranu lub ABI, użyj wariantów kompilacji.
Konfigurowanie kompilacji na potrzeby wielu plików APK
Aby skonfigurować kompilację na potrzeby wielu plików APK, dodaj blok
splits
do pliku build.gradle
na poziomie modułu. W bloku splits
podaj blok density
, który określa, jak Gradle ma generować pliki APK dla poszczególnych gęstości, lub blok abi
, który określa, jak Gradle ma generować pliki APK dla poszczególnych ABI. Możesz podać zarówno bloki gęstości, jak i bloki interfejsu ABI. System kompilacji utworzy plik APK dla każdej kombinacji gęstości i interfejsu ABI.
Konfigurowanie wielu plików APK pod kątem gęstości ekranu
Aby utworzyć osobne pliki APK dla różnych gęstości ekranu, dodaj blok density
w bloku splits
. W bloku density
podaj listę żądanych gęstości ekranu i obsługiwanych rozmiarów ekranu. Używaj listy obsługiwanych rozmiarów ekranu tylko wtedy, gdy potrzebujesz określonych elementów
<compatible-screens>
w pliku manifestu każdego pliku APK.
Aby skonfigurować wiele plików APK pod kątem gęstości ekranu, użyj tych opcji Gradle DSL:
-
enable
– skrypt Groovy,isEnable
– skrypt Kotlin - Jeśli ustawisz tę wartość na
true
, Gradle wygeneruje kilka plików APK na podstawie zdefiniowanych przez Ciebie gęstości ekranu. Wartością domyślną jestfalse
. -
exclude
- Określa rozdzieloną przecinkami listę gęstości, dla których nie chcesz, aby Gradle generował osobne pliki APK. Użyj opcji
exclude
, jeśli chcesz wygenerować pliki APK dla większości wartości gęstości, ale musisz wykluczyć kilka wartości gęstości, których nie obsługuje Twoja aplikacja. -
reset()
-
Czyści domyślną listę gęstości ekranu. Używaj tylko w połączeniu z elementem
include
, aby określić gęstości, które chcesz dodać.Ten fragment kodu ustawia listę gęstości na tylko
ldpi
ixxhdpi
, wywołując funkcjęreset()
do wyczyszczenia listy, a potem używając funkcjiinclude
:reset() // Clears the default list from all densities // to no densities. include "ldpi", "xxhdpi" // Specifies the two densities to generate APKs // for.
-
include
- Określa listę rozdzielczości rozdzielonych przecinkami, dla których Gradle ma wygenerować pliki APK. Używaj tylko w połączeniu z opcją
reset()
, aby określić dokładną listę gęstości. -
compatibleScreens
-
Określa listę zgodnych rozmiarów ekranu rozdzielonych przecinkami. W ten sposób w pliku manifestu każdego pakietu APK zostanie wstrzyknięty odpowiedni węzeł
<compatible-screens>
.To ustawienie zapewnia wygodny sposób zarządzania gęstością pikseli i rozmiarami ekranu w tej samej sekcji
build.gradle
. Użycie usługi<compatible-screens>
może jednak ograniczyć typy urządzeń, na których działa Twoja aplikacja. Informacje o innych sposobach obsługi różnych rozmiarów ekranu znajdziesz w omówieniu zgodności z ekranami.
Każdy plik APK, który jest oparty na gęstości ekranu, zawiera tag <compatible-screens>
z określonymi ograniczeniami dotyczącymi typów ekranów, które obsługuje APK (nawet jeśli opublikujesz kilka plików APK), więc niektóre nowe urządzenia nie będą pasować do filtrów wielu plików APK. W związku z tym Gradle zawsze generuje dodatkowy uniwersalny plik APK zawierający zasoby dla wszystkich gęstości ekranu i nie zawiera tagu <compatible-screens>
. Opublikuj ten uniwersalny plik APK wraz z plikami APK dla poszczególnych wartości gęstości, aby zapewnić alternatywne rozwiązanie dla urządzeń, które nie pasują do plików APK z tagiem <compatible-screens>
.
W tym przykładzie generowany jest osobny plik APK dla każdej gęstości ekranu, z wyjątkiem wartości ldpi
, xxhdpi
i xxxhdpi
. Aby to zrobić, użyj parametru exclude
, aby usunąć te 3 gęstości z domyślnej listy wszystkich gęstości.
Groovy
android { ... splits { // Configures multiple APKs based on screen density. density { // Configures multiple APKs based on screen density. enable true // Specifies a list of screen densities you don't want Gradle to create multiple APKs for. exclude "ldpi", "xxhdpi", "xxxhdpi" // Specifies a list of compatible screen size settings for the manifest. compatibleScreens 'small', 'normal', 'large', 'xlarge' } } }
Kotlin
android { ... splits { // Configures multiple APKs based on screen density. density { // Configures multiple APKs based on screen density. isEnable = true // Specifies a list of screen densities you don't want Gradle to create multiple APKs for. exclude("ldpi", "xxhdpi", "xxxhdpi") // Specifies a list of compatible screen size settings for the manifest. compatibleScreens("small", "normal", "large", "xlarge") } } }
Więcej informacji o dostosowywaniu różnych wersji aplikacji do konkretnych typów ekranów i urządzeń znajdziesz w artykule Zadeklarowanie obsługi ograniczonych ekranów.
Konfigurowanie wielu plików APK na potrzeby interfejsów ABI
Aby utworzyć osobne pliki APK dla różnych ABI, dodaj blok abi
w bloku splits
. W bloku abi
podaj listę żądanych ABI.
Aby skonfigurować wiele plików APK na jeden ABI, użyj tych opcji Gradle DSL:
-
enable
w przypadku Groovy lubisEnable
w przypadku skryptu Kotlin - Jeśli ustawisz ten element na
true
, Gradle wygeneruje wiele plików APK na podstawie zdefiniowanych przez Ciebie ABI. Wartością domyślną jestfalse
. -
exclude
- Określa listę ABI oddzielonych przecinkami, dla której nie chcesz, aby Gradle generował osobne pliki APK. Użyj opcji
exclude
, jeśli chcesz wygenerować pliki APK dla większości interfejsów ABI, ale musisz wykluczyć kilka interfejsów, których Twoja aplikacja nie obsługuje. -
reset()
-
Czyści domyślną listę ABI. Używaj tylko w połączeniu z elementem
include
, aby określić ABI, które chcesz dodać.Ten fragment kodu ustawia listę ABI na
x86
ix86_64
, wywołując funkcjęreset()
, aby ją wykasować, a potem używając funkcjiinclude
: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 listę ABI oddzieloną przecinkami, dla której Gradle ma wygenerować pliki APK. Używaj tylko w połączeniu z opcją
reset()
, aby określić dokładną listę interfejsów ABI. -
universalApk
dla Groovy lubisUniversalApk
dla skryptu Kotlina. -
Jeśli
true
, Gradle generuje uniwersalny plik APK oprócz plików APK dla poszczególnych ABI. Uniwersalny plik APK zawiera kod i zasoby dla wszystkich interfejsów ABI w jednym pliku APK. Wartością domyślną jestfalse
.Ta opcja jest dostępna tylko w bloku
splits.abi
. Podczas kompilowania wielu plików APK na podstawie gęstości ekranu Gradle zawsze generuje uniwersalny plik APK, który zawiera kod i zasoby dla wszystkich gęstości ekranu.
W tym przykładzie generowany jest osobny pakiet APK dla każdego ABI: x86
i x86_64
. Aby to zrobić, użyj instrukcji reset()
, aby zacząć od pustej listy interfejsów ABI, a następnie instrukcji include
, aby utworzyć listę interfejsów ABI, z których każdy ma swój 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 Aktywna kompilacja (patrz rysunek 1).
Rysunek 1. Panel Generowanie wariantów zawiera 2 kolumny w przypadku projektów bez kodu natywnych/C++.
Wartość Aktywna wersja kompilacji w module określa wersję kompilacji, która jest wdrożona i widoczna w edytorze. Aby przełączać się między wariantami, kliknij komórkę Aktywny wariant kompilacji w module 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 zawiera 3 kolumny: Moduł, Aktywna wersja kompilacji i Aktywna ABI, jak pokazano na rysunku 2.
Rysunek 2. Panel Warianty kompilacji dodaje kolumnę Aktywny ABI do projektów z kodem natywnym lub C++.
Wartość Aktywna odmiana wersji w module określa wersję, która jest wdrażana i widoczna w edytorze. W przypadku modułów natywnych wartość Aktywny ABI określa 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ę kolumny Aktywna wersja kompilacji lub Aktywna ABI.
- Wybierz odpowiedni wariant lub ABI z pola listy. Nowa synchronizacja zostanie uruchomiona automatycznie.
Zmiana dowolnej kolumny w aplikacji lub module biblioteki powoduje zastosowanie tej zmiany do wszystkich zależnych wierszy.
Konfigurowanie obsługi wersji
Domyślnie, gdy Gradle generuje wiele plików APK, każdy z nich ma te same informacje o wersji, które są określone w pliku build.gradle
lub build.gradle.kts
na poziomie modułu. Sklep Google Play nie zezwala na używanie wielu plików APK tej samej aplikacji z tymi samymi informacjami o wersji. Przed przesłaniem pliku APK do Sklepu Play musisz się upewnić, że każdy plik APK ma unikalny identyfikator
versionCode
.
Możesz skonfigurować plik build.gradle
na poziomie modułu, aby zastąpić versionCode
w przypadku każdego pliku APK. Po utworzeniu mapowania, które przypisuje unikalną wartość liczbową do każdego ABI i gęstości, dla których skonfigurujesz wiele plików APK, możesz zastąpić kod wersji wyjściowej wartością, która łączy kod wersji zdefiniowany w bloku defaultConfig
lub productFlavors
z wartością liczbową przypisaną do gęstości lub ABI.
W tym przykładzie APK dla ABI x86
ma wartość versionCode
2004, a ABI x86_64
– wartość versionCode
3004.
Przypisywanie kodów wersji z dużą liczbą, np. 1000, umożliwia późniejsze przypisywanie unikalnych kodów wersji, jeśli trzeba zaktualizować aplikację. Na przykład jeśli defaultConfig.versionCode
w kolejnych aktualizacjach jest zastępowane przez 5, Gradle przypisuje do pliku APK x86
kod versionCode
2005, a do pliku APK x86_64
– kod 3005.
Wskazówka: jeśli wersja zawiera uniwersalny plik APK, przypisz mu versionCode
mniejszy niż w przypadku innych plików APK.
Sklep Google Play instaluje wersję aplikacji, która jest zgodna z urządzeniem docelowym i ma najwyższą wartość versionCode
. Przypisanie niższej wartości versionCode
do uniwersalnego pliku APK powoduje, że Sklep Google Play próbuje zainstalować jeden z plików APK, zanim użyje uniwersalnego pliku APK. Poniżej znajdziesz przykładowy kod, który nie zastępuje domyślnej wartości versionCode
w uniwersalnym pakiecie 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] // For per-density APKs, create a similar map: // ext.densityCodes = ['mdpi': 1, 'hdpi': 2, 'xhdpi': 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) // For per-density APKs, create a similar map: // val densityCodes = mapOf("mdpi" to 1, "hdpi" to 2, "xhdpi" 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
na poziomie modułu lub pliku build.gradle.kts
w celu utworzenia wielu plików APK kliknij Utwórz > Utwórz plik APK, aby utworzyć wszystkie pliki APK dla wybranego w tym momencie modułu w panelu Projekt. Gradle tworzy pliki APK dla każdej gęstości lub ABI w katalogu build/outputs/apk/
projektu.
Gradle kompiluje plik APK dla każdej gęstości lub interfejsu ABI, dla których skonfigurowano większą liczbę plików APK. Jeśli włączysz wiele plików APK zarówno dla różnych gęstości, jak i dla różnych ABI, Gradle utworzy plik APK dla każdej kombinacji gęstości i ABI.
Na przykład ten fragment kodu build.gradle
umożliwia tworzenie wielu plików APK dla gęstości mdpi
i hdpi
oraz ABI x86
i x86_64
:
Groovy
... splits { density { enable true reset() include "mdpi", "hdpi" } abi { enable true reset() include "x86", "x86_64" } }
Kotlin
... splits { density { isEnable = true reset() include("mdpi", "hdpi") } abi { isEnable = true reset() include("x86", "x86_64") } }
Dane wyjściowe z przykładowej konfiguracji obejmują 4 pliki APK:
app-hdpiX86-release.apk
: zawiera kod i zasoby dla gęstościhdpi
i interfejsu ABIx86
.app-hdpiX86_64-release.apk
: zawiera kod i zasoby dla gęstościhdpi
i interfejsu ABIx86_64
.app-mdpiX86-release.apk
: zawiera kod i zasoby dla gęstościmdpi
i interfejsu ABIx86
.app-mdpiX86_64-release.apk
: zawiera kod i zasoby dla gęstościmdpi
i interfejsu ABIx86_64
.
Podczas kompilowania wielu plików APK na podstawie gęstości ekranu Gradle zawsze generuje uniwersalny plik APK, który zawiera kod i zasoby dla wszystkich gęstości, a także pliki APK dla poszczególnych gęstości.
Podczas kompilowania wielu plików APK na podstawie ABI Gradle generuje plik APK zawierający kod i zasoby dla wszystkich ABI tylko wtedy, gdy w bloku splits.abi
w pliku build.gradle
(w przypadku Groovy) lub w bloku isUniversalApk = true
w pliku build.gradle.kts
(w przypadku skryptu Kotlin) określisz wartość universalApk true
(w przypadku Groovy) lub isUniversalApk = true
(w przypadku skryptu Kotlin).splits.abi
Format nazwy pliku APK
Podczas kompilowania wielu plików APK Gradle generuje nazwy plików APK za pomocą tego schematu:
modulename-screendensityABI-buildvariant.apk
Komponenty schematu:
-
modulename
- Określa nazwę modułu, który jest kompilowany.
-
screendensity
- Jeśli włączono wiele plików APK dla gęstości ekranu, określa gęstość ekranu pliku APK, np.
mdpi
. -
ABI
-
Jeśli włączono wiele plików APK dla ABI, określa ABI pliku APK, na przykład
x86
.Jeśli włączono wiele plików APK zarówno dla gęstości ekranu, jak i ABI, Gradle złącza nazwę gęstości z nazwą ABI, np.
mdpiX86
. Jeśli opcjauniversalApk
jest włączona dla plików APK dla poszczególnych ABI, Gradle używauniversal
jako części ABI uniwersalnego pliku APK. -
buildvariant
- Określa wariant kompilacji, np.
debug
.
Na przykład podczas kompilowania pliku APK o gęstości ekranu mdpi
na potrzeby wersji debugowania aplikacji myApp nazwa pliku APK to myApp-mdpi-debug.apk
. Wersja wydania aplikacji myApp, która jest skonfigurowana do tworzenia wielu plików APK zarówno dla gęstości ekranu mdpi
, jak i interfejsu ABI x86
, ma nazwę pliku APK myApp-mdpiX86-release.apk
.