На этой странице описывается, как работает слияние манифестов и как можно применить настройки слияния для разрешения конфликтов слияния. Общие сведения о файле манифеста приложения см. в обзоре манифеста приложения .
Объединение нескольких файлов манифеста
Ваш файл APK или Android App Bundle может содержать только один файл AndroidManifest.xml
, но ваш проект Android Studio может содержать несколько файлов манифеста, предоставленных основным набором исходных кодов, вариантами сборки и импортированными библиотеками. При сборке вашего приложения сборка Gradle объединяет все файлы манифеста в один файл манифеста, который упаковывается в ваше приложение.
Инструмент слияния манифестов объединяет все элементы XML из каждого файла, следуя эвристике слияния и предпочтениям слияния, которые вы определили с помощью специальных атрибутов XML.
Совет: Используйте представление объединенного манифеста , описанное в следующем разделе, чтобы просмотреть результаты объединенного манифеста и найти конфликтные ошибки.
Объединить приоритеты
Инструмент слияния последовательно объединяет все файлы манифеста в один файл в зависимости от приоритета каждого файла манифеста. Например, если у вас есть три файла манифеста, манифест с самым низким приоритетом объединяется с манифестом, имеющим следующий по приоритету, а затем он объединяется с манифестом с самым высоким приоритетом, как показано на рисунке 1.
Рисунок 1. Процесс объединения трех файлов манифеста, самого низкого приоритета, в самый высокий.
Существует три основных типа файлов манифеста, которые можно объединять друг с другом, и их приоритеты слияния следующие (сначала высший приоритет):
- Файл манифеста для вашего варианта сборки
Если у вас есть несколько исходных наборов для вашего варианта, их приоритеты манифеста следующие:
- Создайте вариант манифеста (например,
src/demoDebug/
). - Манифест типа сборки (например,
src/debug/
) - Манифест вкуса продукта (например,
src/demo/
)Если вы используете дополнительные измерения, приоритеты манифеста соответствуют порядку, в котором каждое измерение указано в свойстве
flavorDimensions
(первым является наивысший приоритет).
- Создайте вариант манифеста (например,
- Основной файл манифеста для модуля приложения
- Файл манифеста из включенной библиотеки
Если у вас несколько библиотек, их приоритеты манифеста соответствуют порядку, в котором они отображаются в вашем блоке
dependencies
Gradle.
Например, манифест библиотеки объединяется с основным манифестом, а затем основной манифест объединяется с манифестом варианта сборки. Обратите внимание, что это одни и те же приоритеты слияния для всех исходных наборов, как описано в разделе Сборка с исходными наборами .
Важно: Конфигурации сборки из файла build.gradle
переопределяют любые соответствующие атрибуты в объединенном файле манифеста. Например, minSdk
из файла build.gradle
или build.gradle.kts
переопределяет соответствующий атрибут в элементе манифеста <uses-sdk>
. Чтобы избежать путаницы, оставьте элемент <uses-sdk>
и определите эти свойства только в файле build.gradle
. Дополнительные сведения см. в разделе Настройка сборки .
Объединение эвристик конфликтов
Инструмент слияния может логически сопоставить каждый элемент XML из одного манифеста с соответствующим элементом в другом манифесте. Подробную информацию о том, как работает сопоставление, см. в разделе приоритеты слияния в предыдущем разделе.
Если элемент из манифеста с более низким приоритетом не соответствует ни одному элементу в манифесте с более высоким приоритетом, он добавляется в объединенный манифест. Однако если есть соответствующий элемент, инструмент слияния пытается объединить все атрибуты каждого из них в один и тот же элемент. Если инструмент обнаружит, что оба манифеста содержат один и тот же атрибут с разными значениями, возникает конфликт слияния.
В таблице 1 показаны возможные результаты, когда инструмент слияния пытается объединить все атрибуты в один и тот же элемент.
Таблица 1. Поведение слияния по умолчанию для значений атрибутов
Высокоприоритетный атрибут | Атрибут с низким приоритетом | Объединенный результат атрибута |
---|---|---|
Нет значения | Нет значения | Нет значения (используйте значение по умолчанию) |
Значение Б | Значение Б | |
Значение А | Нет значения | Значение А |
Значение А | Значение А | |
Значение Б | Ошибка конфликта — необходимо добавить маркер правила слияния . |
Однако есть несколько ситуаций, в которых инструмент слияния ведет себя по-другому, чтобы избежать конфликтов слияния:
- Атрибуты элемента
<manifest>
никогда не объединяются; используются только атрибуты из манифеста с наивысшим приоритетом. - Атрибут
android:required
в элементах<uses-feature>
и<uses-library>
использует слияние OR . В случае конфликта применяется"true"
и всегда включается функция или библиотека, требуемая одним манифестом. - Атрибуты в элементе
<uses-sdk>
всегда используют значения из манифеста с более высоким приоритетом, за исключением следующих ситуаций:- Если манифест с более низким приоритетом имеет более высокое значение
minSdk
, возникает ошибка, если вы не примените правило слиянияoverrideLibrary
. - Если манифест с более низким приоритетом имеет более низкое значение
targetSdkVersion
, инструмент слияния использует значение из манифеста с более высоким приоритетом, а также добавляет любые системные разрешения, необходимые для обеспечения правильного функционирования импортированной библиотеки (для случаев в более поздняя версия Android имеет увеличенные ограничения разрешений). Дополнительные сведения об этом поведении см. в разделе о неявных системных разрешениях .
- Если манифест с более низким приоритетом имеет более высокое значение
- Элемент
<intent-filter>
никогда не сопоставляется между манифестами. Каждый из них считается уникальным и добавляется к общему родительскому элементу в объединенном манифесте.
При всех других конфликтах между атрибутами вы получаете сообщение об ошибке и должны указать инструменту слияния, как его разрешить, добавив специальный атрибут в файл манифеста с более высоким приоритетом. См. следующий раздел о маркерах правил слияния .
Не зависьте от значений атрибутов по умолчанию. Поскольку все уникальные атрибуты объединяются в один и тот же элемент, это может привести к неожиданным результатам, если манифест с более высоким приоритетом действительно зависит от значения атрибута по умолчанию, не объявляя его. Например, если манифест с более высоким приоритетом не объявляет атрибут android:launchMode
, то он использует значение по умолчанию "standard"
, но если манифест с более низким приоритетом объявляет этот атрибут с другим значением, это значение применяется к объединенный манифест, который переопределяет значение по умолчанию. Вы должны явно определить каждый атрибут так, как вы хотите. Значения по умолчанию для каждого атрибута описаны в справочнике по манифесту .
Объединение маркеров правил
Маркер правила слияния — это атрибут XML, который можно использовать, чтобы выразить свои предпочтения относительно разрешения конфликтов слияния или удаления нежелательных элементов и атрибутов. Вы можете применить маркер либо ко всему элементу, либо только к определенным атрибутам элемента.
При объединении двух файлов манифеста инструмент слияния ищет эти маркеры в файле манифеста с более высоким приоритетом.
Все маркеры принадлежат пространству имен tools
Android, поэтому сначала необходимо объявить это пространство имен в элементе <manifest>
, как показано здесь:
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.myapp" xmlns:tools="http://schemas.android.com/tools">
Маркеры узлов
Чтобы применить правило слияния ко всему элементу XML (ко всем атрибутам в данном элементе манифеста и ко всем его дочерним тегам), используйте следующие атрибуты:
-
tools:node="merge"
- Объедините все атрибуты в этом теге и все вложенные элементы при отсутствии конфликтов, используя эвристику конфликтов слияния . Это поведение элементов по умолчанию.
Манифест с низким приоритетом:
<activity android:name="com.example.ActivityOne" android:windowSoftInputMode="stateUnchanged"> <intent-filter> <action android:name="android.intent.action.SEND" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> </activity>
Высокоприоритетный манифест:
<activity android:name="com.example.ActivityOne" android:screenOrientation="portrait" tools:node="merge"> </activity>
Результат объединенного манифеста:
<activity android:name="com.example.ActivityOne" android:screenOrientation="portrait" android:windowSoftInputMode="stateUnchanged"> <intent-filter> <action android:name="android.intent.action.SEND" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> </activity>
-
tools:node="merge-only-attributes"
- Объединять атрибуты только в этом теге; не объединяйте вложенные элементы.
Манифест с низким приоритетом:
<activity android:name="com.example.ActivityOne" android:windowSoftInputMode="stateUnchanged"> <intent-filter> <action android:name="android.intent.action.SEND" /> <data android:type="image/*" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> </activity>
Высокоприоритетный манифест:
<activity android:name="com.example.ActivityOne" android:screenOrientation="portrait" tools:node="merge-only-attributes"> </activity>
Результат объединенного манифеста:
<activity android:name="com.example.ActivityOne" android:screenOrientation="portrait" android:windowSoftInputMode="stateUnchanged"> </activity>
-
tools:node="remove"
- Удалите этот элемент из объединенного манифеста. Используется, когда вы обнаруживаете в объединенном манифесте элемент, который вам не нужен и который был предоставлен файлом манифеста с более низким приоритетом, который находится вне вашего контроля (например, импортированной библиотекой).
Манифест с низким приоритетом:
<activity-alias android:name="com.example.alias"> <meta-data android:name="cow" android:value="@string/moo"/> <meta-data android:name="duck" android:value="@string/quack"/> </activity-alias>
Высокоприоритетный манифест:
<activity-alias android:name="com.example.alias"> <meta-data android:name="cow" tools:node="remove"/> </activity-alias>
Результат объединенного манифеста:
<activity-alias android:name="com.example.alias"> <meta-data android:name="duck" android:value="@string/quack"/> </activity-alias>
-
tools:node="removeAll"
- Аналогично
tools:node="remove"
, но удаляет все элементы, соответствующие этому типу элемента (внутри одного родительского элемента).Манифест с низким приоритетом:
<activity-alias android:name="com.example.alias"> <meta-data android:name="cow" android:value="@string/moo"/> <meta-data android:name="duck" android:value="@string/quack"/> </activity-alias>
Высокоприоритетный манифест:
<activity-alias android:name="com.example.alias"> <meta-data tools:node="removeAll"/> </activity-alias>
Результат объединенного манифеста:
<activity-alias android:name="com.example.alias"> </activity-alias>
-
tools:node="replace"
- Полностью замените элемент с более низким приоритетом. То есть, если в манифесте с более низким приоритетом есть соответствующий элемент, игнорируйте его и используйте этот элемент точно так, как он отображается в этом манифесте.
Манифест с низким приоритетом:
<activity-alias android:name="com.example.alias"> <meta-data android:name="cow" android:value="@string/moo"/> <meta-data android:name="duck" android:value="@string/quack"/> </activity-alias>
Высокоприоритетный манифест:
<activity-alias android:name="com.example.alias" tools:node="replace"> <meta-data android:name="fox" android:value="@string/dingeringeding"/> </activity-alias>
Результат объединенного манифеста:
<activity-alias android:name="com.example.alias"> <meta-data android:name="fox" android:value="@string/dingeringeding"/> </activity-alias>
-
tools:node="strict"
- Генерировать сбой сборки каждый раз, когда этот элемент в манифесте с более низким приоритетом не совсем соответствует элементу в манифесте с более высоким приоритетом (если только это не разрешено другими маркерами правила слияния). Это переопределяет эвристику конфликта слияния . Например, если манифест с более низким приоритетом включает дополнительный атрибут, сборка завершается неудачей (тогда как поведение по умолчанию добавляет дополнительный атрибут в объединенный манифест).
Манифест с низким приоритетом:
<activity android:name="com.example.ActivityOne" android:windowSoftInputMode="stateUnchanged"> <intent-filter> <action android:name="android.intent.action.SEND" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> </activity>
Высокоприоритетный манифест:
<activity android:name="com.example.ActivityOne" android:screenOrientation="portrait" tools:node="strict"> </activity>
Это создает ошибку слияния манифеста. Два элемента манифеста вообще не могут различаться в строгом режиме. Чтобы устранить эти различия, необходимо применить другие маркеры правила слияния. (Без
tools:node="strict"
эти два файла могут объединиться без ошибок, как показано в примереtools:node="merge"
.)
Маркеры атрибутов
Чтобы вместо этого применить правило слияния только к определенным атрибутам в теге манифеста, используйте следующие атрибуты. Каждый атрибут принимает одно или несколько имен атрибутов (включая пространство имен атрибутов), разделенных запятыми.
-
tools:remove=" attr, ... "
- Удалите указанные атрибуты из объединенного манифеста. Используется, когда файл манифеста с более низким приоритетом содержит эти атрибуты и вы хотите, чтобы они не попали в объединенный манифест.
Манифест с низким приоритетом:
<activity android:name="com.example.ActivityOne" android:windowSoftInputMode="stateUnchanged">
Высокоприоритетный манифест:
<activity android:name="com.example.ActivityOne" android:screenOrientation="portrait" tools:remove="android:windowSoftInputMode">
Результат объединенного манифеста:
<activity android:name="com.example.ActivityOne" android:screenOrientation="portrait">
-
tools:replace=" attr, ... "
- Замените указанные атрибуты в манифесте с более низким приоритетом атрибутами из этого манифеста. Другими словами, всегда сохраняйте значения манифеста с более высоким приоритетом.
Манифест с низким приоритетом:
<activity android:name="com.example.ActivityOne" android:theme="@oldtheme" android:exported="false" android:windowSoftInputMode="stateUnchanged">
Высокоприоритетный манифест:
<activity android:name="com.example.ActivityOne" android:theme="@newtheme" android:exported="true" android:screenOrientation="portrait" tools:replace="android:theme,android:exported">
Результат объединенного манифеста:
<activity android:name="com.example.ActivityOne" android:theme="@newtheme" android:exported="true" android:screenOrientation="portrait" android:windowSoftInputMode="stateUnchanged">
-
tools:strict=" attr, ... "
- Создавать сбой сборки каждый раз, когда эти атрибуты в манифесте с более низким приоритетом не совсем соответствуют атрибутам в манифесте с более высоким приоритетом. Это поведение по умолчанию для всех атрибутов, за исключением атрибутов со специальным поведением, описанным в эвристике конфликта слияния .
Манифест с низким приоритетом:
<activity android:name="com.example.ActivityOne" android:screenOrientation="landscape"> </activity>
Высокоприоритетный манифест:
<activity android:name="com.example.ActivityOne" android:screenOrientation="portrait" tools:strict="android:screenOrientation"> </activity>
Это создает ошибку слияния манифеста. Для разрешения конфликта необходимо применить другие маркеры правила слияния. Это поведение по умолчанию, поэтому тот же результат получается при явном добавлении
tools:strict="screenOrientation"
.
Вы также можете применить несколько маркеров к одному элементу, как показано в следующем примере:
Манифест с низким приоритетом:
<activity android:name="com.example.ActivityOne" android:theme="@oldtheme" android:exported="false" android:allowTaskReparenting="true" android:windowSoftInputMode="stateUnchanged">
Высокоприоритетный манифест:
<activity android:name="com.example.ActivityOne" android:theme="@newtheme" android:exported="true" android:screenOrientation="portrait" tools:replace="android:theme,android:exported" tools:remove="android:windowSoftInputMode">
Результат объединенного манифеста:
<activity android:name="com.example.ActivityOne" android:theme="@newtheme" android:exported="true" android:allowTaskReparenting="true" android:screenOrientation="portrait">
Селектор маркеров
Если вы хотите применить маркеры правила слияния только к определенной импортированной библиотеке, добавьте tools:selector
с именем пакета библиотеки.
Например, в следующем манифесте правило remove
слияния применяется только в том случае, если файл манифеста с более низким приоритетом находится в библиотеке com.example.lib1
:
<permission android:name="permissionOne" tools:node="remove" tools:selector="com.example.lib1">
Если манифест с более низким приоритетом получен из любого другого источника, правило remove
слияния игнорируется.
Примечание. Если вы используете это с одним из маркеров атрибута, оно применяется ко всем атрибутам, указанным в маркере.
Переопределить <uses-sdk> для импортированных библиотек.
По умолчанию при импорте библиотеки со значением minSdk
, превышающим значение основного файла манифеста, возникает ошибка, и библиотеку невозможно импортировать.
Чтобы инструмент слияния игнорировал этот конфликт и импортировал библиотеку, сохраняя при этом меньшее значение minSdk
вашего приложения, добавьте атрибут overrideLibrary
в тег <uses-sdk>
. Значением атрибута может быть одно или несколько имен пакетов библиотек (разделенных запятыми), указывающих библиотеки, которые могут переопределить minSdk
основного манифеста.
Например, если основной манифест вашего приложения применяет overrideLibrary
следующим образом:
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.app" xmlns:tools="http://schemas.android.com/tools"> <uses-sdk tools:overrideLibrary="com.example.lib1, com.example.lib2"/> ...
Тогда следующий манифест можно будет объединить без ошибок в теге <uses-sdk>
, а объединенный манифест сохранит minSdk="2"
из манифеста приложения.
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.lib1"> <uses-sdk android:minSdk="4" /> ...
Неявные системные разрешения
Некоторые API-интерфейсы Android, которые когда-то были свободно доступны приложениям, в последних версиях Android стали ограничены системными разрешениями .
Чтобы избежать поломки приложений, которые ожидают доступа к этим API, последние версии Android позволяют приложениям продолжать получать доступ к этим API без разрешения, если targetSdkVersion
установлено значение меньше, чем в версии, в которую было добавлено ограничение. Такое поведение предоставляет приложению неявное разрешение на доступ к API. Это может повлиять на объединенные манифесты с разными значениями targetSdkVersion
.
Если файл манифеста с более низким приоритетом имеет более низкое значение для targetSdkVersion
, которое предоставляет ему неявное разрешение, а манифест с более высоким приоритетом не имеет такого же неявного разрешения (поскольку его targetSdkVersion
равна или выше, чем версия, в которой ограничение было добавлено), то инструмент слияния явно добавляет системное разрешение в объединенный манифест.
Например, если ваше приложение устанавливает targetSdkVersion
значение 4 или выше и импортирует библиотеку, для которой targetSdkVersion
установлено значение 3 или ниже, инструмент слияния добавляет разрешение WRITE_EXTERNAL_STORAGE
в объединенный манифест.
В таблице 2 перечислены все возможные разрешения, которые можно добавить в объединенный манифест:
Таблица 2. Список разрешений, которые инструмент слияния может добавить в объединенный манифест
Манифест с более низким приоритетом объявляет | Разрешения добавлены в объединенный манифест |
---|---|
targetSdkVersion – 3 или ниже. | WRITE_EXTERNAL_STORAGE , READ_PHONE_STATE |
targetSdkVersion – 15 или ниже и используется READ_CONTACTS | READ_CALL_LOG |
targetSdkVersion – 15 или ниже и используется WRITE_CONTACTS | WRITE_CALL_LOG |
Проверьте объединенный манифест и найдите конфликты.
Еще до создания приложения вы можете предварительно просмотреть, как выглядит объединенный манифест. Чтобы просмотреть предварительный просмотр, выполните следующие действия:
- В Android Studio откройте файл
AndroidManifest.xml
. - Откройте вкладку «Объединенный манифест» в нижней части редактора.
Представление «Объединенный манифест» показывает результаты объединенного манифеста слева и информацию о каждом объединенном файле манифеста справа, как показано на рис. 2.
Элементы, которые были объединены из файлов манифеста с более низким приоритетом, выделяются разными цветами слева. Ключ для каждого цвета указан в разделе «Источники манифеста» .
Рисунок 2. Представление объединенного манифеста.
Файлы манифеста, которые были частью сборки, но не содержали элементов или атрибутов, перечислены в разделе «Другие файлы манифеста» .
Чтобы просмотреть информацию о том, откуда взялся элемент, щелкните его на левой панели, и подробности появятся в разделе «Журнал слияния» .
Если возникают какие-либо конфликты, они отображаются в разделе «Ошибки слияния» с рекомендациями по разрешению конфликта с помощью маркеров правил слияния .
Ошибки также отображаются в окне журнала событий . Чтобы просмотреть их, выберите «Просмотр» > «Инструменты Windows» > «Журнал событий» .
Чтобы просмотреть полный журнал дерева решений по слиянию, вы можете найти файл журнала в каталоге build/outputs/logs/
вашего модуля с именем manifest-merger- buildVariant -report.txt
.
Объединение политик
Инструмент слияния манифестов может логически сопоставлять каждый элемент XML из одного файла манифеста с соответствующим элементом в другом файле. При слиянии каждый элемент сопоставляется с использованием ключа сопоставления , либо уникального значения атрибута (например, android:name
), либо естественной уникальности самого тега (например, может быть только один элемент <supports-screen>
).
Если два манифеста содержат один и тот же элемент XML, инструмент объединяет эти два элемента вместе, используя одну из трех политик слияния:
- Объединить
- Объедините все неконфликтующие атрибуты в один тег и объедините дочерние элементы в соответствии с соответствующей политикой слияния. Если какие-либо атрибуты конфликтуют друг с другом, объедините их вместе с помощью маркеров правила слияния .
- Объединить только детей
- Не объединяйте и не объединяйте атрибуты (сохраняйте только атрибуты, предоставленные файлом манифеста с наивысшим приоритетом) и объединяйте дочерние элементы в соответствии с их политикой объединения.
- Держать
- Оставьте элемент как есть и добавьте его к общему родительскому элементу в объединенном файле. Это используется только тогда, когда допустимо наличие нескольких объявлений одного и того же элемента.
В таблице 3 перечислены все типы элементов, тип используемой политики слияния и ключ, используемый для определения соответствия элемента между двумя манифестами:
Таблица 3. Политики слияния элементов манифеста и ключи сопоставления
Элемент | Политика объединения | Ключ совпадения |
---|---|---|
<action> | Объединить | android:name |
<activity> | Объединить | android:name |
<application> | Объединить | В каждом <manifest> есть только один. |
<category> | Объединить | android:name |
<data> | Объединить | На каждый <intent-filter> есть только один. |
<grant-uri-permission> | Объединить | На каждого <provider> есть только один. |
<instrumentation> | Объединить | android:name |
<intent-filter> | Держать | Нет соответствия; допускается несколько объявлений внутри родительского элемента. |
<manifest> | Объединить только детей | В каждом файле только один. |
<meta-data> | Объединить | android:name |
<path-permission> | Объединить | На каждого <provider> есть только один. |
<permission-group> | Объединить | android:name |
<permission> | Объединить | android:name |
<permission-tree> | Объединить | android:name |
<provider> | Объединить | android:name |
<receiver> | Объединить | android:name |
<screen> | Объединить | android:screenSize |
<service> | Объединить | android:name |
<supports-gl-texture> | Объединить | android:name |
<supports-screen> | Объединить | В каждом <manifest> есть только один. |
<uses-configuration> | Объединить | В каждом <manifest> есть только один. |
<uses-feature> | Объединить | Атрибут android:name (если отсутствует, то атрибут android:glEsVersion ) |
<uses-library> | Объединить | android:name |
<uses-permission> | Объединить | android:name |
<uses-sdk> | Объединить | В каждом <manifest> есть только один. |
Пользовательские элементы | Объединить | Нет соответствия; они неизвестны инструменту слияния и всегда включаются в объединенный манифест. |
Внедрить переменные сборки в манифест
Если вам нужно вставить в файл AndroidManifest.xml
переменные, определенные в файле build.gradle
, вы можете сделать это с помощью свойства manifestPlaceholders
. Это свойство принимает карту пар ключ-значение, как показано здесь:
классный
android { defaultConfig { manifestPlaceholders = [hostName:"www.example.com"] } ... }
Котлин
android { defaultConfig { manifestPlaceholders["hostName"] = "www.example.com" } ... }
Затем вы можете вставить один из заполнителей в файл манифеста в качестве значения атрибута:
<intent-filter ... >
<data android:scheme="https" android:host="${hostName}" ... />
...
</intent-filter>
По умолчанию инструменты сборки также предоставляют идентификатор приложения вашего приложения в заполнителе ${applicationId}
. Значение всегда соответствует окончательному идентификатору приложения для текущей сборки, включая изменения в вариантах сборки. Это полезно, если вы хотите использовать уникальное пространство имен для идентификаторов, таких как действие намерения, даже между вариантами сборки.
Например, если ваш файл build.gradle
выглядит так:
классный
android { defaultConfig { applicationId "com.example.myapp" } flavorDimensions "type" productFlavors { free { applicationIdSuffix ".free" dimension "type" } pro { applicationIdSuffix ".pro" dimension "type" } } }
Котлин
android { defaultConfig { applicationId = "com.example.myapp" } flavorDimensions += "type" productFlavors { create("free") { applicationIdSuffix = ".free" dimension = "type" } create("pro") { applicationIdSuffix = ".pro" dimension = "type" } } }
Затем вы можете вставить идентификатор приложения в свой манифест следующим образом:
<intent-filter ... >
<action android:name="${applicationId}.TRANSMOGRIFY" />
...
</intent-filter>
И явный результат создания «бесплатного» продукта таков:
<intent-filter ... >
<action android:name="com.example.myapp.free.TRANSMOGRIFY" />
...
</intent-filter>
Дополнительные сведения см. в разделе Установка идентификатора приложения .