Cómo administrar los archivos de manifiesto

Organiza tus páginas con colecciones Guarda y categoriza el contenido según tus preferencias.

En esta página, se describe el funcionamiento de la combinación de manifiestos y cómo aplicar preferencias de combinación para resolver conflictos. Para obtener una introducción al archivo de manifiesto de la app, consulta la descripción general del manifiesto de la app.

Cómo combinar varios archivos de manifiesto

El archivo de APK o Android App Bundle puede contener solo un archivo AndroidManifest.xml, pero el proyecto de Android Studio puede contener varios, ya que el conjunto de fuentes principal, las variantes de las compilaciones y las bibliotecas importadas pueden proporcionarlos. Cuando creas la app, la compilación de Gradle combina todos los archivos de manifiesto en uno solo que se empaqueta en la app.

La herramienta de combinación de manifiestos combina todos los elementos XML de cada archivo mediante una heurística de combinación y de acuerdo con las preferencias de combinación definidas con atributos XML especiales.

Sugerencia: Usa la vista Manifiesto combinado que se describe en la siguiente sección para obtener una vista previa de los resultados del manifiesto combinado y detectar errores de conflicto.

Prioridades de combinación

La herramienta de combinación combina todos los archivos de manifiesto en un archivo de manera secuencial, según la prioridad de cada uno. Por ejemplo, si tienes tres archivos de manifiesto, el manifiesto de menor prioridad se combina con el de la siguiente prioridad y, a su vez, ese se vuelve a combinar con el manifiesto de mayor prioridad, como se ilustra en la figura 1.

Figura 1: Proceso de combinación de tres archivos de manifiesto, en el que el de menor prioridad se combina dentro del de mayor prioridad.

Existen tres tipos básicos de archivos de manifiesto que pueden combinarse. A continuación, se indican sus prioridades de combinación (la mayor prioridad se muestra primero):

  1. Archivo de manifiesto para tu variante de compilación

    Si tienes varios conjuntos de orígenes para tu variante, las prioridades de los manifiestos son las siguientes:

    • Manifiesto de variantes de compilación (como src/demoDebug/)
    • Manifiesto de tipos de compilación (como src/debug/)
    • Manifiesto de variantes de productos (como src/demo/)

      Si usas dimensiones de tipo, las prioridades de manifiesto corresponden al orden en que se enumera cada dimensión en la propiedad flavorDimensions (la mayor prioridad se muestra primero).

  2. Archivo de manifiesto principal para el módulo de la app
  3. Archivo de manifiesto de una biblioteca incluida

    Si tienes varias bibliotecas, las prioridades de los manifiestos de estas coinciden con el orden en que aparecen en el bloque dependencies de Gradle.

Por ejemplo, un manifiesto de biblioteca se combina en el manifiesto principal y, luego, este se combina en el manifiesto de variantes de compilación. Ten en cuenta que estas prioridades de combinación son las mismas para todos los conjuntos de orígenes, como se describe en Cómo realizar compilaciones con conjuntos de orígenes.

Importante: Las configuraciones de compilación del archivo build.gradle anulan cualquier atributo coincidente en el archivo de manifiesto combinado. Por ejemplo, el minSdk del archivo build.gradle o build.gradle.kts anula el atributo coincidente del elemento de manifiesto <uses-sdk>. Para evitar confusiones, omite el elemento <uses-sdk> y define estas propiedades solamente en el archivo build.gradle. Para obtener más información, consulta Cómo configurar tu compilación.

Heurística de conflictos de combinación

La herramienta de combinación puede unir de manera lógica cada elemento XML de un manifiesto con un elemento coincidente de otro manifiesto. Para obtener información sobre cómo funciona la coincidencia, consulta las prioridades de combinación de la sección anterior.

Si un elemento del manifiesto de menor prioridad no coincide con ningún elemento del manifiesto de mayor prioridad, se agregará al manifiesto combinado. Sin embargo, si hay un elemento coincidente, la herramienta de combinación intenta combinar todos los atributos de cada uno en el mismo elemento. Si la herramienta detecta que ambos manifiestos contienen el mismo atributo con diferentes valores, se produce un conflicto de combinación.

