Una superposición de recursos del entorno de ejecución (RRO) es un paquete que cambia los valores de los recursos de un paquete de destino en el entorno de ejecución. Por ejemplo, una app instalada en la imagen del sistema podría cambiar su comportamiento según el valor de un recurso. En lugar de codificar de forma rígida el valor del recurso en el momento de la compilación, un RRO instalado en una partición diferente puede cambiar los valores de los recursos de la app en el tiempo de ejecución.
Los RRO se pueden habilitar o inhabilitar. Puedes establecer de forma programática el estado de habilitación o inhabilitación para alternar la capacidad de un RRO de cambiar los valores de los recursos. Los RRos están inhabilitados de forma predeterminada (sin embargo, los RRos estáticos están habilitados de forma predeterminada).
Recursos de superposición
Las superposiciones funcionan asignando los recursos definidos en el paquete de superposición a los recursos definidos en el paquete de destino. Cuando una app intenta resolver el valor de un recurso en el paquete de destino, se devuelve el valor del recurso de superposición al que se asigna el recurso de destino.
Cómo configurar el manifiesto
Un paquete se considera un paquete de RRO si contiene una etiqueta <overlay>
como elemento secundario de la etiqueta <manifest>
.
El valor del atributo
android:targetPackage
obligatorio especifica el nombre del paquete que el RRO pretende superponer.El valor del atributo opcional
android:targetName
especifica el nombre del subconjunto de recursos superponibles del paquete de destino que el RRO pretende superponer. Si el destino no define un conjunto de recursos superponibles, este atributo no debe estar presente.
En el siguiente código, se muestra un ejemplo de AndroidManifest.xml
superpuesto.
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.overlay">
<application android:hasCode="false" />
<overlay android:targetPackage="com.example.target"
android:targetName="OverlayableResources"/>
</manifest>
Las superposiciones no pueden superponerse al código, por lo que no pueden tener archivos DEX. Además, el atributo android:hasCode
de la etiqueta <application
> en el manifiesto debe establecerse en false
.
Define el mapa de recursos
En Android 11 y versiones posteriores, el mecanismo recomendado para definir el mapa de recursos de superposición es crear un archivo en el directorio res/xml
del paquete de superposición, enumerar los recursos de destino que se deben superponer y sus valores de reemplazo, y, luego, establecer el valor del atributo android:resourcesMap
de la etiqueta de manifiesto <overlay>
en una referencia al archivo de asignación de recursos.
El siguiente código muestra un ejemplo de archivo res/xml/overlays.xml
.
<?xml version="1.0" encoding="utf-8"?>
<overlay xmlns:android="http://schemas.android.com/apk/res/android" >
<!-- Overlays string/config1 and string/config2 with the same resource. -->
<item target="string/config1" value="@string/overlay1" />
<item target="string/config2" value="@string/overlay1" />
<!-- Overlays string/config3 with the string "yes". -->
<item target="string/config3" value="@android:string/yes" />
<!-- Overlays string/config4 with the string "Hardcoded string". -->
<item target="string/config4" value="Hardcoded string" />
<!-- Overlays integer/config5 with the integer "42". -->
<item target="integer/config5" value="42" />
</overlay>
El siguiente código muestra un ejemplo de manifiesto de superposición.
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.overlay">
<application android:hasCode="false" />
<overlay android:targetPackage="com.example.target"
android:targetName="OverlayableResources"
android:resourcesMap="@xml/overlays"/>
</manifest>
Compila el paquete
Android 11 y versiones posteriores admiten una regla de compilación de Soong para las superposiciones que impide que Android Asset Packaging Tool 2 (AAPT2) intente quitar duplicados de las configuraciones de recursos con el mismo valor (--no-resource-deduping
) y que quite recursos sin configuraciones predeterminadas (--no-resource-removal
). El siguiente código muestra un ejemplo de un archivo Android.bp
.
runtime_resource_overlay {
name: "ExampleOverlay",
sdk_version: "current",
}
Resuelve recursos
Si un recurso de destino o un recurso de superposición tienen varios parámetros de configuración definidos para el recurso que se consulta, el tiempo de ejecución de los recursos devuelve el valor del parámetro de configuración que mejor coincide con la configuración del dispositivo. Para determinar qué configuración es la que mejor coincide, combina el conjunto de configuraciones de recursos de la superposición en el conjunto de configuraciones de recursos de destino y, luego, sigue el flujo de resolución de recursos normal (para obtener más detalles, consulta Cómo encuentra Android el recurso de coincidencia óptima).
Por ejemplo, si una superposición define un valor para la configuración drawable-en
y el destino define un valor para drawable-en-port
, drawable-en-port
tiene una mejor coincidencia, por lo que se elige el valor de la configuración de destino drawable-en-port
en el tiempo de ejecución. Para superponer todas las configuraciones de drawable-en
, la superposición debe definir un valor para cada configuración de drawable-en
que defina el destino.
Las superposiciones pueden hacer referencia a sus propios recursos, con comportamientos diferentes entre las versiones de Android.
En Android 11 o versiones posteriores, cada superposición tiene su propio espacio de ID de recursos reservado que no se superpone con el espacio de ID de recursos de destino ni con otros espacios de ID de recursos de superposición, por lo que las superposiciones que hacen referencia a sus propios recursos funcionan según lo esperado.
En Android 10 o versiones anteriores, los paquetes de superposición y de destino comparten el mismo espacio de ID de recursos, lo que puede provocar colisiones y un comportamiento inesperado cuando intentan hacer referencia a sus propios recursos con la sintaxis
@type/name
.
Habilitar o inhabilitar superposiciones
Las superposiciones se pueden habilitar o inhabilitar de forma manual y programática.
Cómo inhabilitar o habilitar superposiciones de forma manual
Para habilitar y verificar manualmente un RR, ejecuta el siguiente comando:
adb shell cmd overlay enable --user current com.example.carrro
adb shell cmd overlay list --user current | grep -i com.example com.example.carrro
Esto habilita el RRO para el usuario del sistema (userId = 0
) que posee SystemUI.
Esta instrucción no afecta a las apps que inicia el usuario en primer plano (userId = 10
). Para habilitar el RRO para el usuario en primer plano, usa el parámetro -–user 10
:
adb shell cmd overlay enable --user 10 com.example.carrro
Habilita o inhabilita superposiciones de forma programática
Usa la API de OverlayManager
para habilitar y, luego, inhabilitar las superposiciones mutables (recupera la interfaz de la API con Context#getSystemService(Context.OVERLAY_SERVICE)
). Una superposición solo la puede habilitar el paquete al que se dirige o un paquete con el permiso android.permission.CHANGE_OVERLAY_PACKAGES
. Cuando se habilita o inhabilita una superposición, los eventos de cambio de configuración se propagan al paquete de destino y se reinician las actividades de destino.
Restringe los recursos superponibles
En Android 10 y versiones posteriores, la etiqueta XML <overlayable>
expone un conjunto de recursos que los RRO pueden superponer. En el siguiente ejemplo de archivo res/values/overlayable.xml
, string/foo
y integer/bar
son recursos que se usan para aplicar temas a la apariencia del dispositivo. Para superponer estos recursos, una superposición debe orientarse de forma explícita a la colección de recursos superponibles por nombre.
<!-- The collection of resources for theming the appearance of the device -->
<overlayable name="ThemeResources">
<policy type="public">
<item type="string" name="foo/" />
<item type="integer" name="bar/" />
</policy>
...
</overlayable>
Un APK puede definir varias etiquetas <overlayable>
, pero cada etiqueta debe tener un nombre único dentro del paquete. Por ejemplo, es lo siguiente:
Está bien que dos paquetes diferentes definan
<overlayable name="foo">
.No es correcto que un solo APK tenga dos bloques
<overlayable name="foo">
.
El siguiente código muestra un ejemplo de una superposición en el archivo AndroidManifest.xml
.
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.my.theme.overlay">
<application android:hasCode="false" />
<!-- This overlay will override the ThemeResources resources -->
<overlay android:targetPackage="android" android:targetName="ThemeResources">
</manifest>
Cuando una app define una etiqueta <overlayable>
, las superposiciones que se segmentan para esa app hacen lo siguiente:
Se debe especificar
targetName
.Solo puede superponer los recursos que se enumeran dentro de la etiqueta
<overlayable>
.Solo se puede segmentar para un nombre de
<overlayable>
.
No puedes habilitar una superposición que se segmenta para un paquete que expone recursos superponibles, pero no usa android:targetName
para segmentar una etiqueta <overlayable>
específica.
Políticas de restricción
Usa la etiqueta <policy>
para aplicar restricciones a los recursos superponibles. El atributo type
especifica qué políticas debe cumplir una superposición para anular los recursos incluidos. Entre los tipos admitidos, se incluyen los siguientes:
public
. Cualquier superposición puede anular el recurso.system
. Cualquier superposición en la partición del sistema puede anular los recursos.vendor
. Cualquier superposición en la partición del proveedor puede anular los recursos.product
. Cualquier superposición en la partición del producto puede anular los recursos.oem
. Cualquier superposición en la partición del OEM puede anular los recursos.odm
. Cualquier superposición en la partición odm puede anular los recursos.signature
. Cualquier superposición firmada con la misma firma que el APK de destino puede anular los recursos.actor
. Cualquier superposición firmada con la misma firma que el APK del actor puede anular los recursos. El actor se declara en la etiqueta named-actor en la configuración del sistema.config_signature
. Cualquier superposición firmada con la misma firma que el APK de overlay-config puede anular los recursos. La overlay-config se declara en la etiqueta overlay-config-signature en la configuración del sistema.
El siguiente código muestra un ejemplo de etiqueta <policy>
en el archivo res/values/overlayable.xml
.
<overlayable name="ThemeResources">
<policy type="vendor" >
<item type="string" name="foo" />
</policy>
<policy type="product|signature" >
<item type="string" name="bar" />
<item type="string" name="baz" />
</policy>
</overlayable>
Para especificar varias políticas, usa barras verticales (|) como caracteres separadores.
Cuando se especifican varias políticas, una superposición solo debe cumplir con una política para anular los recursos que se enumeran dentro de la etiqueta <policy>
.
Cómo configurar superposiciones
Android admite diferentes mecanismos para configurar la mutabilidad, el estado predeterminado y la prioridad de las superposiciones según la versión de Android.
Los dispositivos que ejecutan Android 11 o versiones posteriores pueden usar un archivo
OverlayConfig
(config.xml
) en lugar de atributos de manifiesto. Se recomienda usar un archivo de superposición.Todos los dispositivos pueden usar atributos de manifiesto (
android:isStatic
yandroid:priority
) para configurar RRO estáticos.
Usa OverlayConfig
En Android 11 y versiones posteriores, puedes usar OverlayConfig
para configurar la mutabilidad, el estado predeterminado y la prioridad de las superposiciones. Para configurar una superposición, crea o modifica el archivo ubicado en partition/overlay/config/config.xml
, donde partition
es la partición de la superposición que se configurará. Para configurarse, una superposición debe residir en el directorio overlay/
de la partición en la que se configura la superposición. El siguiente código muestra un ejemplo de product/overlay/config/config.xml
.
<config>
<merge path="OEM-common-rros-config.xml" />
<overlay package="com.oem.overlay.device" mutable="false" enabled="true" />
<overlay package="com.oem.green.theme" enabled="true" />
</config>"
La etiqueta <overlay>
requiere un atributo package
que indique qué paquete de superposición se está configurando. El atributo opcional enabled
controla si la superposición está habilitada de forma predeterminada (el valor predeterminado es false
). El atributo opcional mutable
controla si la superposición es mutable y si su estado habilitado se puede cambiar de forma programática en el tiempo de ejecución (el valor predeterminado es true
). Las superposiciones que no se enumeran en un archivo de configuración son mutables y están inhabilitadas de forma predeterminada.
Prioridad de superposición
Cuando varias superposiciones anulan los mismos recursos, el orden de las superposiciones es importante. Una superposición tiene mayor precedencia que las superposiciones con configuraciones anteriores a la suya. El orden de precedencia de las superposiciones en diferentes particiones (de menor a mayor precedencia) es el siguiente.
system
vendor
odm
oem
product
system_ext
Cómo combinar archivos
El uso de etiquetas <merge>
permite que otros archivos de configuración se combinen en la posición especificada en el archivo de configuración. El atributo path
de la etiqueta representa la ruta de acceso del archivo que se combinará en relación con el directorio que contiene los archivos de configuración de la superposición.
Usa atributos de manifiesto o RRO estáticos
En Android 10 y versiones anteriores, la inmutabilidad y la precedencia de las superposiciones se configuran con los siguientes atributos del manifiesto.
android:isStatic
. Cuando el valor de este atributo booleano se establece entrue
, la superposición se habilita de forma predeterminada y es inmutable, lo que impide que se inhabilite.android:priority
. El valor de este atributo numérico (que solo afecta las superposiciones estáticas) configura la prioridad de la superposición cuando varias superposiciones estáticas segmentan el mismo valor de recurso. Un número más alto indica una mayor precedencia.
En el siguiente código, se muestra un ejemplo de AndroidManifest.xml
.
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.overlay">
<application android:hasCode="false" />
<overlay android:targetPackage="com.example.target"
android:isStatic="true"
android:priority="5"/>
</manifest>
Cambios en Android 11
En Android 11 o versiones posteriores, si un archivo de configuración se encuentra en partition/overlay/config/config.xml
, las superposiciones se configuran con ese archivo, y android:isStatic
y android:priority
no tienen efecto en las superposiciones ubicadas en la partición. Definir un archivo de configuración de superposición en cualquier partición exige la precedencia de la partición de superposición.
Además, Android 11 o versiones posteriores quitan la capacidad de usar superposiciones estáticas para afectar los valores de los recursos que se leen durante la instalación de paquetes. Para el caso de uso común de usar superposiciones estáticas para cambiar el valor de los booleanos que configuran el estado habilitado del componente, usa la etiqueta <component-override>
SystemConfig
(nueva en Android 11).
Superposiciones de depuración
Para habilitar, inhabilitar y volcar superposiciones de forma manual, usa el siguiente comando de shell del administrador de superposiciones.
adb shell cmd overlay
Usar enable
sin especificar un usuario afecta al usuario actual, es decir, al usuario del sistema (userId = 0
) que posee la IU del sistema. Esto no afecta al usuario en primer plano (userId = 10
), que es propietario de las apps. Para habilitar la RRO para el usuario en primer plano, usa el parámetro –-user 10
:
adb shell cmd overlay enable --user 10 com.example.carrro
OverlayManagerService
usa idmap2
para asignar los IDs de recursos en el paquete de destino a los IDs de recursos en el paquete de superposición. Las asignaciones de ID generadas se almacenan en /data/resource-cache/
. Si la superposición no funciona correctamente, busca el archivo idmap
correspondiente en /data/resource-cache/
y, luego, ejecuta el siguiente comando.
adb shell idmap2 dump --idmap-path [file]
Este comando imprime la asignación de recursos, como se muestra a continuación.
[target res id] - > [overlay res id] [resource name]
0x01040151 -> 0x01050001 string/config_dozeComponent
0x01040152 -> 0x01050002 string/config_dozeDoubleTapSensorType
0x01040153 -> 0x01050003 string/config_dozeLongPressSensorType