Создание нескольких 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.

Для настройки нескольких APK для разных ABI используются следующие параметры Gradle DSL:

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. Значение по умолчанию: false.

В примере ниже создается отдельный APK для каждого ABI: x86 и x86_64. Для этого сначала нужно указать пустой список ABI с помощью reset(), а затем – список ABI, для каждого из которых будет создан APK-файл, с помощью include.

Яркий

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 приведен в этой статье.

Проекты без нативного кода или кода C++

Для проектов без нативного кода или кода C++ на панели Варианты сборки есть два столбца: Модуль и Активный вариант сборки (см. рисунок 1).

На панели Build Variants (Варианты сборки) есть два столбца для проектов без нативного кода или кода C++.
Рисунок 1. На панели Варианты сборки есть два столбца для проектов без нативного кода или кода C++.

Значение Active Build Variant (Активный вариант сборки) для модуля определяет вариант сборки, который развертывается и отображается в редакторе. Чтобы переключиться между вариантами, нажмите на ячейку Active Build Variant (Активный вариант сборки) для модуля и выберите нужный вариант из списка.

Проекты с нативным кодом или кодом C++

Для проектов с нативным кодом или кодом на C++ на панели Варианты сборки есть три столбца: Модуль, Активный вариант сборки и Активный ABI (см. рисунок 2).

На панели "Варианты сборки" добавлен столбец "Активный ABI" для проектов с нативным кодом или кодом C++.
Рисунок 2. На панели Варианты сборки для проектов с нативным кодом или кодом C++ добавлен столбец Активный ABI.

Значение Active Build Variant (Активный вариант сборки) для модуля определяет, какой вариант сборки будет развернут и показан в редакторе. Для нативных модулей значение Active ABI (Активный ABI) определяет ABI, который использует редактор, но не влияет на то, что развертывается.

Чтобы изменить тип сборки или ABI, выполните следующие действия:

  1. Нажмите на ячейку в столбце Активный вариант сборки или Активный ABI.
  2. Выберите нужный вариант или ABI из списка. Новая синхронизация запустится автоматически.

Изменение любого столбца для модуля приложения или библиотеки применяется ко всем зависимым строкам.

Настройка версий

По умолчанию, когда Gradle генерирует несколько APK, у каждого из них одна и та же информация о версии, указанная в файле build.gradle или build.gradle.kts на уровне модуля. Поскольку в Google Play нельзя загрузить несколько APK-файлов одного приложения с одинаковой информацией о версии, перед загрузкой убедитесь, что у каждого файла уникальный код versionCode.

Вы можете настроить файл 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, нажмите Build (Сборка) > Build APK (Создать APK), чтобы создать все APK для выбранного модуля на панели Project (Проект). 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-файла:

  • app-X86-release.apk – содержит код и ресурсы для ABI x86.
  • 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 генерирует их названия по следующей схеме:

modulename-ABI-buildvariant.apk

Компоненты схемы:

modulename
Указывает название создаваемого модуля.
ABI
Если включено несколько APK для ABI, указывает ABI для APK, например x86.
buildvariant
Указывает на создаваемый вариант сборки, например debug.