Настройка вариантов сборки

На этой странице показано, как можно настроить варианты сборки для создания разных версий вашего приложения из одного проекта, а также как правильно управлять зависимостями и конфигурациями подписи.

Каждый вариант сборки представляет собой отдельную версию вашего приложения, которую вы можете построить. Например, вы можете захотеть построить одну версию вашего приложения, которая будет бесплатной с ограниченным набором контента, и другую платную версию, которая будет включать больше. Вы также можете построить разные версии вашего приложения, которые предназначены для разных устройств, на основе уровня API или других вариаций устройств.

Варианты сборки являются результатом использования Gradle определенного набора правил для объединения настроек, кода и ресурсов, настроенных в типах сборки и вариантах продукта. Хотя вы не настраиваете варианты сборки напрямую, вы настраиваете типы сборки и варианты продукта, которые их формируют.

Например, вариант продукта "demo" может указывать определенные функции и требования к устройству, такие как пользовательский исходный код, ресурсы и минимальные уровни API, в то время как тип сборки "debug" применяет другие настройки сборки и упаковки, такие как параметры отладки и ключи подписи. Вариант сборки, который объединяет эти два варианта, — это версия "demoDebug" вашего приложения, и он включает комбинацию конфигураций и ресурсов, включенных в вариант продукта "demo", тип сборки "debug" и набор main/ source.

Настроить типы сборки

Вы можете создавать и настраивать типы сборки внутри блока android файла build.gradle.kts уровня модуля. При создании нового модуля Android Studio автоматически создает типы сборки debug и release. Хотя тип сборки debug не отображается в файле конфигурации сборки, Android Studio настраивает его с помощью debuggable true . Это позволяет отлаживать приложение на защищенных устройствах Android и настраивает подпись приложения с помощью универсального хранилища ключей отладки.

Вы можете добавить тип сборки отладки в свою конфигурацию, если хотите добавить или изменить определенные настройки. Следующий пример указывает applicationIdSuffix для типа сборки отладки и настраивает тип сборки "staging", который инициализируется с использованием настроек из типа сборки отладки:

Котлин

