Cómo cambiar el valor de los recursos de una app durante el tiempo de ejecución

Una superposición de recursos en tiempo 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 el sistema puede cambiar su comportamiento según el valor de un recurso. En lugar de el valor del recurso en el momento de la compilación, una RRO instalada en un puede cambiar los valores de los recursos de la app durante el tiempo de ejecución.

Las RRO se pueden habilitar o inhabilitar. Puedes configurar de forma programática la Habilita o inhabilita el estado para activar o desactivar la capacidad de una RRO de cambiar los valores de los recursos. RRO están inhabilitadas de forma predeterminada (sin embargo, las RRO estáticas están habilitadas por predeterminada).

Superposición de recursos

Las superposiciones funcionan mediante la asignación de recursos definidos en el paquete de superposiciones a los recursos. definidos en el paquete de destino. Cuando una app intenta resolver el valor de una en el paquete de destino, el valor del recurso de superposición al que se a la que se asigna el recurso.

Cómo configurar el manifiesto

Un paquete se considera un paquete 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 la RRO pretende superponer.

  • El valor del atributo opcional android:targetName especifica el nombre de el subconjunto de recursos superpuestos del paquete de destino que la RRO pretende superposición. Si el destino no define un conjunto de recursos que se puede superponer, este el atributo no debe estar presente.

En el siguiente código, se muestra un ejemplo de superposición 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:targetName="OverlayableResources"/>
</manifest>

Las superposiciones no pueden superponer el código, por lo que no pueden tener archivos DEX. Además, el Atributo android:hasCode de <application> etiqueta en el manifiesto deben ser se define en false.

Define el mapa de recursos

En Android 11 o versiones posteriores, el mecanismo recomendado para Definir el mapa de recursos de superposición es crear un archivo en el res/xml. del paquete de superposición, enumera los recursos de destino que deben y sus valores de reemplazo, establece el valor del Atributo android:resourcesMap de la etiqueta de manifiesto <overlay> para una referencia al archivo de asignación de recursos.

En el siguiente código, se muestra un archivo res/xml/overlays.xml de ejemplo.

<?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 o versiones posteriores admiten una regla de compilación de Soong para superposiciones que evitan que Android Asset Packaging Tool 2 (AAPT2) intente hacer lo siguiente: anular la duplicación de configuraciones de recursos con el mismo valor (--no-resource-deduping) y de quitar recursos sin configuración predeterminada parámetros de configuración (--no-resource-removal). El siguiente código muestra un ejemplo Archivo Android.bp.

runtime_resource_overlay {
    name: "ExampleOverlay",
    sdk_version: "current",
}

Resolver recursos

Si un recurso de destino o de superposición tiene múltiples configuraciones definidas para recurso que se consulta, el entorno de ejecución de recursos devuelve el valor del configuración que mejor se adapte a la configuración del dispositivo. Para determinar cuál es la configuración que mejor coincide, combina los de las configuraciones de recursos de superposición en el conjunto de recursos de destino de red y seguir el flujo regular de resolución de recursos (para consulta Cómo Android encuentra la mejor coincidencia recurso).

Por ejemplo, si una superposición define un valor para la configuración drawable-en. y el objetivo define un valor para drawable-en-port, drawable-en-port tiene una mejor coincidencia por lo que el valor de la configuración de destino drawable-en-port se elige durante el tiempo de ejecución. Para superponer todas las configuraciones de drawable-en, la superposición se 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 diferentes comportamientos entre Versiones de Android

  • En Android 11 o versiones posteriores, cada superposición tiene su propia un espacio de ID de recurso reservado que no se superponga con el espacio de ID de recurso de destino otros espacios de ID de recursos de superposición, por lo que las superposiciones hacen referencia a sus propios recursos. funcionen como se espera.

  • En Android 10 o versiones anteriores, las superposiciones y los paquetes de destino comparten el mismo recurso. espacio de ID, lo que puede provocar colisiones y comportamientos inesperados cuando intentan para hacer referencia a sus propios recursos mediante la sintaxis @type/name.

Cómo habilitar o inhabilitar superposiciones

