Как управлять файлами манифеста

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

Как объединить несколько файлов манифеста

Файл APK или набор Android App Bundle может содержать только один файл AndroidManifest.xml, но в проекте Android Studio может быть несколько файлов манифеста, предоставленных основным набором исходных файлов, вариантами сборки и импортированными библиотеками. При сборке приложения Gradle объединяет все файлы манифеста в один, который упаковывается в приложение.

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

Совет. Чтобы посмотреть результаты объединения и найти конфликты, используйте объединенный манифест, описанный в следующем разделе.

Приоритеты объединения

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

Рисунок 1. Процесс объединения трёх файлов манифеста, от самого низкого приоритета к самому высокому.

Существует три основных типа файлов манифеста, которые можно объединять. Ниже они перечислены в порядке приоритета (от самого высокого к самому низкому):

  1. Файл манифеста для варианта сборки.

    Если у вас несколько наборов исходных файлов для варианта, приоритеты их манифестов следующие:

    • Манифест варианта сборки (например, src/demoDebug/)
    • Манифест типа сборки (например, src/debug/)
    • Манифест версии продукта (например, src/demo/)

      Если вы используете группы вариантов, приоритеты манифестов соответствуют порядку, в котором каждая группа указана в свойстве flavorDimensions (первая имеет наивысший приоритет).

  2. Основной файл манифеста для модуля приложения.
  3. Файл манифеста из включенной библиотеки

    Если у вас несколько библиотек, приоритеты их манифестов соответствуют порядку, в котором они указаны в блоке 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

Как проверить объединенный манифест и найти конфликты

Вы можете посмотреть, как будет выглядеть объединенный манифест, ещё до создания приложения. Чтобы посмотреть предварительную версию, выполните следующие действия:

  1. В Android Studio откройте файл AndroidManifest.xml.
  2. Нажмите на вкладку 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>

Подробнее о том, как задать идентификатор приложения…