android {
    defaultConfig {
        manifestPlaceholders["hostName"] = "www.example.com"
        ...
    }
    buildTypes {
        getByName("release") {
            isMinifyEnabled = true
            proguardFiles(getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro")
        }

        getByName("debug") {
            applicationIdSuffix = ".debug"
            isDebuggable = true
        }

        /**
         * The `initWith` property lets you copy configurations from other build types,
         * then configure only the settings you want to change. This one copies the debug build
         * type, and then changes the manifest placeholder and application ID.
         */
        create("staging") {
            initWith(getByName("debug"))
            manifestPlaceholders["hostName"] = "internal.example.com"
            applicationIdSuffix = ".debugStaging"
        }
    }
}

Круто

android {
    defaultConfig {
        manifestPlaceholders = [hostName:"www.example.com"]
        ...
    }
    buildTypes {
        release {
            minifyEnabled true
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }

        debug {
            applicationIdSuffix ".debug"
            debuggable true
        }

        /**
         * The `initWith` property lets you copy configurations from other build types,
         * then configure only the settings you want to change. This one copies the debug build
         * type, and then changes the manifest placeholder and application ID.
         */
        staging {
            initWith debug
            manifestPlaceholders = [hostName:"internal.example.com"]
            applicationIdSuffix ".debugStaging"
        }
    }
}

Примечание: Когда вы вносите изменения в файл конфигурации сборки, Android Studio требует, чтобы вы синхронизировали свой проект с новой конфигурацией. Чтобы синхронизировать свой проект, нажмите Sync Now в панели уведомлений, которая появляется при внесении изменений, или нажмите Sync Project из панели инструментов. Если Android Studio заметит какие-либо ошибки в вашей конфигурации, появится окно «Сообщения» с описанием проблемы.

Чтобы узнать больше обо всех свойствах, которые можно настроить с помощью типов сборки, прочтите справочник BuildType .

Настройте вкусы продукта

Создание разновидностей продукта похоже на создание типов сборки. Добавьте разновидности продукта в блок productFlavors в конфигурации сборки и включите нужные вам параметры. Разновидности продукта поддерживают те же свойства, что и defaultConfig , поскольку defaultConfig фактически принадлежит классу ProductFlavor . Это означает, что вы можете предоставить базовую конфигурацию для всех разновидностей в блоке defaultConfig , и каждая разновидность может изменить любое из этих значений по умолчанию, например applicationId . Чтобы узнать больше об идентификаторе приложения, прочитайте раздел Установка идентификатора приложения .

Примечание: Вам все равно нужно указать имя пакета с помощью атрибута package в файле main/ manifest. Вы также должны использовать это имя пакета в исходном коде для ссылки на класс R или для разрешения любой относительной активности или регистрации службы. Это позволяет вам использовать applicationId для присвоения каждому варианту продукта уникального идентификатора для упаковки и распространения без необходимости изменения исходного кода.

Все вкусы должны принадлежать к именованному измерению вкуса, которое является группой вкусов продукта. Вы должны назначить все вкусы измерению вкуса; в противном случае вы получите следующую ошибку сборки.

  Error: All flavors must now belong to a named flavor dimension.
  The flavor 'flavor_name' is not assigned to a flavor dimension.

Если данный модуль определяет только одно измерение разновидности, плагин Android Gradle автоматически назначает все разновидности модуля этому измерению.

Следующий пример кода создает измерение flavor с именем "version" и добавляет "demo" и "full" вкусы продукта. Эти вкусы предоставляют свои собственные applicationIdSuffix и versionNameSuffix :

Котлин

android {
    ...
    defaultConfig {...}
    buildTypes {
        getByName("debug"){...}
        getByName("release"){...}
    }
    // Specifies one flavor dimension.
    flavorDimensions += "version"
    productFlavors {
        create("demo") {
            // Assigns this product flavor to the "version" flavor dimension.
            // If you are using only one dimension, this property is optional,
            // and the plugin automatically assigns all the module's flavors to
            // that dimension.
            dimension = "version"
            applicationIdSuffix = ".demo"
            versionNameSuffix = "-demo"
        }
        create("full") {
            dimension = "version"
            applicationIdSuffix = ".full"
            versionNameSuffix = "-full"
        }
    }
}

Круто

android {
    ...
    defaultConfig {...}
    buildTypes {
        debug{...}
        release{...}
    }
    // Specifies one flavor dimension.
    flavorDimensions "version"
    productFlavors {
        demo {
            // Assigns this product flavor to the "version" flavor dimension.
            // If you are using only one dimension, this property is optional,
            // and the plugin automatically assigns all the module's flavors to
            // that dimension.
            dimension "version"
            applicationIdSuffix ".demo"
            versionNameSuffix "-demo"
        }
        full {
            dimension "version"
            applicationIdSuffix ".full"
            versionNameSuffix "-full"
        }
    }
}

Примечание: Если у вас есть устаревшее приложение (созданное до августа 2021 года), которое вы распространяете с помощью APK в Google Play, для распространения вашего приложения с помощью поддержки нескольких APK в Google Play назначьте одинаковое значение applicationId всем вариантам и дайте каждому варианту разный versionCode . Чтобы распространять разные варианты вашего приложения как отдельные приложения в Google Play, вам необходимо назначить разные applicationId каждому варианту.

После создания и настройки вариантов продукта нажмите Sync Now на панели уведомлений. После завершения синхронизации Gradle автоматически создает варианты сборки на основе ваших типов сборки и вариантов продукта и называет их в соответствии с <product-flavor><Build-Type> . Например, если вы создали варианты продукта "demo" и "full" и сохранили типы сборки по умолчанию "debug" и "release", Gradle создает следующие варианты сборки:

  • demoDebug
  • demoRelease
  • fullDebug
  • fullRelease

Чтобы выбрать вариант сборки для сборки и запуска, перейдите в Build > Select Build Variant и выберите вариант сборки из меню. Чтобы начать настраивать каждый вариант сборки с его собственными функциями и ресурсами, вам нужно будет создать и управлять исходными наборами , как описано на этой странице.

Измените идентификатор приложения для вариантов сборки

Когда вы создаете APK или AAB для своего приложения, инструменты сборки помечают приложение идентификатором приложения, определенным в блоке defaultConfig из файла build.gradle.kts , как показано в следующем примере. Однако, если вы хотите создать разные версии своего приложения, которые будут отображаться в виде отдельных листингов в Google Play Store, например, «бесплатную» и «профессиональную» версии, вам необходимо создать отдельные варианты сборки , каждый из которых будет иметь свой идентификатор приложения.

В этом случае определите каждый вариант сборки как отдельный product flavor . Для каждого flavor внутри блока productFlavors вы можете переопределить свойство applicationId или вместо этого можете добавить сегмент к идентификатору приложения по умолчанию с помощью applicationIdSuffix , как показано здесь:

Котлин

android {
    defaultConfig {
        applicationId = "com.example.myapp"
    }
    productFlavors {
        create("free") {
            applicationIdSuffix = ".free"
        }
        create("pro") {
            applicationIdSuffix = ".pro"
        }
    }
}

Круто

android {
    defaultConfig {
        applicationId "com.example.myapp"
    }
    productFlavors {
        free {
            applicationIdSuffix ".free"
        }
        pro {
            applicationIdSuffix ".pro"
        }
    }
}

Таким образом, идентификатор приложения для «бесплатной» версии продукта будет «com.example.myapp.free».

Вы также можете использовать applicationIdSuffix для добавления сегмента на основе типа вашей сборки , как показано здесь:

Котлин

android {
    ...
    buildTypes {
        getByName("debug") {
            applicationIdSuffix = ".debug"
        }
    }
}

Круто

android {
    ...
    buildTypes {
        debug {
            applicationIdSuffix ".debug"
        }
    }
}

Поскольку Gradle применяет конфигурацию типа сборки после разновидности продукта, идентификатор приложения для варианта сборки "free debug" — "com.example.myapp.free.debug". Это полезно, когда вы хотите иметь как отладочную, так и релизную сборку на одном устройстве, поскольку никакие два приложения не могут иметь одинаковый идентификатор приложения.

Если у вас есть устаревшее приложение (созданное до августа 2021 года), которое вы распространяете с помощью APK в Google Play, и вы хотите использовать тот же список приложений для распространения нескольких APK, каждый из которых нацелен на различную конфигурацию устройства, например уровень API, то вы должны использовать один и тот же идентификатор приложения для каждого варианта сборки, но присвоить каждому APK разный versionCode . Для получения дополнительной информации прочтите о поддержке нескольких APK . Публикация с использованием AAB не затрагивается, поскольку она использует один артефакт, который по умолчанию использует один код версии и идентификатор приложения.

Совет: Если вам нужно сослаться на идентификатор приложения в файле манифеста, вы можете использовать заполнитель ${applicationId} в любом атрибуте манифеста. Во время сборки Gradle заменяет этот тег на фактический идентификатор приложения. Для получения дополнительной информации см. Вставка переменных сборки в манифест .

Объедините несколько вкусов продукта с различными вкусовыми параметрами

В некоторых случаях вам может понадобиться объединить конфигурации из нескольких вкусов продукта. Например, вам может понадобиться создать разные конфигурации для «полных» и «демо» вкусов продукта, основанных на уровне API. Для этого плагин Android Gradle позволяет вам создавать несколько групп вкусов продукта в качестве измерений вкусов.

При создании вашего приложения Gradle объединяет конфигурацию вкуса продукта из каждого определенного вами измерения вкуса вместе с конфигурацией типа сборки для создания окончательного варианта сборки. Gradle не объединяет вкусы продукта, которые принадлежат к одному и тому же измерению вкуса.

В следующем примере кода свойство flavorDimensions используется для создания измерения вкуса «mode» для группировки вкусов «full» и «demo» и измерения вкуса «api» для группировки конфигураций вкусов продуктов на основе уровня API:

Котлин

android {
  ...
  buildTypes {
    getByName("debug") {...}
    getByName("release") {...}
  }

  // Specifies the flavor dimensions you want to use. The order in which you
  // list the dimensions determines their priority, from highest to lowest,
  // when Gradle merges variant sources and configurations. You must assign
  // each product flavor you configure to one of the flavor dimensions.
  flavorDimensions += listOf("api", "mode")

  productFlavors {
    create("demo") {
      // Assigns this product flavor to the "mode" flavor dimension.
      dimension = "mode"
      ...
    }

    create("full") {
      dimension = "mode"
      ...
    }

    // Configurations in the "api" product flavors override those in "mode"
    // flavors and the defaultConfig block. Gradle determines the priority
    // between flavor dimensions based on the order in which they appear next
    // to the flavorDimensions property, with the first dimension having a higher
    // priority than the second, and so on.
    create("minApi24") {
      dimension = "api"
      minSdk = 24
      // To ensure the target device receives the version of the app with
      // the highest compatible API level, assign version codes in increasing
      // value with API level.
      versionCode = 30000 + (android.defaultConfig.versionCode ?: 0)
      versionNameSuffix = "-minApi24"
      ...
    }

    create("minApi23") {
      dimension = "api"
      minSdk = 23
      versionCode = 20000  + (android.defaultConfig.versionCode ?: 0)
      versionNameSuffix = "-minApi23"
      ...
    }

    create("minApi21") {
      dimension = "api"
      minSdk = 21
      versionCode = 10000  + (android.defaultConfig.versionCode ?: 0)
      versionNameSuffix = "-minApi21"
      ...
    }
  }
}
...

Круто

android {
  ...
  buildTypes {
    debug {...}
    release {...}
  }

  // Specifies the flavor dimensions you want to use. The order in which you
  // list the dimensions determines their priority, from highest to lowest,
  // when Gradle merges variant sources and configurations. You must assign
  // each product flavor you configure to one of the flavor dimensions.
  flavorDimensions "api", "mode"

  productFlavors {
    demo {
      // Assigns this product flavor to the "mode" flavor dimension.
      dimension "mode"
      ...
    }

    full {
      dimension "mode"
      ...
    }

    // Configurations in the "api" product flavors override those in "mode"
    // flavors and the defaultConfig block. Gradle determines the priority
    // between flavor dimensions based on the order in which they appear next
    // to the flavorDimensions property, with the first dimension having a higher
    // priority than the second, and so on.
    minApi24 {
      dimension "api"
      minSdkVersion 24
      // To ensure the target device receives the version of the app with
      // the highest compatible API level, assign version codes in increasing
      // value with API level.

      versionCode 30000 + android.defaultConfig.versionCode
      versionNameSuffix "-minApi24"
      ...
    }

    minApi23 {
      dimension "api"
      minSdkVersion 23
      versionCode 20000  + android.defaultConfig.versionCode
      versionNameSuffix "-minApi23"
      ...
    }

    minApi21 {
      dimension "api"
      minSdkVersion 21
      versionCode 10000  + android.defaultConfig.versionCode
      versionNameSuffix "-minApi21"
      ...
    }
  }
}
...

Количество вариантов сборки, которые создает Gradle, равно произведению количества вариантов в каждом измерении вариантов и количества настроенных вами типов сборки. Когда Gradle называет каждый вариант сборки или соответствующие артефакты, сначала появляются варианты продукта, принадлежащие к измерению вариантов с более высоким приоритетом, за ними следуют варианты из измерений с более низким приоритетом, а затем тип сборки.

Используя предыдущую конфигурацию сборки в качестве примера, Gradle создает в общей сложности 12 вариантов сборки со следующей схемой именования:

  • Вариант сборки: [minApi24, minApi23, minApi21][Demo, Full][Debug, Release]
  • Соответствующий APK: app-[minApi24, minApi23, minApi21]-[demo, full]-[debug, release].apk
  • Например,
    Вариант сборки: minApi24DemoDebug
    Соответствующий APK: app-minApi24-demo-debug.apk

В дополнение к каталогам исходных наборов, которые вы можете создать для каждого отдельного варианта продукта и варианта сборки, вы также можете создать каталоги исходных наборов для каждой комбинации вариантов продукта. Например, вы можете создать и добавить исходные коды Java в каталог src/demoMinApi24/java/ , и Gradle будет использовать эти источники только при сборке варианта, который объединяет эти два варианта продукта.

Исходные наборы, которые вы создаете для комбинаций вкусов продуктов, имеют более высокий приоритет, чем исходные наборы, которые принадлежат каждому отдельному вкусу продукта. Чтобы узнать больше о исходных наборах и о том, как Gradle объединяет ресурсы, прочитайте раздел о том, как создавать исходные наборы .

Фильтровать варианты

Gradle создает вариант сборки для каждой возможной комбинации вкусов продукта и типов сборки, которые вы настраиваете. Однако могут быть определенные варианты сборки, которые вам не нужны или не имеют смысла в контексте вашего проекта. Чтобы удалить определенные конфигурации вариантов сборки, создайте фильтр вариантов в файле build.gradle.kts на уровне модуля.

Используя конфигурацию сборки из предыдущего раздела в качестве примера, предположим, что вы планируете поддерживать только уровни API 23 и выше для демо-версии приложения. Вы можете использовать блок variantFilter для фильтрации всех конфигураций вариантов сборки, которые объединяют варианты продукта "minApi21" и "demo":

Котлин

android {
  ...
  buildTypes {...}

  flavorDimensions += listOf("api", "mode")
  productFlavors {
    create("demo") {...}
    create("full") {...}
    create("minApi24") {...}
    create("minApi23") {...}
    create("minApi21") {...}
  }
}

androidComponents {
    beforeVariants { variantBuilder ->
        // To check for a certain build type, use variantBuilder.buildType == "<buildType>"
        if (variantBuilder.productFlavors.containsAll(listOf("api" to "minApi21", "mode" to "demo"))) {
            // Gradle ignores any variants that satisfy the conditions above.
            variantBuilder.enable = false
        }
    }
}
...

Круто

android {
  ...
  buildTypes {...}

  flavorDimensions "api", "mode"
  productFlavors {
    demo {...}
    full {...}
    minApi24 {...}
    minApi23 {...}
    minApi21 {...}
  }

  variantFilter { variant ->
      def names = variant.flavors*.name
      // To check for a certain build type, use variant.buildType.name == "<buildType>"
      if (names.contains("minApi21") && names.contains("demo")) {
          // Gradle ignores any variants that satisfy the conditions above.
          setIgnore(true)
      }
  }
}
...

После добавления фильтра вариантов в конфигурацию сборки и нажатия кнопки Синхронизировать сейчас в панели уведомлений Gradle игнорирует любые варианты сборки, которые соответствуют указанным вами условиям. Варианты сборки больше не отображаются в меню, когда вы нажимаете Сборка > Выбрать вариант сборки в строке меню или Варианты сборки на панели окна инструментов.

Создать исходные наборы

По умолчанию Android Studio создает набор main/ source и каталоги для всего, что вы хотите совместно использовать между всеми вариантами сборки. Однако вы можете создать новые наборы источников, чтобы точно контролировать, какие файлы Gradle компилирует и упаковывает для определенных типов сборки, вариантов продукта, комбинаций вариантов продукта (при использовании измерений вариантов ) и вариантов сборки.

Например, вы можете определить базовую функциональность в наборе main/ source и использовать исходные наборы product flavor, чтобы изменить брендинг вашего приложения для разных клиентов, или включить специальные разрешения и функциональность ведения журнала только для вариантов сборки, которые используют тип сборки debug.

Gradle ожидает, что файлы и каталоги исходного набора будут организованы определенным образом, подобно исходному набору main/ . Например, Gradle ожидает, что файлы классов Kotlin или Java, специфичные для вашего типа сборки "debug", будут располагаться в каталогах src/debug/kotlin/ или src/debug/java/ .

Плагин Android Gradle предоставляет полезную задачу Gradle, которая показывает, как организовать файлы для каждого из типов сборки, вариантов продукта и вариантов сборки. Например, следующий пример из выходных данных задачи описывает, где Gradle ожидает найти определенные файлы для типа сборки «debug»:

------------------------------------------------------------
Project :app
------------------------------------------------------------

...

debug
----
Compile configuration: debugCompile
build.gradle name: android.sourceSets.debug
Java sources: [app/src/debug/java]
Kotlin sources: [app/src/debug/kotlin, app/src/debug/java]
Manifest file: app/src/debug/AndroidManifest.xml
Android resources: [app/src/debug/res]
Assets: [app/src/debug/assets]
AIDL sources: [app/src/debug/aidl]
RenderScript sources: [app/src/debug/rs]
JNI sources: [app/src/debug/jni]
JNI libraries: [app/src/debug/jniLibs]
Java-style resources: [app/src/debug/resources]

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

  1. Нажмите Gradle на панели инструментов.
  2. Перейдите в MyApplication > Tasks > android и дважды щелкните sourceSets .

    Чтобы увидеть папку Tasks , необходимо разрешить Gradle построить список задач во время синхронизации. Для этого выполните следующие действия:

    1. Нажмите Файл > Настройки > Экспериментальные ( Android Studio > Настройки > Экспериментальные на macOS).
    2. Снимите флажок Не формировать список задач Gradle во время синхронизации Gradle .
  3. После того, как Gradle выполнит задачу, откроется окно «Выполнить» для отображения вывода.

Примечание: выходные данные задачи также показывают, как организовать исходные наборы для файлов, которые вы хотите использовать для запуска тестов вашего приложения, например, исходные наборы тестирования test/ и androidTest/ .

Когда вы создаете новый вариант сборки, Android Studio не создает для вас каталоги исходного набора, но дает вам несколько вариантов, которые помогут вам. Например, чтобы создать только каталог java/ для вашего типа сборки "debug":

  1. Откройте панель «Проект» и выберите « Проект » в меню в верхней части панели.
  2. Перейдите в MyProject/app/src/ .
  3. Щелкните правой кнопкой мыши каталог src и выберите Создать > Каталог .
  4. В меню Gradle Source Sets выберите full/java .
  5. Нажмите Enter .

Android Studio создает исходный набор каталогов для вашего типа сборки отладки, а затем создает каталог java/ внутри него. В качестве альтернативы Android Studio может создать каталоги для вас, когда вы добавляете новый файл в свой проект для определенного варианта сборки.

Например, чтобы создать XML-файл значений для типа сборки «отладка»:

  1. На панели «Проект» щелкните правой кнопкой мыши каталог src и выберите «Создать» > «XML» > «XML-файл значений» .
  2. Введите имя XML-файла или оставьте имя по умолчанию.
  3. В меню рядом с пунктом «Набор целевых источников» выберите пункт «Отладка» .
  4. Нажмите «Готово» .

Поскольку в качестве целевого исходного набора был указан тип сборки "debug", Android Studio автоматически создает необходимые каталоги при создании XML-файла. Результирующая структура каталогов выглядит как на рисунке 1.

Рисунок 1. Новые каталоги исходного набора для типа сборки «отладка».

Активные исходные наборы имеют зеленый индикатор на значке, показывающий, что они активны. Исходный набор debug имеет суффикс [main] , показывающий, что он будет объединен с main исходным набором.

Используя ту же процедуру, вы также можете создать каталоги исходных наборов для вариантов продукта, например src/demo/ , и вариантов сборки, например src/demoDebug/ . Кроме того, вы можете создать тестовые исходные наборы, которые нацелены на определенные варианты сборки, например src/androidTestDemoDebug/ . Чтобы узнать больше, прочитайте о тестировании исходных наборов .

Изменить конфигурации исходного набора по умолчанию

Если у вас есть источники, которые не организованы в структуру файлов исходного набора по умолчанию, которую ожидает Gradle, как описано в предыдущем разделе о создании исходных наборов , вы можете использовать блок sourceSets , чтобы изменить место, где Gradle ищет файлы для каждого компонента исходного набора.

Блок sourceSets должен быть в блоке android . Вам не нужно перемещать исходные файлы; вам нужно только предоставить Gradle путь(и) относительно файла build.gradle.kts на уровне модуля, где Gradle может найти файлы для каждого компонента исходного набора. Чтобы узнать, какие компоненты можно настроить и можно ли сопоставить их с несколькими файлами или каталогами, см. Справочник API плагина Android Gradle .

Следующий пример кода сопоставляет источники из каталога app/other/ с определенными компонентами main исходного набора и изменяет корневой каталог исходного набора androidTest :

Котлин

android {
  ...
  // Encapsulates configurations for the main source set.
  sourceSets.getByName("main") {
    // Changes the directory for Java sources. The default directory is
    // 'src/main/java'.
    java.setSrcDirs(listOf("other/java"))

    // If you list multiple directories, Gradle uses all of them to collect
    // sources. Because Gradle gives these directories equal priority, if
    // you define the same resource in more than one directory, you receive an
    // error when merging resources. The default directory is 'src/main/res'.
    res.setSrcDirs(listOf("other/res1", "other/res2"))

    // Note: Avoid specifying a directory that is a parent to one
    // or more other directories you specify. For example, avoid the following:
    // res.srcDirs = ['other/res1', 'other/res1/layouts', 'other/res1/strings']
    // Specify either only the root 'other/res1' directory or only the
    // nested 'other/res1/layouts' and 'other/res1/strings' directories.

    // For each source set, you can specify only one Android manifest.
    // By default, Android Studio creates a manifest for your main source
    // set in the src/main/ directory.
    manifest.srcFile("other/AndroidManifest.xml")
    ...
  }

  // Create additional blocks to configure other source sets.
  sourceSets.getByName("androidTest") {
      // If all the files for a source set are located under a single root
      // directory, you can specify that directory using the setRoot property.
      // When gathering sources for the source set, Gradle looks only in locations
      // relative to the root directory you specify. For example, after applying the
      // configuration below for the androidTest source set, Gradle looks for Java
      // sources only in the src/tests/java/ directory.
      setRoot("src/tests")
      ...
  }
}
...

Круто

android {
  ...
  sourceSets {
    // Encapsulates configurations for the main source set.
    main {
      // Changes the directory for Java sources. The default directory is
      // 'src/main/java'.
      java.srcDirs = ['other/java']

      // If you list multiple directories, Gradle uses all of them to collect
      // sources. Because Gradle gives these directories equal priority, if
      // you define the same resource in more than one directory, you receive an
      // error when merging resources. The default directory is 'src/main/res'.
      res.srcDirs = ['other/res1', 'other/res2']

      // Note: Avoid specifying a directory that is a parent to one
      // or more other directories you specify. For example, avoid the following:
      // res.srcDirs = ['other/res1', 'other/res1/layouts', 'other/res1/strings']
      // Specify either only the root 'other/res1' directory or only the
      // nested 'other/res1/layouts' and 'other/res1/strings' directories.

      // For each source set, you can specify only one Android manifest.
      // By default, Android Studio creates a manifest for your main source
      // set in the src/main/ directory.
      manifest.srcFile 'other/AndroidManifest.xml'
      ...
    }

    // Create additional blocks to configure other source sets.
    androidTest {

      // If all the files for a source set are located under a single root
      // directory, you can specify that directory using the setRoot property.
      // When gathering sources for the source set, Gradle looks only in locations
      // relative to the root directory you specify. For example, after applying the
      // configuration below for the androidTest source set, Gradle looks for Java
      // sources only in the src/tests/java/ directory.
      setRoot 'src/tests'
      ...
    }
  }
}
...

Обратите внимание, что исходный каталог может принадлежать только одному исходному набору. Например, вы не можете совместно использовать одни и те же тестовые исходные файлы как с test , так и с androidTest исходными наборами. Это связано с тем, что Android Studio создает отдельные модули IntelliJ для каждого исходного набора и не может поддерживать дублирование корней контента в исходных наборах.

Сборка с исходными наборами

Вы можете использовать каталоги исходных наборов для хранения кода и ресурсов, которые вы хотите упаковать только с определенными конфигурациями. Например, если вы создаете вариант сборки "demoDebug", который является кросс-продуктом "demo" product flavor и "debug" build type, Gradle просматривает эти каталоги и дает им следующий приоритет:

  1. src/demoDebug/ (исходный набор вариантов сборки)
  2. src/debug/ (исходный набор типа сборки)
  3. src/demo/ (исходный набор вкусов продукта)
  4. src/main/ (основной исходный набор)

Исходные наборы, созданные для комбинаций вкусов продукта, должны включать все измерения вкуса. Например, исходный набор варианта сборки должен быть комбинацией типа сборки и всех измерений вкуса. Объединение кода и ресурсов, включающих папки, которые охватывают несколько, но не все измерения вкуса, не поддерживается.

Если вы объединяете несколько вкусов продукта , приоритет между вкусами продукта определяется измерением вкуса, к которому они принадлежат. При перечислении измерений вкуса с помощью свойства android.flavorDimensions вкусы продукта, которые принадлежат к первому перечисленному вами измерению вкуса, имеют более высокий приоритет, чем те, которые принадлежат ко второму измерению вкуса, и т. д. Кроме того, исходные наборы, которые вы создаете для комбинаций вкусов продукта, имеют более высокий приоритет, чем исходные наборы, которые принадлежат к отдельному вкусу продукта.

Порядок приоритетов определяет, какой исходный набор имеет более высокий приоритет, когда Gradle объединяет код и ресурсы. Поскольку каталог исходного набора demoDebug/ , скорее всего, содержит файлы, специфичные для этого варианта сборки, если demoDebug/ включает файл, который также определен в debug/ , Gradle использует файл в исходном наборе demoDebug/ . Аналогично, Gradle присваивает файлам в исходных наборах build type и product flavor более высокий приоритет, чем тем же файлам в main/ . Gradle учитывает этот порядок приоритетов при применении следующих правил сборки:

  • Весь исходный код в каталогах kotlin/ или java/ компилируется вместе для создания единого выходного файла.

    Примечание: для заданного варианта сборки Gradle выдает ошибку сборки, если обнаруживает два или более каталогов исходного набора, в которых определен один и тот же класс Kotlin или Java. Например, при сборке отладочного приложения вы не можете определить оба src/debug/Utility.kt и src/main/Utility.kt , поскольку Gradle просматривает оба этих каталога во время процесса сборки и выдает ошибку «дубликат класса». Если вам нужны разные версии Utility.kt для разных типов сборки, каждый тип сборки должен определить свою собственную версию файла и не включать его в набор main/ source.

  • Манифесты объединяются в один манифест. Приоритет задается в том же порядке, что и в списке в предыдущем примере. То есть настройки манифеста для типа сборки переопределяют настройки манифеста для разновидности продукта и т. д. Чтобы узнать больше, прочтите о слиянии манифестов .
  • Файлы в каталогах values/ объединяются. Если два файла имеют одинаковое имя, например, два файла strings.xml , приоритет задается в том же порядке, что и в списке в предыдущем примере. То есть значения, определенные в файле в исходном наборе типа сборки, переопределяют значения, определенные в том же файле в разновидности продукта и т. д.
  • Ресурсы в каталогах res/ и asset/ упакованы вместе. Если есть ресурсы с одинаковым именем, определенные в двух или более исходных наборах, приоритет дается в том же порядке, что и список в предыдущем примере.
  • Gradle присваивает ресурсам и манифестам, включенным в зависимости от библиотечных модулей, самый низкий приоритет при сборке приложения.

Объявить зависимости

Чтобы настроить зависимость для определенного варианта сборки или исходного набора тестирования , добавьте префикс имени варианта сборки или исходного набора тестирования перед ключевым словом Implementation , как показано в следующем примере:

Котлин

dependencies {
    // Adds the local "mylibrary" module as a dependency to the "free" flavor.
    "freeImplementation"(project(":mylibrary"))

    // Adds a remote binary dependency only for local tests.
    testImplementation("junit:junit:4.12")

    // Adds a remote binary dependency only for the instrumented test APK.
    androidTestImplementation("com.android.support.test.espresso:espresso-core:3.6.1")
}

Круто

dependencies {
    // Adds the local "mylibrary" module as a dependency to the "free" flavor.
    freeImplementation project(":mylibrary")

    // Adds a remote binary dependency only for local tests.
    testImplementation 'junit:junit:4.12'

    // Adds a remote binary dependency only for the instrumented test APK.
    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.6.1'
}

Дополнительную информацию о настройке зависимостей см. в разделе Добавление зависимостей сборки .

Используйте управление зависимостями с учетом вариантов

Плагин Android Gradle 3.0.0 и выше включает новый механизм зависимостей, который автоматически сопоставляет варианты при потреблении библиотеки. Это означает, что debug вариант приложения автоматически потребляет debug вариант библиотеки и т. д. Он также работает при использовании разновидностей: вариант freeDebug приложения будет потреблять вариант freeDebug библиотеки.

Чтобы плагин точно сопоставлял варианты, вам необходимо предоставить резервные варианты соответствия , как описано в следующем разделе, для случаев, когда прямое сопоставление невозможно.

Например, предположим, что ваше приложение настраивает тип сборки под названием «staging», но одна из его зависимостей библиотеки не настраивает. Когда плагин пытается построить версию «staging» вашего приложения, он не будет знать, какую версию библиотеки использовать, и вы увидите сообщение об ошибке, похожее на следующее:

Error:Failed to resolve: Could not resolve project :mylibrary.
Required by:
    project :app

Устранение ошибок сборки, связанных с сопоставлением вариантов

Плагин включает элементы DSL, которые помогут вам контролировать, как Gradle разрешает ситуации, в которых прямое соответствие вариантов между приложением и зависимостью невозможно.

Ниже приведен список проблем, связанных с сопоставлением зависимостей с учетом вариантов, и способы их решения с использованием свойств DSL:

  • Ваше приложение включает тип сборки, которого нет в зависимости от библиотеки.

    Например, ваше приложение включает тип сборки «Staging», но зависимость включает только типы сборки «Debug» и «Release».

    Обратите внимание, что нет никаких проблем, когда зависимость библиотеки включает тип сборки, которого нет в вашем приложении. Это потому, что плагин никогда не запрашивает этот тип сборки из зависимости.

    Используйте matchingFallbacks , чтобы указать альтернативные соответствия для заданного типа сборки, как показано здесь:

    Котлин

    // In the app's build.gradle.kts file.
    android {
        buildTypes {
            getByName("debug") {}
            getByName("release") {}
            create("staging") {
                // Specifies a sorted list of fallback build types that the
                // plugin can try to use when a dependency does not include a
                // "staging" build type. You may specify as many fallbacks as you
                // like, and the plugin selects the first build type that's
                // available in the dependency.
                matchingFallbacks += listOf("debug", "qa", "release")
            }
        }
    }

    Круто

    // In the app's build.gradle file.
    android {
        buildTypes {
            debug {}
            release {}
            staging {
                // Specifies a sorted list of fallback build types that the
                // plugin can try to use when a dependency does not include a
                // "staging" build type. You may specify as many fallbacks as you
                // like, and the plugin selects the first build type that's
                // available in the dependency.
                matchingFallbacks = ['debug', 'qa', 'release']
            }
        }
    }
  • Для заданного измерения вкуса, которое существует как в приложении, так и в его библиотечной зависимости, ваше приложение включает вкусы, которых нет в библиотеке.

    Например, и ваше приложение, и его зависимости от библиотеки включают измерение "tier" flavor. Однако измерение "tier" в приложении включает "free" и "paid" flavors, а зависимость включает только "demo" и "paid" flavors для того же измерения.

    Обратите внимание, что для данного измерения flavor, которое существует как в приложении, так и в его библиотечных зависимостях, не возникает проблем, когда библиотека включает product flavor, которого нет в вашем приложении. Это потому, что плагин никогда не запрашивает этот flavor из зависимости.

    Используйте matchingFallbacks , чтобы указать альтернативные соответствия для «бесплатной» версии продукта приложения, как показано здесь:

    Котлин

    // In the app's build.gradle.kts file.
    android {
        defaultConfig{
        // Don't configure matchingFallbacks in the defaultConfig block.
        // Instead, specify fallbacks for a given product flavor in the
        // productFlavors block, as shown below.
      }
        flavorDimensions += "tier"
        productFlavors {
            create("paid") {
                dimension = "tier"
                // Because the dependency already includes a "paid" flavor in its
                // "tier" dimension, you don't need to provide a list of fallbacks
                // for the "paid" flavor.
            }
            create("free") {
                dimension = "tier"
                // Specifies a sorted list of fallback flavors that the plugin
                // can try to use when a dependency's matching dimension does
                // not include a "free" flavor. Specify as many
                // fallbacks as you like; the plugin selects the first flavor
                // that's available in the dependency's "tier" dimension.
                matchingFallbacks += listOf("demo", "trial")
            }
        }
    }

    Круто

    // In the app's build.gradle file.
    android {
        defaultConfig{
        // Don't configure matchingFallbacks in the defaultConfig block.
        // Instead, specify fallbacks for a given product flavor in the
        // productFlavors block, as shown below.
      }
        flavorDimensions 'tier'
        productFlavors {
            paid {
                dimension 'tier'
                // Because the dependency already includes a "paid" flavor in its
                // "tier" dimension, you don't need to provide a list of fallbacks
                // for the "paid" flavor.
            }
            free {
                dimension 'tier'
                // Specifies a sorted list of fallback flavors that the plugin
                // can try to use when a dependency's matching dimension does
                // not include a "free" flavor. Specify as many
                // fallbacks as you like; the plugin selects the first flavor
                // that's available in the dependency's "tier" dimension.
                matchingFallbacks = ['demo', 'trial']
            }
        }
    }
  • Зависимость от библиотеки включает в себя измерение вкуса, которого нет в вашем приложении.

    Например, зависимость библиотеки включает в себя разновидности для измерения "minApi", но ваше приложение включает в себя разновидности только для измерения "tier". Когда вы хотите создать версию "freeDebug" своего приложения, плагин не знает, использовать ли версию зависимости "minApi23Debug" или "minApi18Debug".

    Обратите внимание, что нет никаких проблем, когда ваше приложение включает измерение flavor, которого нет в зависимости библиотеки. Это потому, что плагин сопоставляет flavors только с измерениями, которые существуют в зависимости. Например, если зависимость не включает измерение для ABI, версия "freeX86Debug" вашего приложения будет использовать версию "freeDebug" зависимости.

    Используйте missingDimensionStrategy в блоке defaultConfig , чтобы указать вкус по умолчанию для плагина, чтобы выбрать из каждого отсутствующего измерения, как показано в следующем примере. Вы также можете переопределить свой выбор в блоке productFlavors , так что каждый вкус может указать другую стратегию сопоставления для отсутствующего измерения.

    Котлин

    // In the app's build.gradle.kts file.
    android {
        defaultConfig{
        // Specifies a sorted list of flavors that the plugin can try to use from
        // a given dimension. This tells the plugin to select the "minApi18" flavor
        // when encountering a dependency that includes a "minApi" dimension.
        // You can include additional flavor names to provide a
        // sorted list of fallbacks for the dimension.
        missingDimensionStrategy("minApi", "minApi18", "minApi23")
        // Specify a missingDimensionStrategy property for each
        // dimension that exists in a local dependency but not in your app.
        missingDimensionStrategy("abi", "x86", "arm64")
        }
        flavorDimensions += "tier"
        productFlavors {
            create("free") {
                dimension = "tier"
                // You can override the default selection at the product flavor
                // level by configuring another missingDimensionStrategy property
                // for the "minApi" dimension.
                missingDimensionStrategy("minApi", "minApi23", "minApi18")
            }
            create("paid") {}
        }
    }

    Круто

    // In the app's build.gradle file.
    android {
        defaultConfig{
        // Specifies a sorted list of flavors that the plugin can try to use from
        // a given dimension. This tells the plugin to select the "minApi18" flavor
        // when encountering a dependency that includes a "minApi" dimension.
        // You can include additional flavor names to provide a
        // sorted list of fallbacks for the dimension.
        missingDimensionStrategy 'minApi', 'minApi18', 'minApi23'
        // Specify a missingDimensionStrategy property for each
        // dimension that exists in a local dependency but not in your app.
        missingDimensionStrategy 'abi', 'x86', 'arm64'
        }
        flavorDimensions 'tier'
        productFlavors {
            free {
                dimension 'tier'
                // You can override the default selection at the product flavor
                // level by configuring another missingDimensionStrategy property
                // for the 'minApi' dimension.
                missingDimensionStrategy 'minApi', 'minApi23', 'minApi18'
            }
            paid {}
        }
    }

Для получения дополнительной информации см. matchingFallbacks и missingDimensionStrategy в справочнике DSL плагина Android Gradle.

Настройте параметры подписи

Gradle не подписывает APK или AAB вашей сборки релиза, если вы явно не определили конфигурацию подписи для этой сборки. Если у вас еще нет ключа подписи, сгенерируйте ключ загрузки и хранилище ключей с помощью Android Studio.

Чтобы вручную настроить конфигурации подписи для вашего типа сборки релиза с помощью конфигураций сборки Gradle:

  1. Создайте хранилище ключей. Хранилище ключей — это двоичный файл, содержащий набор закрытых ключей. Вы должны хранить свое хранилище ключей в надежном и безопасном месте.
  2. Создайте закрытый ключ. Закрытый ключ используется для подписи вашего приложения для распространения и никогда не включается в приложение и не раскрывается неавторизованным третьим лицам.
  3. Добавьте конфигурацию подписи в файл build.gradle.kts на уровне модуля:

    Котлин

    ...
    android {
        ...
        defaultConfig {...}
        signingConfigs {
            create("release") {
                storeFile = file("myreleasekey.keystore")
                storePassword = "password"
                keyAlias = "MyReleaseKey"
                keyPassword = "password"
            }
        }
        buildTypes {
            getByName("release") {
                ...
                signingConfig = signingConfigs.getByName("release")
            }
        }
    }

    Круто

    ...
    android {
        ...
        defaultConfig {...}
        signingConfigs {
            release {
                storeFile file("myreleasekey.keystore")
                storePassword "password"
                keyAlias "MyReleaseKey"
                keyPassword "password"
            }
        }
        buildTypes {
            release {
                ...
                signingConfig signingConfigs.release
            }
        }
    }

Примечание: Включение паролей для вашего ключа релиза и хранилища ключей в файл сборки не является хорошей практикой безопасности. Вместо этого настройте файл сборки на получение этих паролей из переменных среды или сделайте так, чтобы процесс сборки запрашивал у вас эти пароли.

Чтобы получить эти пароли из переменных среды:

Котлин

storePassword = System.getenv("KSTOREPWD")
keyPassword = System.getenv("KEYPWD")

Круто

storePassword System.getenv("KSTOREPWD")
keyPassword System.getenv("KEYPWD")

В качестве альтернативы вы можете загрузить хранилище ключей из локального файла свойств. По соображениям безопасности не добавляйте этот файл в систему управления исходным кодом. Вместо этого настройте его локально для каждого разработчика. Чтобы узнать больше, прочтите статью Удаление информации о подписи из файлов сборки .

После завершения этого процесса вы сможете распространять свое приложение и публиковать его в Google Play.

Предупреждение: храните хранилище ключей и закрытый ключ в надежном и безопасном месте и убедитесь, что у вас есть их надежные резервные копии. Если вы используете Play App Signing и потеряете свой ключ загрузки, вы можете запросить сброс с помощью Play Console. Если вы публикуете приложение без Play App Signing (для приложений, созданных до августа 2021 года) и потеряете свой ключ подписи приложения, вы не сможете публиковать какие-либо обновления своего приложения, поскольку вы всегда должны подписывать все версии своего приложения одним и тем же ключом.

Подписание приложений Wear OS

При публикации приложений Wear OS APK часов и опциональный APK телефона должны быть подписаны одним и тем же ключом. Для получения дополнительной информации об упаковке и подписании приложений Wear OS см. раздел Упаковка и распространение приложений Wear .

,

На этой странице показано, как можно настроить варианты сборки для создания разных версий вашего приложения из одного проекта, а также как правильно управлять зависимостями и конфигурациями подписи.

Каждый вариант сборки представляет собой отдельную версию вашего приложения, которую вы можете построить. Например, вы можете захотеть построить одну версию вашего приложения, которая будет бесплатной с ограниченным набором контента, и другую платную версию, которая будет включать больше. Вы также можете построить разные версии вашего приложения, которые предназначены для разных устройств, на основе уровня API или других вариаций устройств.

Варианты сборки являются результатом использования Gradle определенного набора правил для объединения настроек, кода и ресурсов, настроенных в типах сборки и вариантах продукта. Хотя вы не настраиваете варианты сборки напрямую, вы настраиваете типы сборки и варианты продукта, которые их формируют.

Например, вариант продукта "demo" может указывать определенные функции и требования к устройству, такие как пользовательский исходный код, ресурсы и минимальные уровни API, в то время как тип сборки "debug" применяет другие настройки сборки и упаковки, такие как параметры отладки и ключи подписи. Вариант сборки, который объединяет эти два варианта, — это версия "demoDebug" вашего приложения, и он включает комбинацию конфигураций и ресурсов, включенных в вариант продукта "demo", тип сборки "debug" и набор main/ source.

Настроить типы сборки

Вы можете создавать и настраивать типы сборки внутри блока android файла build.gradle.kts уровня модуля. При создании нового модуля Android Studio автоматически создает типы сборки debug и release. Хотя тип сборки debug не отображается в файле конфигурации сборки, Android Studio настраивает его с помощью debuggable true . Это позволяет отлаживать приложение на защищенных устройствах Android и настраивает подпись приложения с помощью универсального хранилища ключей отладки.

Вы можете добавить тип сборки отладки в свою конфигурацию, если хотите добавить или изменить определенные настройки. Следующий пример указывает applicationIdSuffix для типа сборки отладки и настраивает тип сборки "staging", который инициализируется с использованием настроек из типа сборки отладки:

Котлин

android {
    defaultConfig {
        manifestPlaceholders["hostName"] = "www.example.com"
        ...
    }
    buildTypes {
        getByName("release") {
            isMinifyEnabled = true
            proguardFiles(getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro")
        }

        getByName("debug") {
            applicationIdSuffix = ".debug"
            isDebuggable = true
        }

        /**
         * The `initWith` property lets you copy configurations from other build types,
         * then configure only the settings you want to change. This one copies the debug build
         * type, and then changes the manifest placeholder and application ID.
         */
        create("staging") {
            initWith(getByName("debug"))
            manifestPlaceholders["hostName"] = "internal.example.com"
            applicationIdSuffix = ".debugStaging"
        }
    }
}

Круто

android {
    defaultConfig {
        manifestPlaceholders = [hostName:"www.example.com"]
        ...
    }
    buildTypes {
        release {
            minifyEnabled true
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }

        debug {
            applicationIdSuffix ".debug"
            debuggable true
        }

        /**
         * The `initWith` property lets you copy configurations from other build types,
         * then configure only the settings you want to change. This one copies the debug build
         * type, and then changes the manifest placeholder and application ID.
         */
        staging {
            initWith debug
            manifestPlaceholders = [hostName:"internal.example.com"]
            applicationIdSuffix ".debugStaging"
        }
    }
}

Примечание: Когда вы вносите изменения в файл конфигурации сборки, Android Studio требует, чтобы вы синхронизировали свой проект с новой конфигурацией. Чтобы синхронизировать свой проект, нажмите Sync Now в панели уведомлений, которая появляется при внесении изменений, или нажмите Sync Project из панели инструментов. Если Android Studio заметит какие-либо ошибки в вашей конфигурации, появится окно «Сообщения» с описанием проблемы.

Чтобы узнать больше обо всех свойствах, которые можно настроить с помощью типов сборки, прочтите справочник BuildType .

Настройте вкусы продукта

Создание разновидностей продукта похоже на создание типов сборки. Добавьте разновидности продукта в блок productFlavors в конфигурации сборки и включите нужные вам параметры. Разновидности продукта поддерживают те же свойства, что и defaultConfig , поскольку defaultConfig фактически принадлежит классу ProductFlavor . Это означает, что вы можете предоставить базовую конфигурацию для всех разновидностей в блоке defaultConfig , и каждая разновидность может изменить любое из этих значений по умолчанию, например applicationId . Чтобы узнать больше об идентификаторе приложения, прочитайте раздел Установка идентификатора приложения .

Примечание: Вам все равно нужно указать имя пакета с помощью атрибута package в файле main/ manifest. Вы также должны использовать это имя пакета в исходном коде для ссылки на класс R или для разрешения любой относительной активности или регистрации службы. Это позволяет вам использовать applicationId для присвоения каждому варианту продукта уникального идентификатора для упаковки и распространения без необходимости изменения исходного кода.

Все вкусы должны принадлежать к именованному измерению вкуса, которое является группой вкусов продукта. Вы должны назначить все вкусы измерению вкуса; в противном случае вы получите следующую ошибку сборки.

  Error: All flavors must now belong to a named flavor dimension.
  The flavor 'flavor_name' is not assigned to a flavor dimension.

Если данный модуль определяет только одно измерение разновидности, плагин Android Gradle автоматически назначает все разновидности модуля этому измерению.

Следующий пример кода создает измерение flavor с именем "version" и добавляет "demo" и "full" вкусы продукта. Эти вкусы предоставляют свои собственные applicationIdSuffix и versionNameSuffix :

Котлин

android {
    ...
    defaultConfig {...}
    buildTypes {
        getByName("debug"){...}
        getByName("release"){...}
    }
    // Specifies one flavor dimension.
    flavorDimensions += "version"
    productFlavors {
        create("demo") {
            // Assigns this product flavor to the "version" flavor dimension.
            // If you are using only one dimension, this property is optional,
            // and the plugin automatically assigns all the module's flavors to
            // that dimension.
            dimension = "version"
            applicationIdSuffix = ".demo"
            versionNameSuffix = "-demo"
        }
        create("full") {
            dimension = "version"
            applicationIdSuffix = ".full"
            versionNameSuffix = "-full"
        }
    }
}

Круто

android {
    ...
    defaultConfig {...}
    buildTypes {
        debug{...}
        release{...}
    }
    // Specifies one flavor dimension.
    flavorDimensions "version"
    productFlavors {
        demo {
            // Assigns this product flavor to the "version" flavor dimension.
            // If you are using only one dimension, this property is optional,
            // and the plugin automatically assigns all the module's flavors to
            // that dimension.
            dimension "version"
            applicationIdSuffix ".demo"
            versionNameSuffix "-demo"
        }
        full {
            dimension "version"
            applicationIdSuffix ".full"
            versionNameSuffix "-full"
        }
    }
}

Примечание: Если у вас есть устаревшее приложение (созданное до августа 2021 года), которое вы распространяете с помощью APK в Google Play, для распространения вашего приложения с помощью поддержки нескольких APK в Google Play назначьте одинаковое значение applicationId всем вариантам и дайте каждому варианту разный versionCode . Чтобы распространять разные варианты вашего приложения как отдельные приложения в Google Play, вам необходимо назначить разные applicationId каждому варианту.

После создания и настройки вариантов продукта нажмите Sync Now на панели уведомлений. После завершения синхронизации Gradle автоматически создает варианты сборки на основе ваших типов сборки и вариантов продукта и называет их в соответствии с <product-flavor><Build-Type> . Например, если вы создали варианты продукта "demo" и "full" и сохранили типы сборки по умолчанию "debug" и "release", Gradle создает следующие варианты сборки:

  • demoDebug
  • demoRelease
  • fullDebug
  • fullRelease

Чтобы выбрать вариант сборки для сборки и запуска, перейдите в Build > Select Build Variant и выберите вариант сборки из меню. Чтобы начать настраивать каждый вариант сборки с его собственными функциями и ресурсами, вам нужно будет создать и управлять исходными наборами , как описано на этой странице.

Измените идентификатор приложения для вариантов сборки

Когда вы создаете APK или AAB для вашего приложения, инструменты сборки помечает приложение с идентификатором приложения, определенным в блоке defaultConfig из файла build.gradle.kts , как показано в следующем примере. Однако, если вы хотите создать разные версии вашего приложения, чтобы отображаться в виде отдельных списков в Google Play Store, таких как версия «бесплатно» и «Pro», вам необходимо создать отдельные варианты сборки , каждый из которых имеет другой идентификатор приложения.

В этом случае определите каждый вариант сборки как отдельный вкус продукта . Для каждого вкуса внутри блока productFlavors вы можете переопределить свойство applicationId , или вместо этого вы можете добавить сегмент к идентификатору приложения по умолчанию, используя applicationIdSuffix , как показано здесь:

Котлин

android {
    defaultConfig {
        applicationId = "com.example.myapp"
    }
    productFlavors {
        create("free") {
            applicationIdSuffix = ".free"
        }
        create("pro") {
            applicationIdSuffix = ".pro"
        }
    }
}

Круто

android {
    defaultConfig {
        applicationId "com.example.myapp"
    }
    productFlavors {
        free {
            applicationIdSuffix ".free"
        }
        pro {
            applicationIdSuffix ".pro"
        }
    }
}

Таким образом, идентификатор приложения для «бесплатного» аромата продукта является «com.example.myapp.free».

Вы также можете использовать applicationIdSuffix для добавления сегмента на основе вашего типа сборки , как показано здесь:

Котлин

android {
    ...
    buildTypes {
        getByName("debug") {
            applicationIdSuffix = ".debug"
        }
    }
}

Круто

android {
    ...
    buildTypes {
        debug {
            applicationIdSuffix ".debug"
        }
    }
}

Поскольку Gradle применяет конфигурацию типа сборки после аромата продукта, идентификатор приложения для варианта сборки «Бесплатная отладка» - "com.example.myapp.free.debug". Это полезно, когда вы хотите иметь как отладку, так и настройку выпуска на одном и том же устройстве, потому что никакие два приложения не могут иметь одинакового идентификатора приложения.

Если у вас есть приложение Legacy (созданное до августа 2021 года), которое вы распространяете с помощью APK в Google Play, и вы хотите использовать один и тот же список приложений для распространения нескольких APK, которые нацелены на конфигурацию устройства, например, уровень API, то необходимо использовать один идентификатор приложения для каждого варианта сборки, но дайте каждому APK различный versionCode . Для получения дополнительной информации прочитайте о нескольких поддержке APK . Публикация с использованием AABS не зависит от того, что он использует один артефакт, который по умолчанию использует один код версии и идентификатор приложения.

Совет: если вам нужно ссылаться на идентификатор приложения в вашем манифестном файле, вы можете использовать заполнитель ${applicationId} в любом атрибуте Manifest. Во время сборки Градл заменяет этот тег фактическим идентификатором приложения. Для получения дополнительной информации см. Переменные ввода в манифест .

Объедините несколько ароматов продукта с ароматными размерами

В некоторых случаях вы можете объединить конфигурации из нескольких ароматов продукта. Например, вы можете создать различные конфигурации для «полных» и «демонстрационных» вкусов продукта, которые основаны на уровне API. Для этого плагин Android Gradle позволяет создавать несколько групп ароматов продуктов в качестве ароматных размеров.

При создании вашего приложения Gradle объединяет конфигурацию вкуса продукта из каждого измерения вкуса, который вы определяете, наряду с конфигурацией типа сборки, чтобы создать окончательный вариант сборки. Gradle не сочетает в себе ароматы продукта, которые принадлежат к одному аромату.

Следующий образец кода использует свойство flavorDimensions для создания ароматизации вкуса «режима», чтобы сгруппировать ароматы «полного» и «демонстрационного» продукта и измерение аромата «API» для групповых конфигураций вкуса продукта на основе уровня API:

Котлин

android {
  ...
  buildTypes {
    getByName("debug") {...}
    getByName("release") {...}
  }

  // Specifies the flavor dimensions you want to use. The order in which you
  // list the dimensions determines their priority, from highest to lowest,
  // when Gradle merges variant sources and configurations. You must assign
  // each product flavor you configure to one of the flavor dimensions.
  flavorDimensions += listOf("api", "mode")

  productFlavors {
    create("demo") {
      // Assigns this product flavor to the "mode" flavor dimension.
      dimension = "mode"
      ...
    }

    create("full") {
      dimension = "mode"
      ...
    }

    // Configurations in the "api" product flavors override those in "mode"
    // flavors and the defaultConfig block. Gradle determines the priority
    // between flavor dimensions based on the order in which they appear next
    // to the flavorDimensions property, with the first dimension having a higher
    // priority than the second, and so on.
    create("minApi24") {
      dimension = "api"
      minSdk = 24
      // To ensure the target device receives the version of the app with
      // the highest compatible API level, assign version codes in increasing
      // value with API level.
      versionCode = 30000 + (android.defaultConfig.versionCode ?: 0)
      versionNameSuffix = "-minApi24"
      ...
    }

    create("minApi23") {
      dimension = "api"
      minSdk = 23
      versionCode = 20000  + (android.defaultConfig.versionCode ?: 0)
      versionNameSuffix = "-minApi23"
      ...
    }

    create("minApi21") {
      dimension = "api"
      minSdk = 21
      versionCode = 10000  + (android.defaultConfig.versionCode ?: 0)
      versionNameSuffix = "-minApi21"
      ...
    }
  }
}
...

Круто

android {
  ...
  buildTypes {
    debug {...}
    release {...}
  }

  // Specifies the flavor dimensions you want to use. The order in which you
  // list the dimensions determines their priority, from highest to lowest,
  // when Gradle merges variant sources and configurations. You must assign
  // each product flavor you configure to one of the flavor dimensions.
  flavorDimensions "api", "mode"

  productFlavors {
    demo {
      // Assigns this product flavor to the "mode" flavor dimension.
      dimension "mode"
      ...
    }

    full {
      dimension "mode"
      ...
    }

    // Configurations in the "api" product flavors override those in "mode"
    // flavors and the defaultConfig block. Gradle determines the priority
    // between flavor dimensions based on the order in which they appear next
    // to the flavorDimensions property, with the first dimension having a higher
    // priority than the second, and so on.
    minApi24 {
      dimension "api"
      minSdkVersion 24
      // To ensure the target device receives the version of the app with
      // the highest compatible API level, assign version codes in increasing
      // value with API level.

      versionCode 30000 + android.defaultConfig.versionCode
      versionNameSuffix "-minApi24"
      ...
    }

    minApi23 {
      dimension "api"
      minSdkVersion 23
      versionCode 20000  + android.defaultConfig.versionCode
      versionNameSuffix "-minApi23"
      ...
    }

    minApi21 {
      dimension "api"
      minSdkVersion 21
      versionCode 10000  + android.defaultConfig.versionCode
      versionNameSuffix "-minApi21"
      ...
    }
  }
}
...

Количество вариантов сборки создает Gradle, равное продукту количества ароматов в каждом измерении вкуса и количества типов сборки, которые вы настраиваете. Когда Gradle имена каждый вариант строительства или соответствующие артефакты, сначала появляются ароматы продукта, принадлежащие к более приоритетному вкусу, с последующими измерениями более низкого приоритета, за которым следует тип сборки.

Используя предыдущую конфигурацию сборки в качестве примера, Gradle создает в общей сложности 12 вариантов сборки со следующей схемой именования:

  • Вариант сборки: [minApi24, minApi23, minApi21][Demo, Full][Debug, Release]
  • Соответствующий APK: app-[minApi24, minApi23, minApi21]-[demo, full]-[debug, release].apk
  • Например,
    Вариант сборки: minApi24DemoDebug
    Соответствующий APK: app-minApi24-demo-debug.apk

В дополнение к каталогам исходных наборов, которые вы можете создать для каждого отдельного варианта продукта и создания, вы также можете создавать каталоги наборов источников для каждой комбинации вкусов продукта. Например, вы можете создавать и добавлять источники Java в src/demoMinApi24/java/ Directory, и Gradle использует эти источники только при создании варианта, который сочетает в себе эти два вкуса продукта.

Наборы источников, которые вы создаете для комбинаций вкуса продукта, имеют более высокий приоритет, чем исходные наборы, которые принадлежат каждому отдельному вкусу продукта. Чтобы узнать больше о наборах источников и о том, как Gradle объединяет ресурсы, прочитайте раздел о том, как создать исходные наборы .

Фильтрующие варианты

Gradle создает вариант сборки для каждой возможной комбинации ароматов продукта и типов сборки, которые вы настраиваете. Тем не менее, могут быть определенные варианты сборки, которые вам не нужны, или которые не имеют смысла в контексте вашего проекта. Чтобы удалить определенные конфигурации варианта сборки, создайте вариант фильтра в вашем файле на уровне модуля build.gradle.kts .

Используя конфигурацию сборки из предыдущего раздела в качестве примера, предположим, что вы планируете поддерживать только уровни API 23 и выше для демонстрационной версии приложения. Вы можете использовать блок variantFilter , чтобы отфильтровать все конфигурации вариантов сборки, которые объединяют ароматы «minapi21» и «демо»:

Котлин

android {
  ...
  buildTypes {...}

  flavorDimensions += listOf("api", "mode")
  productFlavors {
    create("demo") {...}
    create("full") {...}
    create("minApi24") {...}
    create("minApi23") {...}
    create("minApi21") {...}
  }
}

androidComponents {
    beforeVariants { variantBuilder ->
        // To check for a certain build type, use variantBuilder.buildType == "<buildType>"
        if (variantBuilder.productFlavors.containsAll(listOf("api" to "minApi21", "mode" to "demo"))) {
            // Gradle ignores any variants that satisfy the conditions above.
            variantBuilder.enable = false
        }
    }
}
...

Круто

android {
  ...
  buildTypes {...}

  flavorDimensions "api", "mode"
  productFlavors {
    demo {...}
    full {...}
    minApi24 {...}
    minApi23 {...}
    minApi21 {...}
  }

  variantFilter { variant ->
      def names = variant.flavors*.name
      // To check for a certain build type, use variant.buildType.name == "<buildType>"
      if (names.contains("minApi21") && names.contains("demo")) {
          // Gradle ignores any variants that satisfy the conditions above.
          setIgnore(true)
      }
  }
}
...

После того, как вы добавите вариант фильтра в свою конфигурацию сборки и нажмите Sync Now в панели уведомлений, Gradle игнорирует любые варианты сборки, которые соответствуют указанным условиям. Варианты сборки больше не появляются в меню, когда вы нажимаете на Build> Выберите вариант Build из строки меню или вариантов сборки В панели окна инструмента.

Создать исходные наборы

По умолчанию Android Studio создает main/ исходный набор и каталоги для всего, что вы хотите поделиться между всеми вариантами сборки. Тем не менее, вы можете создать новые наборы источников для управления именно тем, какие файлы Gradle компилируют и пакеты для конкретных типов сборки, вкуса продуктов, комбинации ароматов продукта (при использовании ароматных измерений ) и вариантов сборки.

Например, вы можете определить базовую функциональность в main/ исходных наборах и использовать исходные наборы вкуса продукта, чтобы изменить брендинг вашего приложения для разных клиентов или включать специальные разрешения и функции журнала только для вариантов сборки, которые используют тип сборки отладки.

Gradle ожидает, что исходные файлы и каталоги будут организованы определенным образом, аналогично main/ исходному набору. Например, Gradle ожидает, что файлы класса Kotlin или Java, специфичные для вашего типа «отладки», будут расположены в src/debug/kotlin/ или src/debug/java/ Directory.

Плагин Android Gradle предоставляет полезную задачу Gradle, которая показывает вам, как организовать ваши файлы для каждого из ваших типов сборки, вкуса продукта и вариантов сборки. Например, в следующей выборке из вывода задачи описывается, где Gradle рассчитывает найти определенные файлы для типа «отладка»

------------------------------------------------------------
Project :app
------------------------------------------------------------

...

debug
----
Compile configuration: debugCompile
build.gradle name: android.sourceSets.debug
Java sources: [app/src/debug/java]
Kotlin sources: [app/src/debug/kotlin, app/src/debug/java]
Manifest file: app/src/debug/AndroidManifest.xml
Android resources: [app/src/debug/res]
Assets: [app/src/debug/assets]
AIDL sources: [app/src/debug/aidl]
RenderScript sources: [app/src/debug/rs]
JNI sources: [app/src/debug/jni]
JNI libraries: [app/src/debug/jniLibs]
Java-style resources: [app/src/debug/resources]

Чтобы просмотреть этот вывод, выполните следующее:

  1. Нажмите Gradle в панели окна инструмента.
  2. Перейдите к MyApplication> Задачи> Android и дважды щелкните источники .

    Чтобы увидеть папку задач , вы должны позволить Gradle создать список задач во время синхронизации. Для этого следуйте этим шагам:

    1. Нажмите «Файл»> «Настройки»> «Экспериментальный» ( Android Studio> Настройки> Экспериментальные на MacOS).
    2. Deselect Не создайте список задач Gradle во время синхронизации Gradle .
  3. После того, как Gradle выполняет задачу, окно запуска открывается для отображения вывода.

ПРИМЕЧАНИЕ. Вывод задачи также показывает, как организовать исходные наборы для файлов, которые вы хотите использовать для запуска тестов для вашего приложения, таких как наборы исходных исследований test/ и androidTest/ Testing.

Когда вы создаете новый вариант сборки, Android Studio не создает для вас каталоги исходных наборов, но дает вам несколько вариантов, которые помогут вам. Например, чтобы создать только java/ Directory для вашего типа «отладки»:

  1. Откройте панель проекта и выберите представление проекта в меню в верхней части панели.
  2. Перейдите в MyProject/app/src/ .
  3. Щелкните правой кнопкой мыши каталог src и выберите «Новый > каталог» .
  4. В меню в рамках исходных наборов Gradle выберите Full/Java .
  5. Нажмите Enter .

Android Studio создает каталог Source Set для вашего типа сборки отладки, а затем создает внутри него java/ Directory. В качестве альтернативы, Android Studio может создавать каталоги для вас, когда вы добавляете новый файл в свой проект для конкретного варианта сборки.

Например, для создания значений XML -файла для вашего типа «отладки»:

  1. На панели проекта щелкните правой кнопкой мыши каталог src и выберите New > XML > Значения XML .
  2. Введите имя для файла XML или сохраните имя по умолчанию.
  3. В меню рядом с набором целевого источника выберите отладку .
  4. Нажмите «Готово» .

Поскольку тип сборки «отладки» был указан в качестве целевого набора источника, Android Studio автоматически создает необходимые каталоги, когда он создает файл XML. Полученная структура каталогов выглядит как рисунок 1.

Рисунок 1.. Новые каталоги набора источников для типа сборки «отладки».

Активные наборы источников имеют зеленый индикатор в их значке, чтобы показать, что они активны. Набор источника debug суффикс с [main] чтобы показать, что он будет объединен с main набором источника.

Используя ту же процедуру, вы также можете создавать каталоги набора источников для вкусов продуктов, таких как src/demo/ и Build Variants, такие как src/demoDebug/ . Кроме того, вы можете создать исходные наборы тестирования, которые нацелены на конкретные варианты сборки, такие как src/androidTestDemoDebug/ . Чтобы узнать больше, прочитайте о наборах исходных тестирования .

Изменить конфигурации исходного набора по умолчанию

Если у вас есть источники, которые не организованы в структуру исходного набора исходных исходных по умолчанию, которую ожидает Gradle, как описано в предыдущем разделе о создании исходных наборов , вы можете использовать блок sourceSets , чтобы изменить, где Gradle надеется собирать файлы для каждого компонента исходного набора.

Блок sourceSets должен быть в блоке android . Вам не нужно перемещать исходные файлы; Вам нужно только предоставить Gradle по пути (ы) по сравнению с файлом на уровне модуля build.gradle.kts , где Gradle может найти файлы для каждого компонента исходного набора. Чтобы узнать, какие компоненты вы можете настроить и можете ли вы сопоставить их с несколькими файлами или каталогами, см . Справочник API API API API Android Gradle .

Следующий образец кода отображает источники из app/other/ каталога в определенные компоненты main набора источников и изменяет корневой каталог исходного набора androidTest :

Котлин

android {
  ...
  // Encapsulates configurations for the main source set.
  sourceSets.getByName("main") {
    // Changes the directory for Java sources. The default directory is
    // 'src/main/java'.
    java.setSrcDirs(listOf("other/java"))

    // If you list multiple directories, Gradle uses all of them to collect
    // sources. Because Gradle gives these directories equal priority, if
    // you define the same resource in more than one directory, you receive an
    // error when merging resources. The default directory is 'src/main/res'.
    res.setSrcDirs(listOf("other/res1", "other/res2"))

    // Note: Avoid specifying a directory that is a parent to one
    // or more other directories you specify. For example, avoid the following:
    // res.srcDirs = ['other/res1', 'other/res1/layouts', 'other/res1/strings']
    // Specify either only the root 'other/res1' directory or only the
    // nested 'other/res1/layouts' and 'other/res1/strings' directories.

    // For each source set, you can specify only one Android manifest.
    // By default, Android Studio creates a manifest for your main source
    // set in the src/main/ directory.
    manifest.srcFile("other/AndroidManifest.xml")
    ...
  }

  // Create additional blocks to configure other source sets.
  sourceSets.getByName("androidTest") {
      // If all the files for a source set are located under a single root
      // directory, you can specify that directory using the setRoot property.
      // When gathering sources for the source set, Gradle looks only in locations
      // relative to the root directory you specify. For example, after applying the
      // configuration below for the androidTest source set, Gradle looks for Java
      // sources only in the src/tests/java/ directory.
      setRoot("src/tests")
      ...
  }
}
...

Круто

android {
  ...
  sourceSets {
    // Encapsulates configurations for the main source set.
    main {
      // Changes the directory for Java sources. The default directory is
      // 'src/main/java'.
      java.srcDirs = ['other/java']

      // If you list multiple directories, Gradle uses all of them to collect
      // sources. Because Gradle gives these directories equal priority, if
      // you define the same resource in more than one directory, you receive an
      // error when merging resources. The default directory is 'src/main/res'.
      res.srcDirs = ['other/res1', 'other/res2']

      // Note: Avoid specifying a directory that is a parent to one
      // or more other directories you specify. For example, avoid the following:
      // res.srcDirs = ['other/res1', 'other/res1/layouts', 'other/res1/strings']
      // Specify either only the root 'other/res1' directory or only the
      // nested 'other/res1/layouts' and 'other/res1/strings' directories.

      // For each source set, you can specify only one Android manifest.
      // By default, Android Studio creates a manifest for your main source
      // set in the src/main/ directory.
      manifest.srcFile 'other/AndroidManifest.xml'
      ...
    }

    // Create additional blocks to configure other source sets.
    androidTest {

      // If all the files for a source set are located under a single root
      // directory, you can specify that directory using the setRoot property.
      // When gathering sources for the source set, Gradle looks only in locations
      // relative to the root directory you specify. For example, after applying the
      // configuration below for the androidTest source set, Gradle looks for Java
      // sources only in the src/tests/java/ directory.
      setRoot 'src/tests'
      ...
    }
  }
}
...

Обратите внимание, что справочный каталог может принадлежать только одному исходному набору. Например, вы не можете поделиться одними и теми же источниками тестирования с наборами test и источников androidTest . Это связано с тем, что Android Studio создает отдельные модули IntelliJ для каждого набора источников и не может поддерживать дублирующие корни контента в наборах исходных источников.

Построить с помощью исходных наборов

Вы можете использовать каталоги Source Set для содержания кода и ресурсов, которые вы хотите, упакованы только с определенными конфигурациями. Например, если вы создаете вариант сборки DemodeBug », который представляет собой поперечный продукт« демонстрационного »аромата продукта и типа« отладка », Градл смотрит на эти каталоги и дает им следующий приоритет:

  1. src/demoDebug/ (набор источника варианта сборки)
  2. src/debug/ (набор источников типа сборки)
  3. src/demo/ (Набор источника вкуса продукта)
  4. src/main/ (набор основного источника)

Наборы источников, созданные для комбинаций ароматов продукта, должны включать в себя все ароматные размеры. Например, набор источника варианта сборки должен быть комбинацией типа сборки и всех размеров вкуса. Объединение кода и ресурсов, включающих папки, которые охватывают несколько, но не все ароматные размеры, не поддерживается.

Если вы объединяете несколько ароматов продукта , приоритет между ароматами продукта определяется измерением вкуса, к которому они принадлежат. При перечислении ароматических размеров со свойством android.flavorDimensions , ароматы продуктов, которые принадлежат к первому измерению вкуса, имеют более высокий приоритет, чем те, которые принадлежат ко второму измерению вкуса, и так далее. Кроме того, исходные наборы, которые вы создаете для комбинаций ароматов продукта, имеют более высокий приоритет, чем исходные наборы, которые принадлежат индивидуальному вкусу продукта.

Приоритетный заказ определяет, какой набор источников имеет более высокий приоритет, когда Gradle объединяет код и ресурсы. Поскольку каталог demoDebug/ Source Set, вероятно, содержит файлы, которые являются специфическими для этого варианта сборки, если demoDebug/ включает файл, который также определяется в debug/ , Gradle использует файл в наборе demoDebug/ Source. Точно так же Gradle дает файлы в типе сборки, а источник вкуса продукта устанавливает более высокий приоритет, чем те же файлы в main/ . Градл рассматривает этот приоритетный заказ при применении следующих правил сборки:

  • Весь исходный код в каталогах kotlin/ или java/ Combillesmented вместе для создания одного выхода.

    ПРИМЕЧАНИЕ. Для данного варианта сборки Gradle выбрасывает ошибку сборки, если он встречается с двумя или более каталогов исходных наборов, которые определили один и тот же класс Kotlin или Java. Например, при создании приложения отладки вы не можете определить как src/debug/Utility.kt так и src/main/Utility.kt , потому что Градл смотрит на обе эти каталоги в процессе сборки и выбрасывает ошибку «дубликата класса». Если вам нужны разные версии Utility.kt для различных типов сборки, каждый тип сборки должен определить свою собственную версию файла и не включать его в набор main/ источников.

  • Манифесты объединены в один манифест. Приоритет приведен в том же порядке, что и список в предыдущем примере. То есть манифестные настройки для типа сборки переопределяют настройки манифеста для аромата продукта и так далее. Чтобы узнать больше, прочитайте о явном слиянии .
  • Файлы в values/ каталогах объединяются вместе. Если два файла имеют одинаковое имя, например, два файла strings.xml , приоритет приведен в том же порядке, что и список в предыдущем примере. То есть значения, определенные в файле в наборе источника типа сборки, переопределяют значения, определенные в одном и том же файле в аромате продукта, и так далее.
  • Ресурсы в res/ и asset/ каталоги упакованы вместе. Если есть ресурсы с тем же именем, определенным в двух или более исходных наборах, приоритет приведен в том же порядке, что и список в предыдущем примере.
  • Gradle дает ресурсы и манифесты, включенные в зависимости от библиотечного модуля, самый низкий приоритет при создании приложения.

Объявить зависимости

Чтобы настроить зависимость для конкретного варианта сборки или набора источников тестирования , префикс название варианта сборки или исходного набора тестирования перед ключевым словом Implementation , как показано в следующем примере:

Котлин

dependencies {
    // Adds the local "mylibrary" module as a dependency to the "free" flavor.
    "freeImplementation"(project(":mylibrary"))

    // Adds a remote binary dependency only for local tests.
    testImplementation("junit:junit:4.12")

    // Adds a remote binary dependency only for the instrumented test APK.
    androidTestImplementation("com.android.support.test.espresso:espresso-core:3.6.1")
}

Круто

dependencies {
    // Adds the local "mylibrary" module as a dependency to the "free" flavor.
    freeImplementation project(":mylibrary")

    // Adds a remote binary dependency only for local tests.
    testImplementation 'junit:junit:4.12'

    // Adds a remote binary dependency only for the instrumented test APK.
    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.6.1'
}

Для получения дополнительной информации о настройке зависимостей см. Добавить зависимости от сборки .

Использовать управление зависимостями варианта

Плагин Android Gradle 3.0.0 и выше включает новый механизм зависимостей, который автоматически соответствует вариантам при употреблении библиотеки. Это означает, что вариант debug приложения автоматически потребляет вариант debug библиотеки и так далее. Он также работает при использовании вкуса: вариант приложения freeDebug будет потреблять вариант freeDebug библиотеки.

Чтобы плагин точно соответствовал вариантам, вам необходимо предоставить соответствующие запасные отступления, как описано в следующем разделе, для случаев, когда прямое совпадение невозможно.

Например, предположим, что ваше приложение настраивает тип сборки, называемый «постановка», но одна из его библиотечных зависимостей не. Когда плагин пытается создать версию «постановки» вашего приложения, он не будет знать, какую версию библиотеки использовать, и вы увидите сообщение об ошибке, похожее на следующее:

Error:Failed to resolve: Could not resolve project :mylibrary.
Required by:
    project :app

Разрешить ошибки сборки, связанные с сопоставлением вариантов

Плагин включает в себя элементы DSL, которые помогут вам контролировать, как Gradle разрешает ситуации, в которых прямой вариант совпадения между приложением и зависимостью невозможно.

Ниже приведен список вопросов, связанных с сопоставлением зависимостей с вариантами, и как их решить с помощью свойств DSL:

  • Ваше приложение включает в себя тип сборки, которого нет библиотечной зависимости.

    Например, ваше приложение включает в себя тип «постановки» сборки, но зависимость включает только типы сборки «отладка» и «выпуск».

    Обратите внимание, что нет проблем, когда библиотечная зависимость включает в себя тип сборки, которого нет в вашем приложении. Это потому, что плагин никогда не запрашивает этот тип сборки от зависимости.

    Используйте matchingFallbacks , чтобы указать альтернативные совпадения для данного типа сборки, как показано здесь:

    Котлин

    // In the app's build.gradle.kts file.
    android {
        buildTypes {
            getByName("debug") {}
            getByName("release") {}
            create("staging") {
                // Specifies a sorted list of fallback build types that the
                // plugin can try to use when a dependency does not include a
                // "staging" build type. You may specify as many fallbacks as you
                // like, and the plugin selects the first build type that's
                // available in the dependency.
                matchingFallbacks += listOf("debug", "qa", "release")
            }
        }
    }

    Круто

    // In the app's build.gradle file.
    android {
        buildTypes {
            debug {}
            release {}
            staging {
                // Specifies a sorted list of fallback build types that the
                // plugin can try to use when a dependency does not include a
                // "staging" build type. You may specify as many fallbacks as you
                // like, and the plugin selects the first build type that's
                // available in the dependency.
                matchingFallbacks = ['debug', 'qa', 'release']
            }
        }
    }
  • Для данного ароматического измерения, которое существует в приложении и в его библиотечной зависимости, ваше приложение включает в себя ароматы, которых нет в библиотеке.

    Например, как ваше приложение, так и его библиотечные зависимости включают в себя аромат «уровня». Тем не менее, измерение «уровня» в приложении включает в себя «бесплатные» и «оплачиваемые» ароматы, но зависимость включает только «демонстрацию» и «платные» ароматы для того же измерения.

    Обратите внимание, что для данного ароматического измерения, которое существует в приложении и в его библиотечной зависимости, нет проблем, когда библиотека включает в себя вкус продукта, который нет в вашем приложении. Это потому, что плагин никогда не запрашивает этот вкус от зависимости.

    Используйте matchingFallbacks , чтобы указать альтернативные совпадения для «бесплатного» аромата продукта приложения, как показано здесь:

    Котлин

    // In the app's build.gradle.kts file.
    android {
        defaultConfig{
        // Don't configure matchingFallbacks in the defaultConfig block.
        // Instead, specify fallbacks for a given product flavor in the
        // productFlavors block, as shown below.
      }
        flavorDimensions += "tier"
        productFlavors {
            create("paid") {
                dimension = "tier"
                // Because the dependency already includes a "paid" flavor in its
                // "tier" dimension, you don't need to provide a list of fallbacks
                // for the "paid" flavor.
            }
            create("free") {
                dimension = "tier"
                // Specifies a sorted list of fallback flavors that the plugin
                // can try to use when a dependency's matching dimension does
                // not include a "free" flavor. Specify as many
                // fallbacks as you like; the plugin selects the first flavor
                // that's available in the dependency's "tier" dimension.
                matchingFallbacks += listOf("demo", "trial")
            }
        }
    }

    Круто

    // In the app's build.gradle file.
    android {
        defaultConfig{
        // Don't configure matchingFallbacks in the defaultConfig block.
        // Instead, specify fallbacks for a given product flavor in the
        // productFlavors block, as shown below.
      }
        flavorDimensions 'tier'
        productFlavors {
            paid {
                dimension 'tier'
                // Because the dependency already includes a "paid" flavor in its
                // "tier" dimension, you don't need to provide a list of fallbacks
                // for the "paid" flavor.
            }
            free {
                dimension 'tier'
                // Specifies a sorted list of fallback flavors that the plugin
                // can try to use when a dependency's matching dimension does
                // not include a "free" flavor. Specify as many
                // fallbacks as you like; the plugin selects the first flavor
                // that's available in the dependency's "tier" dimension.
                matchingFallbacks = ['demo', 'trial']
            }
        }
    }
  • Библиотечная зависимость включает в себя ароматное измерение, которое нет вашего приложения.

    Например, библиотечная зависимость включает в себя ароматы для измерения «minapi», но ваше приложение включает в себя ароматы только для измерения «уровня». Если вы хотите создать версию вашего приложения «Freedebug», плагин не знает, использовать ли версия «minapi23debug» или «minapi18debug».

    Обратите внимание, что нет проблем, когда ваше приложение включает в себя ароматное измерение, которого нет библиотечной зависимости. Это потому, что плагин соответствует ароматам только тех измерений, которые существуют в зависимости. Например, если зависимость не включает измерение для ABIS, версия «freex86debug» вашего приложения будет использовать версию «Freebebug».

    Используйте missingDimensionStrategy в блоке defaultConfig , чтобы указать вкус плагина по умолчанию, чтобы выбрать из каждого пропущенного измерения, как показано в следующем образце. Вы также можете переопределить свой выбор в блоке productFlavors , поэтому каждый вкус может указать различную стратегию соответствия для недостающего измерения.

    Котлин

    // In the app's build.gradle.kts file.
    android {
        defaultConfig{
        // Specifies a sorted list of flavors that the plugin can try to use from
        // a given dimension. This tells the plugin to select the "minApi18" flavor
        // when encountering a dependency that includes a "minApi" dimension.
        // You can include additional flavor names to provide a
        // sorted list of fallbacks for the dimension.
        missingDimensionStrategy("minApi", "minApi18", "minApi23")
        // Specify a missingDimensionStrategy property for each
        // dimension that exists in a local dependency but not in your app.
        missingDimensionStrategy("abi", "x86", "arm64")
        }
        flavorDimensions += "tier"
        productFlavors {
            create("free") {
                dimension = "tier"
                // You can override the default selection at the product flavor
                // level by configuring another missingDimensionStrategy property
                // for the "minApi" dimension.
                missingDimensionStrategy("minApi", "minApi23", "minApi18")
            }
            create("paid") {}
        }
    }

    Круто

    // In the app's build.gradle file.
    android {
        defaultConfig{
        // Specifies a sorted list of flavors that the plugin can try to use from
        // a given dimension. This tells the plugin to select the "minApi18" flavor
        // when encountering a dependency that includes a "minApi" dimension.
        // You can include additional flavor names to provide a
        // sorted list of fallbacks for the dimension.
        missingDimensionStrategy 'minApi', 'minApi18', 'minApi23'
        // Specify a missingDimensionStrategy property for each
        // dimension that exists in a local dependency but not in your app.
        missingDimensionStrategy 'abi', 'x86', 'arm64'
        }
        flavorDimensions 'tier'
        productFlavors {
            free {
                dimension 'tier'
                // You can override the default selection at the product flavor
                // level by configuring another missingDimensionStrategy property
                // for the 'minApi' dimension.
                missingDimensionStrategy 'minApi', 'minApi23', 'minApi18'
            }
            paid {}
        }
    }

Для получения дополнительной информации см. matchingFallbacks и missingDimensionStrategy в плагине Android Gradle DSL.

Настройте настройки подписания

Gradle не подписывает APK или AAB вашего релиза, если вы явно не определите конфигурацию подписания для этой сборки. Если у вас еще нет ключа подписи, сгенерируйте клавишу загрузки и магазин клавиш с помощью Android Studio.

Чтобы вручную настроить конфигурации подписи для вашего типа сборки выпуска, используя конфигурации Gradle Build:

  1. Создайте магазин ключей. Слайт ключей - это двоичный файл, который содержит набор частных ключей. Вы должны сохранить свой магазин ключей в безопасном и безопасном месте.
  2. Создайте закрытый ключ. Частный ключ используется для подписи вашего приложения для распространения и никогда не включается в приложение и не раскрывается несанкционированным третьим лицам.
  3. Добавьте конфигурацию подписания в файл на уровне модуля build.gradle.kts :

    Котлин

    ...
    android {
        ...
        defaultConfig {...}
        signingConfigs {
            create("release") {
                storeFile = file("myreleasekey.keystore")
                storePassword = "password"
                keyAlias = "MyReleaseKey"
                keyPassword = "password"
            }
        }
        buildTypes {
            getByName("release") {
                ...
                signingConfig = signingConfigs.getByName("release")
            }
        }
    }

    Круто

    ...
    android {
        ...
        defaultConfig {...}
        signingConfigs {
            release {
                storeFile file("myreleasekey.keystore")
                storePassword "password"
                keyAlias "MyReleaseKey"
                keyPassword "password"
            }
        }
        buildTypes {
            release {
                ...
                signingConfig signingConfigs.release
            }
        }
    }

ПРИМЕЧАНИЕ. Включение паролей для вашего ключа выпуска и хранилища ключей в файл сборки не является хорошей практикой безопасности. Вместо этого настройте файл сборки, чтобы получить эти пароли из переменных среды или получить процесс сборки для этих паролей.

Чтобы получить эти пароли из переменных среды:

Котлин

storePassword = System.getenv("KSTOREPWD")
keyPassword = System.getenv("KEYPWD")

Круто

storePassword System.getenv("KSTOREPWD")
keyPassword System.getenv("KEYPWD")

В качестве альтернативы, вы можете загрузить хранилище ключа из локального файла свойств. По соображениям безопасности не добавляйте этот файл в управление источником. Вместо этого установите его локально для каждого разработчика. Чтобы узнать больше, прочитайте удалить информацию о подписи из ваших файлов сборки .

После завершения этого процесса вы можете распространять свое приложение и опубликовать его в Google Play.

ПРЕДУПРЕЖДЕНИЕ: Держите свой магазин ключей и личный ключ в безопасном и безопасном месте и убедитесь, что у вас есть безопасные резервные копии. Если вы используете подписание приложения Play и потеряете ключ загрузки, вы можете запросить сброс, используя Play Console. Если вы публикуете приложение без подписания приложений Play (для приложений, созданных до августа 2021 года), и вы теряете ключ подписания приложения, вы не сможете публиковать какие -либо обновления в своем приложении, поскольку вы всегда должны подписать все версии вашего приложения с одним и тем же ключом.

Подписание приложения для одежды ОС

При публикации приложений OS Wear ОС как Watch APK, так и опциональный телефон APK должны быть подписаны с одним и тем же ключом. Для получения дополнительной информации о приложениях для упаковки и подписи ОС см. Пакет и распространите приложения для износа .