Modifier la valeur des ressources d'une application au moment de l'exécution

Une superposition de ressource d'exécution (RRO) est un package qui modifie les valeurs des ressources d'un package cible lors de l'exécution. Par exemple, une application installée sur le système peut changer son comportement en fonction de la valeur d'une ressource. Plutôt que coder en dur la valeur de la ressource au moment de la compilation, un RRO installé sur une autre peut modifier les valeurs des ressources de l'application au moment de l'exécution.

Les RRO peuvent être activées ou désactivées. Vous pouvez définir le paramètre activer/désactiver l'état pour activer/désactiver la capacité d'une RRO à modifier les valeurs des ressources. RRO sont désactivés par défaut (les ROR statiques sont toutefois activés par défaut).

Ressources en superposition

Les superpositions fonctionnent en mappant les ressources définies dans le package de superposition aux ressources défini dans le package cible. Lorsqu'une application tente de résoudre la valeur d'un ressource dans le package cible, la valeur de la ressource de superposition que la cible sur laquelle la ressource est mappée est renvoyé.

Configurer le fichier manifeste

Un package est considéré comme un package RRO s'il contient une balise <overlay> en tant que enfant de la balise <manifest>.

  • La valeur de l'attribut android:targetPackage obligatoire indique le nom du package que la RRO a l'intention de superposer.

  • La valeur de l'attribut facultatif android:targetName indique le nom sous-ensemble superposable de ressources du package cible que la RRO prévoit superposition. Si la cible ne définit pas d'ensemble de ressources superposable, ne doit pas être présent.

Le code suivant montre un exemple de superposition 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>

Les superpositions ne peuvent pas superposer de code. Elles ne peuvent donc pas comporter de fichiers DEX. En outre, Attribut android:hasCode de <application> dans le fichier manifeste doit être définie sur false.

Définir le mappage des ressources

Dans Android 11 ou version ultérieure, le mécanisme recommandé pour définir la carte des ressources de superposition consiste à créer un fichier dans res/xml du package de superposition, énumérez les ressources cibles qui doivent être et leurs valeurs de remplacement, puis définissez la valeur du paramètre Attribut android:resourcesMap de la balise <overlay> du fichier manifeste vers une référence au fichier de mappage de ressources.

Le code suivant montre un exemple de fichier 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>

Le code suivant montre un exemple de fichier manifeste en superposition.

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

Créer le package

Android 11 ou version ultérieure est compatible avec une règle de compilation Soong pour qui empêchent Android Asset Packaging Tool 2 (AAPT2) d'essayer dédupliquer les configurations de ressources ayant la même valeur (--no-resource-deduping) et de supprimer des ressources sans valeur par défaut (--no-resource-removal). Le code suivant montre un exemple Android.bp.

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

Résoudre les ressources

Si plusieurs configurations sont définies pour une ressource cible ou une ressource de superposition ressource interrogée, l'environnement d'exécution des ressources renvoie la valeur configuration qui correspond le mieux à celle de la configuration de l'appareil. Pour déterminer la configuration qui correspond le mieux, fusionnez les l'ensemble des configurations de ressources superposées dans l'ensemble de ressources cibles de configuration, puis suivez le flux standard de résolution des ressources pour en savoir plus, consultez Comment Android détermine-t-il ressource).

Par exemple, si une superposition définit une valeur pour la configuration drawable-en et la cible définit une valeur pour drawable-en-port, drawable-en-port a une meilleure correspondance. Par conséquent, la valeur de la configuration cible drawable-en-port est choisi au moment de l'exécution. Pour superposer toutes les configurations drawable-en, la superposition doit définir une valeur pour chaque configuration drawable-en définie par la cible.

Les superpositions peuvent référencer leurs propres ressources, avec des comportements différents entre Versions d'Android.

  • Sur Android 11 ou version ultérieure, chaque superposition a sa propre un espace d'ID de ressource réservé qui ne chevauche pas l'espace d'ID de ressource cible ou d'autres espaces d'ID de ressource de superposition, de sorte que les superpositions référençant leurs propres ressources fonctionnent comme prévu.

  • Sous Android 10 ou version antérieure, les superpositions et les packages cibles partagent la même ressource l'espace d'identification, ce qui peut provoquer des collisions et un comportement inattendu lors des tentatives de référencer leurs propres ressources à l'aide de la syntaxe @type/name.