Usa la API de OverlayManager para habilitar o inhabilitar las superposiciones mutables (recuperar la interfaz de la API con Context#getSystemService(Context.OVERLAY_SERVICE)). Los solo puede habilitarse por medio del paquete al que se orienta o de un paquete con el el permiso android.permission.CHANGE_OVERLAY_PACKAGES. Cuando una superposición es habilitado o inhabilitado, los eventos de cambio de la configuración se propagan al paquete de destino y las actividades objetivo.

Cómo restringir recursos superpuestos

En Android 10 o versiones posteriores, la etiqueta XML <overlayable> expone un conjunto de recursos. que las RRO pueden superponerse. En el siguiente ejemplo, res/values/overlayable.xml archivo, string/foo y integer/bar son recursos se usan para aplicar temas a la apariencia del dispositivo; para superponer estos recursos, una superposición debe dirigirse explícitamente a la colección de recursos superpuestos por su 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:

  • Se permite que dos paquetes diferentes definan <overlayable name="foo">.

  • No es correcto que un solo APK tenga dos bloques <overlayable name="foo">.

En el siguiente código, se muestra un ejemplo de una superposición en 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>, se superpone la segmentación con esa app:

  • Se debe especificar targetName.

  • Solo se pueden superponer los recursos enumerados en la etiqueta <overlayable>.

  • Se puede orientar solo a un nombre de <overlayable>.

No se puede habilitar una superposición orientada a un paquete que expone recurso, pero no usa android:targetName para orientarse a un Etiqueta <overlayable>.

Restringe políticas

Usa la etiqueta <policy> para aplicar restricciones en los recursos superpuestos. El El atributo type especifica qué políticas debe cumplir una superposición para anularla. 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 de producto puede anular los recursos.
  • oem Cualquier superposición en la partición 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 anulan los recursos.
  • actor Cualquier superposición firmada con la misma firma que el APK de actor puede anulan los recursos. En el sistema, el actor se declara en la etiqueta names-actor. config.
  • config_signature Cualquier superposición firmada con la misma firma que el El APK overlay-config puede anular los recursos. El parámetro de configuración de superposición declarada en la etiqueta overlay-config-signature en la configuración del sistema.

En el siguiente código, se muestra una etiqueta <policy> de ejemplo 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 debe cumplir solo una política para anular los recursos enumerados en la etiqueta <policy>.

Cómo configurar superposiciones

Android admite diferentes mecanismos para configurar la mutabilidad, valores predeterminados el estado y la prioridad de las superposiciones según la versión de actualización de Android.

  • Los dispositivos que ejecutan Android 11 o versiones posteriores pueden usar un OverlayConfig (config.xml) en lugar de los atributos del manifiesto. Con un el método recomendado para las superposiciones.

  • Todos los dispositivos pueden usar atributos de manifiesto (android:isStatic y android:priority) para configurar RRO estáticas.

Usa OverlayConfig

En Android 11 o versiones posteriores, puedes usar OverlayConfig para configurar la mutabilidad, el estado predeterminado y la prioridad de las superposiciones. Para configurar una superposición, crear o modificar el archivo ubicado en partition/overlay/config/config.xml, donde partition es la partición de la que se configurará. Para configurarse, una superposición debe encontrarse en el Directorio overlay/ de la partición en la que se configura la superposición El El siguiente código muestra un product/overlay/config/config.xml de ejemplo.

<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é superposición se está configurando. El atributo opcional enabled controla si o no, la superposición estará habilitada de forma predeterminada (el valor predeterminado es false). La fase opcional El atributo mutable controla si la superposición es mutable y puede tener su estado habilitado cambió de manera programática durante el tiempo de ejecución (el valor predeterminado es true). Las superposiciones que no se incluyen en un archivo de configuración son mutables y las inhabilitan de forma predeterminada.

Prioridad de la superposición

Cuando varias superposiciones anulan los mismos recursos, el orden de las superposiciones es el siguiente: importante. Una superposición tiene mayor precedencia que las que tienen configuraciones antes de su propia configuración. El orden de prioridad de las superposiciones en diferentes particiones (de menor a mayor precedencia) es la siguiente.

  • system
  • vendor
  • odm
  • oem
  • product
  • system_ext

Combinar archivos

El uso de etiquetas <merge> permite combinar otros archivos de configuración en el la posición especificada en el archivo de configuración. El atributo path de la etiqueta representa la ruta del archivo que se va a fusionar en relación con el directorio que contiene archivos de configuración de superposición.

Usar atributos de manifiesto o RRO estáticas

En Android 10 o versiones anteriores, la inmutabilidad y la prioridad de las superposiciones se configuran usando los siguientes atributos del manifiesto.

  • android:isStatic Cuando el valor de este atributo booleano se establece en true, La superposición está habilitada de forma predeterminada y es inmutable, lo que evita que de inhabilitarse.

  • android:priority El valor de este atributo numérico (que solo afecta superposiciones estáticas) configura la precedencia de la superposición cuando se activan varias las superposiciones se orientan al mismo valor de recurso. Un número más alto indica un mayor prioridad.

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 se ubicados en partition/overlay/config/config.xml, las superposiciones se configuran usando ese archivo, y android:isStatic y android:priority no tienen efecto en superposiciones ubicadas en la partición. Definir un archivo de configuración de superposición en cualquier partición aplica la prioridad de partición de superposición.

Además, en Android 11 o versiones posteriores, se quita la capacidad usar superposiciones estáticas para afectar los valores de los recursos leídos durante el paquete instalación. En el caso de uso común de usar superposiciones estáticas para cambiar la de valores booleanos que configuran el estado habilitado del componente, usa el <component-override> Etiqueta SystemConfig (nueva en Android) 11).

Superposiciones de depuración

Para habilitar, inhabilitar y volcar las superposiciones de forma manual, utiliza la siguiente superposición de shell de administrador.

adb shell cmd overlay

OverlayManagerService usa idmap2 para asignar IDs de recursos en el destino. como IDs de recursos en el paquete de superposición. Las asignaciones de ID generadas almacenado en /data/resource-cache/. Si la superposición no funciona correctamente, busca el archivo idmap correspondiente para tu superposición 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