На этой странице описывается, как работает объединение манифестов и как можно применить настройки объединения для разрешения конфликтов. Подробнее о файле манифеста приложения…
Как объединить несколько файлов манифеста
Файл APK или набор Android App Bundle может содержать только один файл AndroidManifest.xml, но в проекте Android Studio может быть несколько файлов манифеста, предоставленных основным набором исходных файлов, вариантами сборки и импортированными библиотеками. При сборке приложения Gradle объединяет все файлы манифеста в один, который упаковывается в приложение.
Инструмент объединения манифестов объединяет все элементы XML из каждого файла, следуя эвристике объединения и соблюдая настройки объединения, которые вы определили с помощью специальных атрибутов XML.
Совет. Чтобы посмотреть результаты объединения и найти конфликты, используйте объединенный манифест, описанный в следующем разделе.
Приоритеты объединения
Инструмент объединения последовательно объединяет все файлы манифеста в один файл на основе приоритета каждого файла манифеста. Например, если у вас есть три файла манифеста, то манифест с самым низким приоритетом объединяется с манифестом со следующим по высоте приоритетом, а затем он объединяется с манифестом с самым высоким приоритетом, как показано на рисунке 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>использует объединение ИЛИ. Если возникает конфликт, применяется"true"и всегда включается функция или библиотека, требуемая одним манифестом. - Атрибуты в элементе
<uses-sdk>всегда используют значение из манифеста с более высоким приоритетом, за исключением следующих ситуаций:- Если в манифесте с более низким приоритетом значение
minSdkвыше, произойдет ошибка, если вы не примените правило объединенияoverrideLibrary. - Если в манифесте с более низким приоритетом значение
targetSdkVersionменьше, инструмент объединения использует значение из манифеста с более высоким приоритетом, а также добавляет все системные разрешения, необходимые для правильной работы импортированной библиотеки (в случаях, когда в более поздней версии Android действуют более строгие ограничения на разрешения). Подробнее об этом поведении читайте в разделе Неявные системные разрешения.
- Если в манифесте с более низким приоритетом значение
- Элемент
<intent-filter>никогда не сопоставляется между манифестами. Каждый из них считается уникальным и добавляется в общий родительский элемент в объединенном манифесте.
Во всех остальных случаях вы получите сообщение об ошибке и должны будете указать инструменту объединения, как ее устранить, добавив специальный атрибут в файл манифеста с более высоким приоритетом. Подробнее о маркерах правил объединения…
Не полагайтесь на значения атрибутов по умолчанию. Поскольку все уникальные атрибуты объединяются в один элемент, это может привести к неожиданным результатам, если манифест с более высоким приоритетом зависит от значения атрибута по умолчанию, не объявляя его. Например, если в манифесте с более высоким приоритетом не объявлен атрибут android:launchMode, то используется значение по умолчанию – "standard". Однако если в манифесте с более низким приоритетом этот атрибут объявлен с другим значением, то в объединенном манифесте будет использоваться именно оно, а не значение по умолчанию. Вы должны явно определить каждый атрибут так, как вам нужно. Значения по умолчанию для каждого атрибута приведены в справочнике по манифесту.
Объединить маркеры правил
Маркер правила объединения – это атрибут XML, который позволяет указать, как разрешать конфликты объединения или удалять ненужные элементы и атрибуты. Маркер можно применить как ко всему элементу, так и к отдельным его атрибутам.
При объединении двух файлов манифеста инструмент объединения ищет эти маркеры в файле манифеста с более высоким приоритетом.
Все маркеры принадлежат пространству имен Android tools, поэтому сначала необходимо объявить это пространство имен в элементе <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="mergeOnlyAttributes"- Объединяйте только атрибуты в этом теге, не объединяйте вложенные элементы.
Манифест с низким приоритетом:
<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="mergeOnlyAttributes"> </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 или выше, а в импортируемой
библиотеке – targetSdkVersion3 или ниже, инструмент объединения добавит в объединенный манифест разрешение
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. - Нажмите на вкладку Merged Manifest (Объединенный манифест) в нижней части редактора.
В режиме Merged Manifest (Объединенный манифест) слева показаны результаты объединения, а справа – информация о каждом объединенном файле манифеста (см. рис. 2).
Элементы, объединенные из файлов манифеста с более низким приоритетом, выделены разными цветами слева. Значение каждого цвета указано в разделе Источники манифеста.
Рисунок 2. Режим просмотра объединенного манифеста.
Файлы манифеста, которые были частью сборки, но не добавили элементы или атрибуты, перечислены в разделе Другие файлы манифеста.
Чтобы узнать, откуда взят тот или иной элемент, нажмите на него на панели слева. Нужная информация появится в разделе Журнал объединения.
Если возникнут конфликты, они появятся в разделе Ошибки объединения с рекомендациями по их устранению с помощью маркеров правил объединения.
Ошибки также отображаются в окне Event Log (Журнал событий). Чтобы посмотреть их, выберите View (Вид) > Tool Windows (Окна инструментов) > Event Log (Журнал событий).
Полный журнал дерева решений по объединению можно найти в каталоге 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"] } ... }
Kotlin
android { defaultConfig { manifestPlaceholders["hostName"] = "www.example.com" } ... }
Затем вы можете вставить один из плейсхолдеров в файл манифеста в качестве значения атрибута:
<intent-filter ... >
<data android:scheme="https" android:host="${hostName}" ... />
...
</intent-filter>
По умолчанию инструменты сборки также предоставляют идентификатор приложения в плейсхолдере ${applicationId}. Значение всегда соответствует окончательному идентификатору приложения для текущей сборки, включая изменения, внесенные вариантами сборки.
Это полезно, если вы хотите использовать уникальное пространство имен для идентификаторов, например для действия intent, даже в разных вариантах сборки.
Например, если ваш файл build.gradle выглядит так:
Яркий
android { defaultConfig { applicationId "com.example.myapp" } flavorDimensions "type" productFlavors { free { applicationIdSuffix ".free" dimension "type" } pro { applicationIdSuffix ".pro" dimension "type" } } }
Kotlin
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>
Подробнее о том, как задать идентификатор приложения…