Tworzenie wielu pakietów APK

Uwaga: od sierpnia 2021 r. aplikacje muszą być opublikowane jako pakiety aplikacji. Jeśli opublikujesz aplikację w Google Play, utwórz i prześlij pakiet Android App Bundle. Kiedy to Google Play automatycznie generuje i udostępnia zoptymalizowane pliki APK konfiguracji urządzeń poszczególnych użytkowników. Pobierają oni tylko kod i zasoby do uruchomienia aplikacji. Publikowanie wielu plików APK przydaje się, jeśli: w sklepie, który nie obsługuje formatu pakietu AAB. W takim przypadku musisz samodzielnie utworzyć i podpisać każdy plik APK oraz nim zarządzać.

Lepiej jednak utworzyć jeden plik APK do obsługi wszystkich urządzeń docelowych. (w miarę możliwości może to spowodować utworzenie bardzo dużego pakietu APK z powodu plików obsługa wielu elementów gęstości ekranu lub Plik binarny aplikacji Interfejsy (ABI). Jednym ze sposobów zmniejszenia rozmiaru pliku APK jest utworzenie wiele plików APK, zawierają pliki o określonej gęstości ekranu lub interfejsów ABI.

Gradle może tworzyć oddzielne pliki APK zawierające tylko kod i określone zasoby do poszczególnych gęstości i interfejsu ABI. Na tej stronie dowiesz się, jak skonfigurować kompilację wiele plików APK. Jeśli chcesz utworzyć różne wersje aplikacji które nie są oparte na gęstości ekranu lub interfejsu ABI, zamiast tego użyj utwórz warianty.

Konfigurowanie kompilacji dla wielu plików APK

Aby skonfigurować kompilację pod kątem wielu plików APK, dodaj atrybut splits na poziomie modułu build.gradle. W ciągu Blokada splits, podaj blok density, który określa sposób generowania przez Gradle pliki APK według gęstości lub blok abi, który określa sposób obsługi Gradle aby generować pliki APK w formacie ABI. Można podać zarówno gęstość, jak i bloki ABI, system kompilacji tworzy 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 atrybut Blok density w Twojej Blokada: splits. W bloku density podaj listę pożądanej gęstości i zgodnych rozmiarów ekranu. Korzystaj tylko z listy określonych rozmiarów ekranu. <compatible-screens> w pliku manifestu każdego pakietu APK.

Poniższe opcje DSL Gradle służą do konfigurowania wielu plików APK dla gęstości ekranu:

enable – Groovy, isEnable – skrypt Kotlin
Jeśli ustawisz ten element na wartość true, Gradle wygeneruje wiele plików APK. zgodnie z określonymi gęstościami ekranu. Wartość domyślna to false
exclude
Określa rozdzieloną przecinkami listę gęstości, których Gradle nie ma być obsługiwana aby wygenerować osobne pliki APK. Użyj exclude, jeśli: chcą generować pliki APK dla większości gęstości, ale muszą wykluczyć kilka gęstości, których Twoja aplikacja nie obsługuje.
reset()

Czyści domyślną listę gęstości ekranu. Używaj tylko w połączeniu z include, aby określić preferowane gęstości dodaj.

Ten fragment kodu ustawia listę gęstości na ldpi i xxhdpi, dzwoniąc pod numer reset() aby wyczyścić listę, a następnie użyć include:

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 rozdzielaną przecinkami listę gęstości, które ma generować Gradle Pliki APK dla. Używaj tylko w połączeniu z właściwością reset(), aby określić dokładną listę gęstości.
compatibleScreens

Określa rozdzielaną przecinkami listę zgodnych rozmiarów ekranu. Powoduje to wstrzyknięcie kodu pasujące <compatible-screens> węzeł w pliku manifestu instancji każdego pliku APK.

To ustawienie zapewnia wygodny sposób zarządzania oboma ekranami gęstości i rozmiarów ekranu w tej samej sekcji build.gradle. Korzystając jednak z metody <compatible-screens> może ograniczać typy urządzeń z Twoją aplikacją. Alternatywne sposoby obsługi różnych rozmiarów ekranu, zapoznaj się z przeglądzie zgodności ekranów.

Każdy plik APK oparty na gęstości ekranu zawiera <compatible-screens> tag z konkretnymi ograniczeniami o typach ekranów obsługiwanych przez plik APK – nawet jeśli publikujesz pliki APK – niektóre nowe urządzenia nie pasują do wielu filtrów 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 <compatible-screens>. Opublikuj wraz z pakietami APK dla określonej gęstości, aby utworzyć plik zastępczy urządzeń, które nie pasują do plików APK z parametrem <compatible-screens>.

Ten przykład pozwala wygenerować oddzielny plik APK dla każdego ekran gęstość oprócz ldpi, xxhdpi i xxxhdpi. Jest to możliwe dzięki użyciu funkcji exclude do usuwania te trzy gęstości z domyślnej listy wszystkich gęstości.

Odlotowe

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 kompilacji wersji aplikacji na określone typy ekranów i urządzeń, zapoznaj się z Deklaruj ograniczenia obsługę ekranu.

Konfigurowanie wielu plików APK pod kątem interfejsów ABI

Aby tworzyć oddzielne pliki APK dla różnych interfejsów ABI, dodaj blok abi wewnątrz Blokada: splits. W bloku abi podaj listę przy użyciu interfejsów ABI.

Poniższe opcje DSL narzędzia Gradle służą do konfigurowania wielu plików APK Interfejs ABI:

enable w przypadku Groovy, a isEnable dla skryptu Kotlin
Jeśli ustawisz ten element na true, Gradle wygeneruje wiele Pliki APK utworzone na podstawie zdefiniowanych przez Ciebie interfejsów ABI. Wartością domyślną jest false.
exclude
Określa rozdzieloną przecinkami listę interfejsów ABI, których Gradle nie ma używać aby wygenerować osobne pliki APK. Aby wygenerować tag: exclude dla większości interfejsów ABI, ale musisz wykluczyć kilka interfejsów ABI, których nie obsługuje Twoja aplikacja .
reset()

Czyści domyślną listę interfejsów ABI. Używaj tylko w połączeniu z include określający interfejsy ABI, które chcesz dodać.

Ten fragment kodu ustawia listę interfejsów ABI tylko na x86 i x86_64, wywołując funkcję reset() w celu wyczyszczenia listy oraz następnie za pomocą 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
Określa rozdzieloną przecinkami listę interfejsów ABI, które mają generować pliki APK przez Gradle . Używaj tylko w połączeniu z właściwością reset(), aby określić dokładne z listą interfejsów ABI.
universalApk w przypadku Groovy, a isUniversalApk w przypadku pismo Kotlin

Jeśli zasada ma wartość true, Gradle generuje oprócz pliki APK zgodne z interfejsem ABI. Uniwersalny plik APK zawiera kod i zasoby dla wszystkich interfejsów ABI w pojedynczy plik APK. Wartością domyślną jest false.

Pamiętaj, że ta opcja jest dostępne w bloku splits.abi. Podczas tworzenia wielu plików APK zgodnie z gęstością ekranu, Gradle zawsze generuje uniwersalny plik APK, zawiera kod i zasoby dla wszystkich gęstości ekranu.

Ten przykład pozwala wygenerować oddzielny plik APK dla każdego interfejsu ABI: x86 i x86_64. Służy do tego funkcja reset() zacznij od pustej listy interfejsów ABI, po której następuje ciąg include i listę interfejsów ABI, z których każdy otrzymuje pakiet APK.

Odlotowe

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 tutaj: Obsługiwane interfejsy ABI.

Projekty bez kodu natywnego/C++

W przypadku projektów bez kodu natywnego lub C++ panel Utwórz warianty zawiera 2 elementy kolumny: Module i Aktywna kompilacja Wariant, jak pokazano na ilustracji 1.

Panel wariantów kompilacji,
Rysunek 1. Panel Utwórz warianty zawiera 2 kolumny dotyczące projektów bez kod natywny/kod C++.

Wartość Wariant aktywnej kompilacji dla: określa wariant kompilacji, który jest wdrożony i widoczny w edytorze. Aby przełączać się między wariantami, kliknij komórkę Aktywny wariant kompilacji modułu i wybierz na liście odpowiedni wariant.

Projekty z kodem natywnym/C++

W przypadku projektów z kodem natywnym lub C++ panel Utwórz warianty zawiera 3 elementy kolumny: Moduł i Aktywna kompilacja Wariant i Aktywny interfejs ABI, jak pokazano na ilustracji 2.

Rysunek 2. W panelu Utwórz warianty pojawi się kolumna Aktywny interfejs ABI: projektów z kodem natywnym/C++.

Wartość Aktywnej kompilacji dla modułu. określa wariant kompilacji, który został wdrożony i jest widoczny w edytorze. W przypadku modułów natywnych wartość Aktywny interfejs ABI określa interfejs ABI, który edytor ale nie ma wpływu na to, co jest wdrażane.

Aby zmienić typ kompilacji lub interfejs ABI:

  1. Kliknij komórkę aktywnej kompilacji. lub Active ABI.
  2. Wybierz z listy odpowiedni wariant lub interfejs ABI . Automatycznie zostanie uruchomiona nowa synchronizacja.

Zmiana jednej z kolumn w module aplikacji lub biblioteki spowoduje zastosowanie zmiany do wszystkich wiersze zależne.

Skonfiguruj obsługę wersji

Domyślnie, gdy Gradle generuje wiele plików APK, każdy z nich ma taki sam zgodnie z informacjami o wersji, które są określone na poziomie modułu, build.gradle lub build.gradle.kts. Ponieważ W Sklepie Google Play nie można mieć wielu plików APK tej samej aplikacji, które wszystkie zawierają o takich samych informacjach o wersji, musisz upewnić się, że każdy plik APK ma unikalny identyfikator versionCode przed przesłaniem aplikacji do Sklepu Play.

Plik build.gradle na poziomie modułu możesz skonfigurować tak, zastąp versionCode dla każdego pliku APK. Tworząc mapowanie przypisującej unikalną wartość liczbową do każdego skonfigurowanego interfejsu ABI i gęstości dla wielu plików APK, możesz zastąpić kod wersji wyjściowej wartością określającą łączy kod wersji zdefiniowany w zasadzie defaultConfig lub Blok productFlavors z wartością numeryczną przypisaną do funkcji lub interfejs ABI.

W poniższym przykładzie pakiet APK dla interfejsu ABI x86 uzyskuje versionCode z 2004 r. i interfejs x86_64 ABI otrzyma versionCode o wartości 3004.

Przypisanie kodów wersji dużymi przyrostami, na przykład 1000, pozwala przypisać później unikalne kody wersji, aby zaktualizować aplikację. Dla: jeśli na przykład defaultConfig.versionCode wykona w parametrze po kolejnej aktualizacji Gradle przypisuje wartość versionCode z 2005 r. plik APK x86 i kod 3005 do pliku APK x86_64.

Wskazówka: jeśli kompilacja zawiera uniwersalny plik APK, przypisz do niego versionCode to wynik niższy niż w przypadku jakiegokolwiek innego pliku APK. Ponieważ Sklep Google Play instaluje Twoją aplikację, która jest jest zgodny z urządzeniem docelowym i ma najwyższą versionCode, przypisuję niższą wartość versionCode do który gwarantuje, że Sklep Google Play spróbuje zainstalować jedną z Twoich plików APK. Poniżej znajduje się przykładowy kod. zajmuje się tym, nie zastępując uniwersalnego pakietu APK domyślna wartość versionCode.

Odlotowe

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 schematów kodu wersji alternatywnych znajdziesz w artykule Przypisanie kodów wersji.

Tworzenie wielu plików APK

Po skonfigurowaniu modułu build.gradle lub build.gradle.kts pliku, aby utworzyć kilka plików APK, kliknij Kompilacja > Utwórz plik APK, by utworzyć wszystkie pakiety APK przeznaczone wybrany moduł w panelu Projekt. Gradle tworzy pliki APK dla każdej gęstości lub interfejsu ABI w: build/outputs/apk/ projektu katalogu.

Gradle tworzy plik APK dla każdej gęstości lub interfejsu ABI, dla którego skonfigurujesz wiele plików APK. Jeśli włączysz wiele plików APK zarówno dla gęstości, jak i interfejsów ABI, Gradle utworzy plik APK dla każdej kombinacji gęstości i interfejsu ABI.

Na przykład: Fragment kodu build.gradle umożliwia tworzenie wielu plików APK dla usług mdpi oraz Gęstości: hdpi, a także interfejsy ABI x86 i x86_64:

Odlotowe

...
  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 przykładowej konfiguracji zawierają te 4 pliki APK:

  • app-hdpiX86-release.apk: zawiera kod i zasoby dla języka: Gęstość hdpi i x86 ABI.
  • app-hdpiX86_64-release.apk: zawiera kod i zasoby dla języka: Gęstość hdpi i x86_64 ABI.
  • app-mdpiX86-release.apk: zawiera kod i zasoby dla języka: Gęstość mdpi i x86 ABI.
  • app-mdpiX86_64-release.apk: zawiera kod i zasoby dla języka: Gęstość mdpi i x86_64 ABI.

W przypadku tworzenia wielu plików APK opartych na gęstości ekranu Gradle zawsze generuje uniwersalny plik APK, który zawiera kod i zasoby dla wszystkich gęstości, a także pakiety APK dla poszczególnych gęstości.

Podczas tworzenia wielu plików APK na podstawie ABI, Gradle generuje tylko plik APK zawierający kod i zasoby dla wszystkich Interfejsy ABI, jeśli określisz universalApk true w parametrze Blok splits.abi w pliku build.gradle (dla Groovy) lub isUniversalApk = true w Blok splits.abi w pliku build.gradle.kts (dla skryptu Kotlin).

Format nazwy pliku APK

Podczas tworzenia wielu plików APK Gradle generuje nazwy plików APK za pomocą tych reguł: schemat:

modulename-screendensityABI-buildvariant.apk

Elementy schematu to:

modulename
Określa nazwę tworzonego modułu.
screendensity
Jeśli włączonych jest wiele plików APK gęstości ekranu, określa ekran dla pliku APK, np. mdpi.
ABI

Jeśli włączonych jest wiele plików APK dla ABI, określa interfejs ABI dla pliku APK, np. jako x86.

Jeśli włączonych jest wiele plików APK zarówno dla gęstości ekranu, jak i interfejsu ABI, Gradle łączy nazwę gęstości z nazwą interfejsu ABI, np. mdpiX86 Jeśli włączono interfejs universalApk dla poszczególnych interfejsów ABI plików APK, Gradle używa wersji universal jako części ABI uniwersalnego pliku APK nazwa pliku.

buildvariant
Określa kompilowany wariant kompilacji, np. debug.

Na przykład podczas tworzenia mdpi pakietu APK o gęstości ekranu dla aplikacji wersja myApp do debugowania, nazwa pliku APK to myApp-mdpi-debug.apk Premiera czyli w wersji myApp skonfigurowanej do tworzenia wielu plików APK dla Gęstość ekranu mdpi i interfejs ABI x86 ma nazwę pliku APK myApp-mdpiX86-release.apk