Activer/Désactiver les superpositions

Utilisez l'API OverlayManager pour activer et désactiver les superpositions modifiables (récupérer l'interface API à l'aide de Context#getSystemService(Context.OVERLAY_SERVICE)). Une la superposition ne peut être activée que par le package ciblé ou par un package avec Autorisation android.permission.CHANGE_OVERLAY_PACKAGES. Lorsqu'une superposition est activé ou désactivé, les événements de modification de configuration se propagent au package cible. et les activités cibles sont relancées.

Limiter les ressources superposables

Sous Android 10 ou version ultérieure, la balise XML <overlayable> expose un ensemble de ressources que les RRO peuvent superposer. Dans l'exemple suivant, res/values/overlayable.xml fichier, string/foo et integer/bar sont des ressources utilisé pour thématiser l'apparence de l'appareil ; pour superposer ces ressources, une superposition doit cibler explicitement la collection de ressources superposables par son nom.

<!-- 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 peut définir plusieurs balises <overlayable>, mais chaque balise doit avoir une valeur unique dans le package. Par exemple:

  • Il est possible que deux packages différents définissent tous les deux <overlayable name="foo">.

  • Il n'est pas possible qu'un seul APK contienne deux blocs <overlayable name="foo">.

Le code suivant montre un exemple de superposition dans 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>

Lorsqu'une application définit une balise <overlayable>, les superpositions ciblant cette application:

  • Vous devez spécifier targetName.

  • Seules les ressources répertoriées dans la balise <overlayable> peuvent se superposer.

  • Vous ne pouvez cibler qu'un seul nom <overlayable>.

Vous ne pouvez pas activer une superposition ciblant un package qui expose des superpositions mais n'utilise pas android:targetName pour cibler Balise <overlayable>.

Limiter les règles

Utilisez le tag <policy> pour appliquer des restrictions sur les ressources superposables. La L'attribut type indique les règles qu'une superposition doit respecter pour être ignorée. les ressources incluses. Les types compatibles sont les suivants.

  • public Toute superposition peut remplacer la ressource.
  • system Toute superposition sur la partition système peut remplacer les ressources.
  • vendor Toute superposition sur la partition des fournisseurs peut remplacer les ressources.
  • product Toute superposition sur la partition de produits peut remplacer les ressources.
  • oem Toute superposition sur la partition Oem peut remplacer les ressources.
  • odm Toute superposition sur la partition odm peut remplacer les ressources.
  • signature Toute superposition signée avec la même signature que l'APK cible peut remplacer les ressources.
  • actor Toute superposition signée avec la même signature que l'APK actor peut remplacer les ressources. L'acteur est déclaré dans la balise names-actor du système. configuration.
  • config_signature Toute superposition signée avec la même signature que L'APK overlay-config peut remplacer les ressources. La commande superposition-config est déclaré dans la balise overlay-config-signature de la configuration système.

Le code suivant montre un exemple de balise <policy> dans 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>

Pour spécifier plusieurs règles, utilisez des barres verticales (|) comme caractères de séparation. Lorsque plusieurs règles sont spécifiées, une superposition ne doit remplir qu'une seule des conditions pour remplacer les ressources répertoriées dans le tag <policy>.

Configurer les superpositions

Android prend en charge différents mécanismes de configuration de la mutabilité, par défaut l'état et la priorité des superpositions selon la version d'Android.

  • Les appareils équipés d'Android 11 ou version ultérieure peuvent utiliser un OverlayConfig (config.xml) au lieu des attributs du fichier manifeste. À l'aide d'un est la méthode recommandée pour les superpositions.

  • Tous les appareils peuvent utiliser les attributs de fichier manifeste (android:isStatic et android:priority) pour configurer des RRO statiques.