En la tabla 1, se ilustran los posibles resultados que pueden generarse cuando una herramienta de combinación intenta combinar todos los atributos en el mismo elemento.

Tabla 1: Comportamiento de combinación predeterminado para valores de atributo

Atributo de prioridad alta Atributo de prioridad baja Resultado combinado del atributo
Sin valor Sin valor Sin valor (usar valor predeterminado)
Valor B Valor B
Valor A Sin valor Valor A
Valor A Valor A
Valor B Error de conflicto: debes agregar un marcador de regla de combinación.

Sin embargo, existen algunas situaciones en las que la herramienta de combinación se comporta de manera diferente para evitar conflictos de combinación:

  • Nunca se combinan los atributos del elemento <manifest>; solo se usan los atributos del manifiesto de mayor prioridad.
  • El atributo android:required de los elementos <uses-feature> y <uses-library> usa una combinación O. Si hay un conflicto, se aplica "true" y siempre se incluye la función o la biblioteca que requiere un manifiesto.
  • Los atributos del elemento <uses-sdk> siempre usan el valor del manifiesto de mayor prioridad, excepto en las siguientes situaciones:
    • Cuando el manifiesto de menor prioridad tiene un valor minSdk que es mayor, se produce un error, a menos que apliques la regla de combinación overrideLibrary.
    • Cuando el manifiesto de menor prioridad tiene un valor targetSdkVersion menor, la herramienta de combinación usa el valor del manifiesto de mayor prioridad y también agrega los permisos del sistema que se necesitan para garantizar que la biblioteca importada siga funcionando correctamente (en casos en los que la versión superior de Android haya aumentado las restricciones de permisos). Para obtener más información sobre este comportamiento, consulta la sección sobre permisos implícitos del sistema.
  • El elemento <intent-filter> nunca coincide entre diferentes manifiestos. Cada uno recibe tratamiento exclusivo y se agrega al elemento principal común en el manifiesto combinado.

Para todos los demás conflictos entre atributos, aparecerá un error y deberás indicar a la herramienta de combinación la manera de resolverlo. Para ello, debes agregar un atributo especial en el archivo de manifiesto de mayor prioridad. Consulta la siguiente sección sobre marcadores de reglas de combinación.

No dependas de los valores de atributos predeterminados. Como todos los atributos únicos se combinan en el mismo elemento, es posible que se produzcan resultados inesperados si el manifiesto de mayor prioridad en realidad depende del valor predeterminado de un atributo sin declararlo. Por ejemplo, si el manifiesto de mayor prioridad no declara el atributo android:launchMode, usa el valor predeterminado de "standard", pero, si el manifiesto de menor prioridad declara esto con un valor diferente, ese valor se aplica al manifiesto combinado, lo que anula el valor predeterminado. Debes definir cada atributo de manera explícita como desees. Los valores predeterminados de cada atributo se documentan en la referencia del manifiesto.

Marcadores de reglas de combinación

Un marcador de reglas de combinación es un atributo XML que puedes usar para expresar tu preferencia para resolver conflictos de combinación o quitar elementos y atributos no deseados. Puedes aplicar un marcador a un elemento entero o solo a atributos específicos de un elemento.

Cuando se combinan dos archivos de manifiesto, la herramienta de combinación busca estos marcadores en el archivo de manifiesto de mayor prioridad.

Todos los marcadores pertenecen al espacio de nombres tools de Android. Por eso, primero debes declarar este espacio de nombres en el elemento <manifest>, como se observa a continuación:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.myapp"
    xmlns:tools="http://schemas.android.com/tools">

Marcadores de nodos

Para aplicar una regla de combinación a un elemento XML completo (a todos los atributos de un elemento de manifiesto específico y a todas sus etiquetas secundarias), usa los siguientes atributos:

tools:node="merge"
Combina todos los atributos de esta etiqueta y todos los elementos anidados cuando no hay conflictos usando la heurística de conflictos de combinación. Este es el comportamiento predeterminado de los elementos.

Manifiesto de prioridad baja:

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

Manifiesto de prioridad alta:

