マニフェスト ファイルを管理する

このページでは、マニフェスト マージの仕組みと、マージ優先順位を適用してマージ競合を解決する方法について説明します。アプリ マニフェスト ファイルの概要については、アプリ マニフェストの概要をご覧ください。

複数のマニフェスト ファイルをマージする

APK または Android App Bundle ファイルには AndroidManifest.xml ファイルが 1 つだけ含まれていますが、Android Studio プロジェクトには、メイン ソースセット、ビルド バリアント、インポート済みライブラリによって提供される複数のマニフェスト ファイルが含まれる場合があります。アプリをビルドする際、Gradle ビルドはすべてのマニフェスト ファイルを単一のマニフェスト ファイルにマージして、アプリ内にパッケージ化します。

マニフェスト マージツールは、マージ ヒューリスティックに沿い、特別な XML 属性で定義したマージ優先順位に従って、各ファイルのすべての XML 要素を結合します。

ヒント: [Merged Manifest] ビューを使用すると、次のセクションで説明するように、マージ マニフェストの結果をプレビューしたり、競合エラーを確認したりできます。

マージ優先順位

マージツールは、各マニフェスト ファイルの優先順位に基づいて、すべてのマニフェスト ファイルを 1 つのファイルに順次結合します。たとえば、3 つのマニフェスト ファイルがある場合、図 1 に示すように、優先度第 3 位のマニフェストが優先度第 2 位のマニフェストにマージされ、そのマージ結果が優先度第 1 位のマニフェストにマージされます。

図 1. 3 つのマニフェスト ファイルのマージ処理(最も優先度が低いファイルから最も優先度が高いファイルに順次マージ)。

相互にマージ可能なマニフェスト ファイルには 3 つの基本タイプがあります。以下に、マージ優先順位が最も高いものから順に示します。

  1. ビルド バリアントのマニフェスト ファイル

    バリアントに複数のソースセットがある場合、そのマニフェストの優先順位は次のようになります。

    • ビルド バリアント マニフェスト(src/demoDebug/ など)
    • ビルドタイプ マニフェスト(src/debug/ など)
    • プロダクト フレーバー マニフェスト(src/demo/ など)

      フレーバー ディメンションを使用している場合、マニフェストの優先順位は flavorDimensions プロパティ内にリストされている各ディメンションの順序に対応します(リスト内の登場順)。

  2. アプリ モジュールのメイン マニフェスト ファイル
  3. 含まれているライブラリ内のマニフェスト ファイル

    複数のライブラリがある場合、マニフェストの優先順位は、Gradle dependencies ブロック内の登場順と一致します。

たとえば、ライブラリ マニフェストはメイン マニフェストにマージされ、次にメイン マニフェストがビルド バリアント マニフェストにマージされます。注: すべてのソースセットで同じマージ優先順位になります。ソースセットでビルドするをご覧ください。

重要: build.gradle ファイル内のビルド構成は、マージされるマニフェスト ファイル内の対応する属性をオーバーライドします。たとえば、build.gradle または build.gradle.kts ファイルの minSdk は、<uses-sdk> マニフェスト要素内の対応する属性をオーバーライドします。混乱を避けるため、<uses-sdk> 要素を削除し、build.gradle ファイルでのみプロパティを定義してください。詳細については、ビルドを構成するをご覧ください。

マージ競合ヒューリスティック

マージツールは、あるマニフェスト内のすべての XML 要素を、別のマニフェスト内の対応する要素に論理的にマッチングできますマッチング処理の詳細については、前のセクションのマージ優先順位をご覧ください。

優先度の低いマニフェスト内の要素が、優先度の高いマニフェスト内のどの要素にも一致しない場合、その要素はマージ マニフェストに追加されます。ただし、一致する要素が存在する場合、マージツールは各マニフェスト内のすべての属性を単一の要素に結合しようとします。両方のマニフェスト内に同じ属性があるがその値が異なることをツールが検出した場合、マージの競合が発生します。

マージツールがすべての属性を単一の要素に結合しようとする際に起こり得る結果を表 1 に示します。

表 1. 属性値のデフォルト マージ処理

優先度の高い属性 優先度の低い属性 属性のマージ結果
値なし 値なし 値なし(デフォルト値を使用)
値 B 値 B
値 A 値なし 値 A
値 A 値 A
値 B 競合エラー: マージルール マーカーを追加する必要があります。

ただし、マージ競合を避けるために、マージツールが別の処理を行う場合があります。

  • <manifest> 要素内の属性はマージされません。最も優先度が高いマニフェストの属性だけが使用されます。
  • <uses-feature> 要素と <uses-library> 要素の android:required 属性では、「OR」マージが使用されます。競合が発生すると "true" が適用され、あるマニフェストに必要な機能またはライブラリが必ず含まれるようになります。
  • <uses-sdk> 要素内の属性には、最も優先度の高いマニフェストの値が常に使用されます。ただし、次の場合を除きます。
    • 優先度の低いマニフェストの方が minSdk 値が大きい場合、overrideLibrary マージルールを適用しない限りエラーが発生します。
    • 優先度の低いマニフェストの方が targetSdkVersion 値が小さい場合、マージツールは、優先度の高いマニフェストの値を使用します。インポート ライブラリが引き続き適切に機能するために必要なシステム権限も追加されます(上位の Android バージョンの方が権限の制限が強化されている場合に対応するため)。この処理の詳細については、暗黙的システム権限をご覧ください。
  • <intent-filter> 要素をマニフェスト間でマッチングすることはありません。各要素は一意と見なされ、マージ マニフェストの共通親要素に追加されます。