Utiliser OverlayConfig

Sous Android 11 ou version ultérieure, vous pouvez utiliser OverlayConfig pour configurer la mutabilité, l'état par défaut et la priorité des superpositions. Pour configurer une superposition, créez ou modifiez le fichier situé partition/overlay/config/config.xml, où partition est la partition du de superposition à configurer. Pour être configurée, une superposition doit se trouver dans le Répertoire overlay/ de la partition dans laquelle la superposition est configurée. La Le code suivant montre un exemple 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 balise <overlay> nécessite un attribut package qui indique quelle superposition est en cours de configuration. L'attribut facultatif enabled permet de déterminer si ou non, la superposition est activée par défaut (false par défaut). L'option L'attribut mutable détermine si la superposition est modifiable ou non son état activé a été modifié de manière programmatique au moment de l'exécution (par défaut, true). Les superpositions qui ne sont pas répertoriées dans un fichier de configuration peuvent être modifiées et désactivées par par défaut.

Priorité des superpositions

Lorsque plusieurs superpositions remplacent les mêmes ressources, l'ordre des superpositions est importantes. Les superpositions ont une priorité plus élevée que les superpositions avec configurations. précédant sa propre configuration. L'ordre de priorité des superpositions dans les différentes (de la priorité la plus faible à la plus élevée) se présente comme suit.

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

Fusionner des fichiers

L'utilisation des balises <merge> permet de fusionner d'autres fichiers de configuration au niveau la position spécifiée dans le fichier de configuration. Attribut path de la balise représente le chemin du fichier à fusionner par rapport au répertoire contenant les fichiers de configuration de superposition.

Utiliser des attributs de fichier manifeste/des RRO statiques

Dans Android 10 ou version antérieure, l'immuabilité et la priorité des superpositions sont configurées à l'aide de les attributs de fichier manifeste suivants.

  • android:isStatic Lorsque la valeur de cet attribut booléen est définie sur true, la superposition est activée par défaut et immuable, ce qui empêche la superposition d'être désactivés.

  • android:priority La valeur de cet attribut numérique (qui affecte uniquement les superpositions statiques) configure la priorité de la superposition lorsque plusieurs les superpositions ciblent la même valeur de ressource. Plus le nombre est élevé, plus la priorité.

Le code suivant montre un exemple 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>

Modifications apportées à Android 11

Sous Android 11 ou version ultérieure, si un fichier de configuration est située dans partition/overlay/config/config.xml, les superpositions sont configurées ce fichier, ainsi que android:isStatic et android:priority n'ont aucune incidence sur superpositions situées dans la partition. Définir un fichier de configuration de superposition dans applique la priorité des partitions de superposition.

De plus, Android 11 ou version ultérieure supprime la possibilité d'utiliser des superpositions statiques pour affecter les valeurs des ressources lues l'installation. Dans le cas d'utilisation courant des superpositions statiques pour modifier des valeurs booléennes qui configurent l'état d'activation du composant, utilisez Balise SystemConfig <component-override> (nouveau sur Android) 11).

Déboguer les superpositions

Pour activer, désactiver et vider manuellement les superpositions, utilisez la superposition suivante : gestionnaire d'interface système.

adb shell cmd overlay

OverlayManagerService utilise idmap2 pour mapper les ID de ressource dans la cible. vers les ID de ressources du package de superposition. Les mappages d'ID générés sont stocké dans /data/resource-cache/. Si votre superposition ne fonctionne pas correctement, recherchez le fichier idmap correspondant à votre superposition dans /data/resource-cache/, puis exécutez la commande suivante.

adb shell idmap2 dump --idmap-path [file]

Cette commande imprime le mappage des ressources, comme indiqué ci-dessous.

[target res id] - > [overlay res id] [resource name]
0x01040151 -> 0x01050001 string/config_dozeComponent
0x01040152 -> 0x01050002 string/config_dozeDoubleTapSensorType
0x01040153 -> 0x01050003 string/config_dozeLongPressSensorType