<activity android:name="com.example.ActivityOne"
    android:screenOrientation="portrait"
    tools:node="merge">
</activity>

Resultado del manifiesto combinado:

<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"
Combina solo los atributos de esta etiqueta. No combina elementos anidados.

Manifiesto de prioridad baja:

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

Manifiesto de prioridad alta:

<activity android:name="com.example.ActivityOne"
    android:screenOrientation="portrait"
    tools:node="merge-only-attributes">
</activity>

Resultado del manifiesto combinado:

<activity android:name="com.example.ActivityOne"
    android:screenOrientation="portrait"
    android:windowSoftInputMode="stateUnchanged">
</activity>
tools:node="remove"
Quita este elemento del manifiesto combinado. Se usa cuando descubres en el manifiesto combinado un elemento que no necesitas que se haya proporcionado en un archivo de manifiesto de menor prioridad que está fuera de tu control (como una biblioteca importada).

Manifiesto de prioridad baja:

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

Manifiesto de prioridad alta:

<activity-alias android:name="com.example.alias">
  <meta-data android:name="cow"
      tools:node="remove"/>
</activity-alias>

Resultado del manifiesto combinado:

<activity-alias android:name="com.example.alias">
  <meta-data android:name="duck"
      android:value="@string/quack"/>
</activity-alias>
tools:node="removeAll"
Similar a tools:node="remove", pero quita todos los elementos que coinciden con este tipo de elemento (dentro del mismo elemento superior).

Manifiesto de prioridad baja:

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

Manifiesto de prioridad alta:

<activity-alias android:name="com.example.alias">
  <meta-data tools:node="removeAll"/>
</activity-alias>

Resultado del manifiesto combinado:

<activity-alias android:name="com.example.alias">
</activity-alias>
tools:node="replace"
Reemplaza el elemento de prioridad inferior por completo. Es decir, si hay un elemento coincidente en el manifiesto de menor prioridad, debes ignorarlo y usar este elemento exactamente como aparece en este manifiesto.

Manifiesto de prioridad baja:

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

Manifiesto de prioridad alta:

<activity-alias android:name="com.example.alias"
    tools:node="replace">
  <meta-data android:name="fox"
      android:value="@string/dingeringeding"/>
</activity-alias>

Resultado del manifiesto combinado:

<activity-alias android:name="com.example.alias">
  <meta-data android:name="fox"
      android:value="@string/dingeringeding"/>
</activity-alias>
tools:node="strict"
Genera una falla de compilación cada vez que este elemento del manifiesto de menor prioridad no coincide exactamente con el elemento del manifiesto de mayor prioridad (salvo que se resuelva a través de otros marcadores de reglas de combinación). De esta manera, se anula la heurística de conflictos de combinación. Por ejemplo, si el manifiesto de menor prioridad incluye un atributo adicional, la compilación falla (mientras que el comportamiento predeterminado agrega el atributo adicional al manifiesto combinado).

Manifiesto de prioridad baja:

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

Manifiesto de prioridad alta:

<activity android:name="com.example.ActivityOne"
    android:screenOrientation="portrait"
    tools:node="strict">
</activity>

De esta manera, se crea un error de combinación de manifiestos. Los dos elementos de manifiestos no pueden diferir de ninguna manera en el modo estricto. Debes aplicar otros marcadores de reglas de combinación para resolver estas diferencias. (Sin tools:node="strict", estos dos archivos se pueden combinar sin errores, como se muestra en el ejemplo de tools:node="merge").

Marcadores de atributos

Para aplicar una regla de combinación solo a atributos específicos en una etiqueta de manifiesto, usa los siguientes atributos. Cada atributo acepta uno o más nombres (incluido el espacio de nombres de los atributos), separados por coma.

tools:remove="attr, ..."
Quita los atributos especificados del manifiesto combinado. Se usa cuando el archivo de manifiesto de menor prioridad incluye estos atributos, y quieres asegurarte de que no se incluyan en el manifiesto combinado.

Manifiesto de prioridad baja:

<activity android:name="com.example.ActivityOne"
    android:windowSoftInputMode="stateUnchanged">