属性間に他の競合がある場合、すべてエラーが発生します。その場合、優先度の高いマニフェスト ファイル内に特別な属性を追加して、マージツールに解決方法を指定する必要があります(マージルール マーカーをご覧ください)。

デフォルト属性値に依存しないでください。すべての一意の属性が単一の要素に結合されるため、優先度の高いマニフェストが属性の値を宣言せずにデフォルト値に依存していた場合、予期しない結果が生じる可能性があります。たとえば、優先度の高いマニフェストが android:launchMode 属性を宣言していない場合、デフォルト値の "standard" が使用されますが、優先度の低いマニフェストが別の値を使用してこの属性を宣言していた場合、その値がマージ マニフェストに適用されます(デフォルト値をオーバーライドします)。使用する各属性は明示的に定義する必要があります。各属性のデフォルト値については、マニフェスト リファレンスをご覧ください。

マージルール マーカー

マージルール マーカーは、マージ時の競合を解決したり、不要な要素や属性を削除したりする際の優先順位を示すために使用する XML 属性です。マーカーは、要素全体または要素内の特定の属性に対して適用できます。

2 つのマニフェスト ファイルをマージする際、マージツールは、優先度の高いマニフェスト ファイル内にマーカーがないか検索します。

すべてのマーカーは 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="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>

この場合、マニフェスト マージエラーが発生します。strict モードでは、2 つのマニフェスト要素は完全に一致している必要があります。不一致を解決するには、別のマージルール マーカーを適用する必要があります(tools:node="merge" の例に示すように、tools:node="strict" がなくても、この 2 つのファイルは問題なくマージできます)。

属性マーカー

マニフェスト タグ内の特定の属性だけにマージルールを適用するには、下記の属性を使用します。各属性には、1 つまたは複数の属性名(属性名前空間を含む)を指定できます(複数の場合はカンマ区切りで指定します)。

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" を明示的に追加した場合も同じ結果になります。

次の例に示すように、1 つの要素に複数のマーカーを適用することもできます。

優先度の低いマニフェスト:

<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 属性を追加して、ライブラリ パッケージ名を指定します。

たとえば、下記のマニフェストでは、優先度の低いマニフェスト ファイルが com.example.lib1 ライブラリに由来している場合に限り、remove マージルールが適用されます。

<permission android:name="permissionOne"
    tools:node="remove"
    tools:selector="com.example.lib1">

優先度の低いマニフェストが他のソースに由来している場合、remove マージルールは無視されます。

注: マーカー セレクタを属性マーカーと一緒に使用した場合、マーカー セレクタは、そのマーカー内で指定されているすべての属性に適用されます。

インポート ライブラリの <uses-sdk> をオーバーライドする

minSdk 値がメイン マニフェスト ファイルよりも大きいライブラリをインポートしようとすると、デフォルトではエラーが発生し、ライブラリはインポートできません。

<uses-sdk> タグに overrideLibrary 属性を追加すると、アプリの小さい方の minSdk 値をアプリレベルで維持したままで、マージツールが競合を無視してライブラリをインポートできるようになります。この属性値には、1 つまたは複数のライブラリ パッケージ名を指定できます(複数の場合はカンマ区切りで指定します)。これにより、メイン マニフェストの 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" />
...

暗黙的システム権限

以前はアプリから無制限にアクセスできた一部の Android API が、最近の Android バージョンではシステム権限によって制限されるようになりました。

このような API へのアクセスを前提とするアプリが正常に動作するように、最近の Android バージョンでは、アプリの targetSdkVersion 値が、制限が追加されたバージョンよりも小さい値に設定されていれば、権限がなくても API に引き続きアクセスできるようになっています。この動作により、API へのアクセスを許可する暗黙的な権限がアプリに付与されます。これは、targetSdkVersion の値が異なるマージ マニフェストに影響する可能性があります。

優先度の低いマニフェスト ファイルの方が targetSdkVersion 値が小さく、暗黙的権限を付与されており、優先度の高いマニフェストの方は(制限が追加されたバージョン以上の targetSdkVersion 値であるために)暗黙的権限が付与されていない場合、マージツールは、このシステム権限をマージ マニフェストに明示的に追加します。

たとえば、アプリが targetSdkVersion を 4 以上に設定していて、targetSdkVersion が 3 以下のライブラリをインポートした場合、マージツールは、マージ マニフェストに WRITE_EXTERNAL_STORAGE 権限を追加します。

マージ マニフェストに追加される可能性があるすべての権限を表 2 に示します。