Manifiesto de prioridad alta:

<activity android:name="com.example.ActivityOne"
    android:screenOrientation="portrait"
    tools:remove="android:windowSoftInputMode">

Resultado del manifiesto combinado:

<activity android:name="com.example.ActivityOne"
    android:screenOrientation="portrait">
tools:replace="attr, ..."
Reemplaza los atributos especificados en el manifiesto de menor prioridad por los de este manifiesto. Es decir, conserva siempre los valores de los manifiestos de mayor prioridad.

Manifiesto de prioridad baja:

<activity android:name="com.example.ActivityOne"
    android:theme="@oldtheme"
    android:exported="false"
    android:windowSoftInputMode="stateUnchanged">

Manifiesto de prioridad alta:

<activity android:name="com.example.ActivityOne"
    android:theme="@newtheme"
    android:exported="true"
    android:screenOrientation="portrait"
    tools:replace="android:theme,android:exported">

Resultado del manifiesto combinado:

<activity android:name="com.example.ActivityOne"
    android:theme="@newtheme"
    android:exported="true"
    android:screenOrientation="portrait"
    android:windowSoftInputMode="stateUnchanged">
tools:strict="attr, ..."
Genera una falla de compilación cada vez que estos atributos del manifiesto de menor prioridad no coinciden exactamente con los atributos del manifiesto de mayor prioridad. Este es el comportamiento predeterminado de todos los atributos, a excepción de los que tienen comportamientos especiales, como se describe en Heurística de conflictos de combinación.

Manifiesto de prioridad baja:

<activity android:name="com.example.ActivityOne"
    android:screenOrientation="landscape">
</activity>

Manifiesto de prioridad alta:

<activity android:name="com.example.ActivityOne"
    android:screenOrientation="portrait"
    tools:strict="android:screenOrientation">
</activity>

De esta manera, se crea un error de combinación de manifiestos. Para resolver este conflicto, debes aplicar otros marcadores de reglas de combinación. Este es el comportamiento predeterminado, por lo que se produce el mismo resultado cuando se agrega tools:strict="screenOrientation" de forma explícita.

También puedes aplicar varios marcadores a un elemento, como se muestra en el siguiente ejemplo:

Manifiesto de prioridad baja:

<activity android:name="com.example.ActivityOne"
    android:theme="@oldtheme"
    android:exported="false"
    android:allowTaskReparenting="true"
    android:windowSoftInputMode="stateUnchanged">

Manifiesto de prioridad alta:

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

Resultado del manifiesto combinado:

<activity android:name="com.example.ActivityOne"
    android:theme="@newtheme"
    android:exported="true"
    android:allowTaskReparenting="true"
    android:screenOrientation="portrait">

Selector de marcadores

Si deseas aplicar los marcadores de reglas de combinación únicamente a una biblioteca importada específica, agrega el atributo tools:selector con el nombre del paquete de la biblioteca.

Por ejemplo, con el siguiente manifiesto, solo se aplica la regla de combinación remove cuando el archivo de manifiesto de menor prioridad pertenece a la biblioteca com.example.lib1:

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

Si el manifiesto de menor prioridad pertenece a otra fuente, se ignora la regla de combinación remove.

Nota: Si usas este procedimiento con uno de los marcadores de atributos, este se aplicará a todos los atributos especificados en el marcador.

Cómo anular <uses-sdk> para las bibliotecas importadas

De forma predeterminada, si importas una biblioteca con un valor de minSdk superior al del archivo de manifiesto principal, se produce un error y no es posible importar la biblioteca.

Para que la herramienta de combinación ignore este conflicto, importe la biblioteca y, al mismo tiempo, mantenga el valor de minSdk inferior de la app, agrega el atributo overrideLibrary a la etiqueta <uses-sdk>. El valor del atributo puede ser uno o más nombres de paquetes de bibliotecas (separados por comas), que indiquen las bibliotecas que pueden anular el valor minSdk del manifiesto principal.

Por ejemplo, si el manifiesto principal de la app aplica overrideLibrary como se indica a continuación:

<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"/>
...

El siguiente manifiesto se puede combinar sin errores relacionados con la etiqueta <uses-sdk> y el manifiesto combinado mantiene el valor minSdk="2" del manifiesto de la app.

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
          package="com.example.lib1">
   <uses-sdk android:minSdk="4" />
...

Permisos del sistema implícitos

Algunas APIs de Android que solían ser de libre acceso por medio de las apps ahora están restringidas por permisos del sistema en versiones recientes de Android.

Para evitar daños en las apps que esperan acceso a estas APIs, las versiones recientes de Android permiten que las apps continúen accediendo a estas APIs sin permiso si targetSdkVersion se estableció en un valor inferior al de la versión en la que se agregó la restricción. Este comportamiento otorga a la app un permiso implícito para acceder a las APIs. Los manifiestos combinados que tienen valores diferentes de targetSdkVersion pueden verse afectados.

Si el archivo de manifiesto de menor prioridad tiene un valor de targetSdkVersion inferior que le otorga un permiso implícito, y el manifiesto de mayor prioridad no tiene el mismo permiso implícito (porque su targetSdkVersion es igual o mayor que el de la versión en la que se agregó la restricción), la herramienta de combinación agrega de manera explícita el permiso del sistema al manifiesto combinado.

Por ejemplo, si la app establece targetSdkVersion en 4 o un valor superior e importa una biblioteca con targetSdkVersion establecido en 3 o en un valor inferior, la herramienta de combinación agrega el permiso WRITE_EXTERNAL_STORAGE al manifiesto combinado.

En la tabla 2, se enumeran todos los posibles permisos que se pueden agregar al manifiesto combinado:

Tabla 2: Lista de permisos que la herramienta de combinación puede agregar al manifiesto combinado

El manifiesto de menor prioridad declara Permisos agregados al manifiesto fusionado
targetSdkVersion es 3 o menor WRITE_EXTERNAL_STORAGE, READ_PHONE_STATE
targetSdkVersion es 15 o menor y usa READ_CONTACTS READ_CALL_LOG
targetSdkVersion es 15 o menor y usa WRITE_CONTACTS WRITE_CALL_LOG

Cómo inspeccionar el manifiesto combinado y buscar conflictos

Incluso antes de compilar la app, puedes obtener una vista previa del manifiesto combinado. Para obtener una vista previa, haz lo siguiente:

  1. En Android Studio, abre el archivo AndroidManifest.xml.
  2. Haz clic en la pestaña Manifiesto combinado que está en la parte inferior del editor.

En la vista Manifiesto combinado, se muestran los resultados del manifiesto combinado en la parte izquierda y se incluye información sobre cada manifiesto combinado a la derecha, como se observa en la figura 2.

Los elementos combinados a partir de archivos de manifiesto de menor prioridad se destacan en diferentes colores a la izquierda. El significado de cada color se especifica en Fuentes del manifiesto.

Figura 2: Vista Manifiesto combinado

Los archivos de manifiesto que formaron parte de la compilación, pero que no aportaron elementos ni atributos se detallan en Otros archivos de manifiesto.

Para ver información sobre el origen de un elemento, haz clic sobre él en el panel izquierdo. Los detalles aparecerán en Registro de combinación.

Si se produce algún conflicto, este aparecerá en Errores de combinación, con una recomendación sobre cómo resolver el conflicto usando marcadores de reglas de combinación.

También se incluyen errores impresos en la ventana Registro de eventos. Para verlos, selecciona Ver > Ventanas de herramientas > Registro de eventos.

Para ver un registro completo del árbol de decisiones de combinación, puedes encontrar el archivo de registro en el directorio build/outputs/logs/ de tu módulo, denominado manifest-merger-buildVariant-report.txt.

Políticas de combinación

La herramienta de combinación de manifiestos puede unir de manera lógica cada elemento XML de un archivo de manifiesto con un elemento coincidente de otro archivo. La combinación une cada elemento a través de una clave de coincidencia, que puede ser un valor de atributo único (como android:name) o la exclusividad natural de la propia etiqueta (por ejemplo, puede haber un solo elemento <supports-screen>).