表 2. マージツールがマージ マニフェストに追加する可能性のある権限のリスト

優先度の低いマニフェスト内の宣言 マージ後のマニフェストに追加されるパーミッション
targetSdkVersion が 3 以下 WRITE_EXTERNAL_STORAGEREAD_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 のように、左側にマージ マニフェストの結果が表示され、右側に各マージ マニフェスト ファイルの情報が表示されます。

優先度の低いマニフェスト ファイルからマージされた要素は、ビューの左側に、異なる色でハイライト表示されます。それぞれの色の説明は、[Manifest Sources] に記載されています。

図 2. [Merged Manifest] ビュー

ビルドの一部ではあっても要素や属性を指定していないマニフェスト ファイルは、[Other Manifest Files] に表示されます。

要素の元の所属に関する情報を表示するには、左側でその要素をクリックします。[Merging Log] に詳細が表示されます。

競合が発生している場合、[Merging Errors] に表示されます。ここには、マージルール マーカーを使用して競合を解決するためのおすすめの方法も表示されます。

エラーは [Event Log] ウィンドウにも表示されます([View] > [Tool Windows] > [Event Log] を選択します)。

マージ決定木の完全なログは、モジュールの build/outputs/logs/ ディレクトリにある manifest-merger-buildVariant-report.txt というログファイルで確認できます。

マージポリシー

マニフェスト マージツールは、あるマニフェスト内のすべての XML 要素と、別のファイル内の対応する要素を、論理的にマッチングできます。マージツールは、「マッチングキー」を使用して各要素をマッチングします。マッチングキーとは、一意の属性値(android:name など)か、タグ自体が元々備えている一意性(例: <supports-screen> 要素は 1 つに限られる)のいずれかです。

2 つのマニフェスト内に同じ XML 要素が含まれている場合、マージツールは、以下の 3 つのマージポリシーのいずれかを使用して 2 つの要素をマージします。

マージ
競合していないすべての属性を 1 つのタグに結合し、子要素をそれぞれのマージポリシーに従ってマージします。競合が発生している属性の場合は、マージルール マーカーを使用してマージします。
子だけをマージ
属性のマージ(結合)は行いません(最も優先度の高いマニフェスト ファイルが提供する属性だけを維持します)。子要素は、それぞれのマージポリシーに従ってマージします。
維持
各要素を維持したまま、マージファイル内の共通親要素に追加します。このポリシーは、1 つの要素に対して複数の宣言が可能な場合に限り使用されます。

各要素のタイプ、使用されるマージポリシーのタイプ、2 つのマニフェスト間の要素のマッチングを判断する際に使用されるキーを表 3 に示します。

表 3. マニフェスト要素のマージポリシーとマッチングキー

要素 マージポリシー マッチングキー
<action> マージ android:name 属性
<activity> マージ android:name 属性
<application> マージ <manifest> ごとに 1 つ
<category> マージ android:name 属性
<data> マージ <intent-filter> ごとに 1 つ
<grant-uri-permission> マージ <provider> ごとに 1 つ
<instrumentation> マージ android:name 属性
<intent-filter> 維持 マッチングなし。親要素内で複数の宣言が可能
<manifest> 子だけをマージ ファイルごとに 1 つ
<meta-data> マージ android:name 属性
<path-permission> マージ <provider> ごとに 1 つ
<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> ごとに 1 つ
<uses-configuration> マージ <manifest> ごとに 1 つ
<uses-feature> マージ android:name 属性(存在しない場合は android:glEsVersion 属性)
<uses-library> マージ android:name 属性
<uses-permission> マージ android:name 属性
<uses-sdk> マージ <manifest> ごとに 1 つ
カスタム要素 マージ マッチングなし。マージツールでは認識できず、常にマージ マニフェストに結合

マニフェストにビルド変数を追加する

build.gradle ファイルで定義されている変数を AndroidManifest.xml ファイルに追加する必要がある場合は、manifestPlaceholders プロパティを使用して追加できます。このプロパティは、以下に示すように Key-Value ペアのマップを受け取ります。

Groovy

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>

デフォルトでは、アプリのアプリケーション ID もビルドツールにより ${applicationId} プレースホルダに設定されます。この値は、現在のビルドの最終的なアプリケーション ID(ビルド バリアントによる変更を含む)と常に一致します。これは、ビルド バリアント間でもインテントのアクションなどの識別子に一意の名前空間を使用する場合に役立ちます。

たとえば、build.gradle ファイルが次のようであったとします。

Groovy

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"
        }
    }
}

この場合、次のようにアプリケーション ID をマニフェストに追加できます。

<intent-filter ... >
    <action android:name="${applicationId}.TRANSMOGRIFY" />
    ...
</intent-filter>

また、「free」プロダクト フレーバーをビルドした場合のマニフェストは次のようになります。

<intent-filter ... >
   <action android:name="com.example.myapp.free.TRANSMOGRIFY" />
    ...
</intent-filter>

詳しくは、アプリケーション ID の設定をご覧ください。