Si los dos manifiestos tienen el mismo elemento XML, la herramienta los combina con una de las tres políticas de combinación:

Combinar
Combina todos los atributos sin conflictos en la misma etiqueta, y los elementos secundarios según sus respectivas políticas de combinación. Si alguno de los atributos tiene un conflicto con otro, los combina con los marcadores de reglas de combinación.
Combinar solo elementos secundarios
No combina ni fusiona los atributos (mantiene únicamente los atributos provistos por el archivo de manifiesto de mayor prioridad), y combina los elementos secundarios según sus políticas de combinación.
Conservar
Deja el elemento como se encuentra y lo agrega al elemento superior común en el archivo combinado. Esta opción solo se usa cuando es aceptable que haya diferentes declaraciones del mismo elemento.

En la tabla 3, se enumera cada tipo de elemento, el tipo de política de combinación empleado y la clave usada para determinar la coincidencia de elementos entre dos manifiestos.

Tabla 3: Claves de coincidencia y políticas de combinación de elementos de manifiesto

Elemento Política de combinación Clave de coincidencia
<action> Combinar Atributo android:name
<activity> Combinar Atributo android:name
<application> Combinar Solo hay uno por <manifest>
<category> Combinar Atributo android:name
<data> Combinar Solo hay una por <intent-filter>.
<grant-uri-permission> Combinar Solo hay uno por <provider>
<instrumentation> Combinar Atributo android:name
<intent-filter> Conservar Sin coincidencia; se permiten varias declaraciones dentro del elemento superior.
<manifest> Combinar solo elementos secundarios Solo hay uno por archivo.
<meta-data> Combinar Atributo android:name
<path-permission> Combinar Solo hay uno por <provider>
<permission-group> Combinar Atributo android:name
<permission> Combinar Atributo android:name
<permission-tree> Combinar Atributo android:name
<provider> Combinar Atributo android:name
<receiver> Combinar Atributo android:name
<screen> Combinar Atributo android:screenSize
<service> Combinar Atributo android:name
<supports-gl-texture> Combinar Atributo android:name
<supports-screen> Combinar Solo hay uno por <manifest>
<uses-configuration> Combinar Solo hay uno por <manifest>
<uses-feature> Combinar Atributo android:name (si no está presente, entonces el atributo android:glEsVersion)
<uses-library> Combinar Atributo android:name
<uses-permission> Combinar Atributo android:name
<uses-sdk> Combinar Solo hay uno por <manifest>
Elementos personalizados Combinar Sin coincidencia; la herramienta de combinación no los reconoce y siempre se incluyen en el manifiesto combinado.

Cómo insertar variables de compilación en el manifiesto

Si necesitas insertar variables en el archivo AndroidManifest.xml que estén definidas en el archivo build.gradle, puedes hacerlo con la propiedad manifestPlaceholders. Esta propiedad toma una asignación de pares clave-valor, como se muestra a continuación:

Groovy

android {
    defaultConfig {
        manifestPlaceholders = [hostName:"www.example.com"]
    }
    ...
}

Kotlin

android {
    defaultConfig {
        manifestPlaceholders["hostName"] = "www.example.com"
    }
    ...
}

Luego, puedes insertar uno de los marcadores de posición en el archivo de manifiesto como un valor del atributo:

<intent-filter ... >
    <data android:scheme="https" android:host="${hostName}" ... />
    ...
</intent-filter>

De forma predeterminada, las herramientas de compilación también proporcionan el ID de aplicación de la app en el marcador de posición ${applicationId}. El valor siempre coincide con el ID de aplicación final de la compilación actual, incluidas las modificaciones que realizan las variantes de compilación, lo que resulta útil cuando quieres usar un espacio de nombres único para los identificadores como una acción de intent, incluso entre tus variantes de compilación.

Por ejemplo, si tu archivo build.gradle tiene el siguiente aspecto:

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

Entonces, podrás insertar el ID de aplicación en tu manifiesto de la siguiente manera:

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

Y el resultado del manifiesto una vez que compilaste la variante de producto "gratuita" será el siguiente:

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

Para obtener más información, lee Cómo configurar el ID de aplicación.