Ändern Sie den Wert der Ressourcen einer App zur Laufzeit

Ein Runtime Resource Overlay (RRO) ist ein Paket, das die Ressourcenwerte eines Zielpakets zur Laufzeit ändert. Beispielsweise könnte eine auf dem Systemabbild installierte App ihr Verhalten basierend auf dem Wert einer Ressource ändern. Anstatt den Ressourcenwert zur Erstellungszeit fest zu codieren, kann ein auf einer anderen Partition installiertes RRO die Werte der Ressourcen der App zur Laufzeit ändern.

RROs können aktiviert oder deaktiviert werden. Sie können den Aktivierungs-/Deaktivierungsstatus programmgesteuert festlegen, um die Fähigkeit eines RRO zum Ändern von Ressourcenwerten umzuschalten. RROs sind standardmäßig deaktiviert ( statische RROs sind jedoch standardmäßig aktiviert).

Overlay-Ressourcen

Overlays funktionieren, indem sie im Overlay-Paket definierte Ressourcen den im Zielpaket definierten Ressourcen zuordnen. Wenn eine App versucht, den Wert einer Ressource im Zielpaket aufzulösen, wird stattdessen der Wert der Overlay-Ressource zurückgegeben, der die Zielressource zugeordnet ist.

Richten Sie das Manifest ein

Ein Paket gilt als RRO-Paket, wenn es ein <overlay> -Tag als untergeordnetes Element des <manifest> -Tags enthält.

  • Der Wert des erforderlichen Attributs android:targetPackage gibt den Namen des Pakets an, das die RRO überlagern möchte.

  • Der Wert des optionalen Attributs android:targetName gibt den Namen der überlagerbaren Teilmenge der Ressourcen des Zielpakets an, das der RRO überlagern möchte. Wenn das Ziel keinen überlagerbaren Ressourcensatz definiert, sollte dieses Attribut nicht vorhanden sein.

Der folgende Code zeigt ein Beispiel-Overlay 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>

Overlays können keinen Code überlagern und daher keine DEX-Dateien enthalten. Darüber hinaus muss das Attribut android:hasCode des Tags <application > im Manifest auf false gesetzt werden.

Definieren Sie die Ressourcenkarte

In Android 11 oder höher besteht der empfohlene Mechanismus zum Definieren der Overlay-Ressourcenzuordnung darin, eine Datei im Verzeichnis res/xml des Overlay-Pakets zu erstellen, die Zielressourcen, die überlagert werden sollen, und ihre Ersatzwerte aufzuzählen und dann den Wert festzulegen android:resourcesMap Attribut des <overlay> -Manifest-Tags auf einen Verweis auf die Ressourcenzuordnungsdatei.

Der folgende Code zeigt eine Beispieldatei 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>

Der folgende Code zeigt ein Beispiel für ein Overlay-Manifest.

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

Erstellen Sie das Paket

Android 11 oder höher unterstützt eine Soong-Build-Regel für Overlays, die verhindert, dass Android Asset Packaging Tool 2 (AAPT2) versucht, Konfigurationen von Ressourcen mit demselben Wert zu deduplizieren ( --no-resource-deduping ) und Ressourcen ohne Standardkonfigurationen entfernt ( --no-resource-removal ). Der folgende Code zeigt eine Beispiel Android.bp Datei.

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

Ressourcen auflösen

Wenn für eine Zielressource oder Overlay-Ressource mehrere Konfigurationen für die abgefragte Ressource definiert sind, gibt die Ressourcenlaufzeit den Wert der Konfiguration zurück, der am besten mit der Konfiguration der Gerätekonfiguration übereinstimmt. Um zu ermitteln, welche Konfiguration die am besten passende Konfiguration ist, führen Sie den Satz der Overlay-Ressourcenkonfigurationen mit dem Satz der Zielressourcenkonfigurationen zusammen und folgen Sie dann dem regulären Ressourcenauflösungsablauf (Einzelheiten finden Sie unter So findet Android die am besten passende Ressource ).

Wenn beispielsweise ein Overlay einen Wert für die Konfiguration drawable-en definiert und das Ziel einen Wert für drawable-en-port definiert, hat drawable-en-port eine bessere Übereinstimmung, sodass der Wert der Zielkonfiguration drawable-en-port lautet zur Laufzeit ausgewählt. Um alle drawable-en Konfigurationen zu überlagern, muss die Überlagerung einen Wert für jede drawable-en Konfiguration definieren, die das Ziel definiert.

Overlays können auf ihre eigenen Ressourcen verweisen, wobei sich das Verhalten zwischen Android-Versionen unterscheidet.

  • In Android 11 oder höher verfügt jedes Overlay über einen eigenen reservierten Ressourcen-ID-Bereich, der sich nicht mit dem Zielressourcen-ID-Bereich oder anderen Overlay-Ressourcen-ID-Bereichen überschneidet, sodass Overlays, die auf ihre eigenen Ressourcen verweisen, wie erwartet funktionieren.

  • In Android 10 oder niedriger nutzen Overlays und Zielpakete denselben Ressourcen-ID-Bereich, was zu Kollisionen und unerwartetem Verhalten führen kann, wenn sie versuchen, mithilfe der @type/name Syntax auf ihre eigenen Ressourcen zu verweisen.

Overlays aktivieren/deaktivieren

Verwenden Sie die OverlayManager API, um veränderbare Overlays zu aktivieren und zu deaktivieren (rufen Sie die API-Schnittstelle mit Context#getSystemService(Context.OVERLAY_SERVICE) ab). Ein Overlay kann nur durch das Paket, auf das es abzielt, oder durch ein Paket mit der Berechtigung android.permission.CHANGE_OVERLAY_PACKAGES aktiviert werden. Wenn ein Overlay aktiviert oder deaktiviert wird, werden Konfigurationsänderungsereignisse an das Zielpaket weitergegeben und die Zielaktivitäten werden neu gestartet.

Beschränken Sie überlagerbare Ressourcen

In Android 10 oder höher stellt das XML-Tag <overlayable> eine Reihe von Ressourcen bereit, die RROs überlagern dürfen. In der folgenden Beispieldatei res/values/overlayable.xml sind string/foo und integer/bar Ressourcen, die zur Gestaltung des Erscheinungsbilds des Geräts verwendet werden. Um diese Ressourcen zu überlagern, muss ein Overlay explizit namentlich auf die Sammlung überlagerbarer Ressourcen abzielen.

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

Ein APK kann mehrere <overlayable> -Tags definieren, aber jedes Tag muss innerhalb des Pakets einen eindeutigen Namen haben. Es handelt sich zum Beispiel um:

  • OK, wenn zwei verschiedene Pakete beide <overlayable name="foo"> definieren.

  • Es ist nicht in Ordnung, dass ein einzelnes APK zwei <overlayable name="foo"> Blöcke hat.

Der folgende Code zeigt ein Beispiel für eine Überlagerung in der Datei 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>

Wenn eine App ein <overlayable> -Tag definiert, werden Overlays, die auf diese App abzielen:

  • targetName muss angegeben werden.

  • Kann nur die im <overlayable> -Tag aufgeführten Ressourcen überlagern.

  • Kann nur auf einen <overlayable> -Namen abzielen.

Sie können kein Overlay aktivieren, das auf ein Paket abzielt, das überlagerbare Ressourcen verfügbar macht, aber nicht android:targetName verwendet, um auf ein bestimmtes <overlayable> -Tag abzuzielen.

Richtlinien einschränken

Verwenden Sie das <policy> -Tag, um Einschränkungen für überlagerbare Ressourcen durchzusetzen. Das type gibt an, welche Richtlinien ein Overlay erfüllen muss, um die enthaltenen Ressourcen zu überschreiben. Zu den unterstützten Typen gehören die folgenden.

  • public . Jede Überlagerung kann die Ressource überschreiben.
  • system . Jede Überlagerung auf der Systempartition kann die Ressourcen überschreiben.
  • vendor . Jede Überlagerung auf der Herstellerpartition kann die Ressourcen überschreiben.
  • product . Jede Überlagerung auf der Produktpartition kann die Ressourcen überschreiben.
  • oem . Jede Überlagerung auf der OEM-Partition kann die Ressourcen überschreiben.
  • odm . Jede Überlagerung auf der ODM-Partition kann die Ressourcen überschreiben.
  • signature . Jedes Overlay, das mit derselben Signatur wie das Ziel-APK signiert ist, kann die Ressourcen überschreiben.
  • actor . Jedes Overlay, das mit derselben Signatur wie das Akteur- APK signiert ist, kann die Ressourcen überschreiben. Der Akteur wird im Named-Actor -Tag in der Systemkonfiguration deklariert.
  • config_signature . Jedes Overlay, das mit derselben Signatur wie die Overlay-Config -Apk signiert ist, kann die Ressourcen überschreiben. Die Overlay-Konfiguration wird im Tag „overlay-config-signature“ in der Systemkonfiguration deklariert.

Der folgende Code zeigt ein Beispiel eines <policy> -Tags in der Datei 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>

Um mehrere Richtlinien anzugeben, verwenden Sie vertikale Striche (|) als Trennzeichen. Wenn mehrere Richtlinien angegeben sind, muss ein Overlay nur eine Richtlinie erfüllen, um die im <policy> -Tag aufgeführten Ressourcen zu überschreiben.

Konfigurieren Sie Overlays

Android unterstützt je nach Android-Release-Version unterschiedliche Mechanismen zum Konfigurieren der Veränderlichkeit, des Standardstatus und der Priorität von Overlays.

  • Geräte mit Android 11 oder höher können anstelle von Manifestattributen eine OverlayConfig Datei ( config.xml ) verwenden. Die Verwendung einer Overlay-Datei ist die empfohlene Methode für Overlays.

  • Alle Geräte können Manifestattribute ( android:isStatic und android:priority ) verwenden, um statische RROs zu konfigurieren.

Verwenden Sie OverlayConfig

In Android 11 oder höher können Sie OverlayConfig verwenden, um die Veränderlichkeit, den Standardstatus und die Priorität von Overlays zu konfigurieren. Um ein Overlay zu konfigurieren, erstellen oder ändern Sie die Datei unter partition/overlay/config/config.xml , wobei partition die Partition des zu konfigurierenden Overlays ist. Um konfiguriert zu werden, muss sich ein Overlay im Verzeichnis overlay/ der Partition befinden, in der das Overlay konfiguriert ist. Der folgende Code zeigt ein Beispiel 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>"

Das <overlay> -Tag erfordert ein package , das angibt, welches Overlay-Paket konfiguriert wird. Das optionale Attribut enabled steuert, ob das Overlay standardmäßig aktiviert ist (Standard ist false ). Das optionale Attribut mutable steuert, ob das Overlay veränderbar ist oder nicht, und kann seinen aktivierten Status zur Laufzeit programmgesteuert ändern (Standard ist true ). Overlays, die nicht in einer Konfigurationsdatei aufgeführt sind, sind veränderbar und standardmäßig deaktiviert.

Overlay-Priorität

Wenn mehrere Overlays dieselben Ressourcen überschreiben, ist die Reihenfolge der Overlays wichtig. Ein Overlay hat eine höhere Priorität als Overlays mit Konfigurationen, die seiner eigenen Konfiguration vorangehen. Die Rangfolge der Überlagerungen in verschiedenen Partitionen (von der niedrigsten zur größten Rangfolge) ist wie folgt.

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

Dateien zusammenführen

Durch die Verwendung von <merge> -Tags können andere Konfigurationsdateien an der angegebenen Position in die Konfigurationsdatei eingefügt werden. Das path des Tags stellt den Pfad der zusammenzuführenden Datei relativ zum Verzeichnis dar, das Overlay-Konfigurationsdateien enthält.

Verwenden Sie Manifestattribute/statische RROs

In Android 10 oder niedriger werden Overlay-Unveränderlichkeit und Priorität mithilfe der folgenden Manifestattribute konfiguriert.

  • android:isStatic . Wenn der Wert dieses booleschen Attributs auf true gesetzt ist, ist das Overlay standardmäßig aktiviert und unveränderlich, was verhindert, dass das Overlay deaktiviert wird.

  • android:priority . Der Wert dieses numerischen Attributs (das nur statische Overlays betrifft) konfiguriert die Priorität des Overlays, wenn mehrere statische Overlays auf denselben Ressourcenwert abzielen. Eine höhere Zahl weist auf eine höhere Priorität hin.

Der folgende Code zeigt ein Beispiel 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>

Änderungen in Android 11

Wenn sich in Android 11 oder höher eine Konfigurationsdatei in partition/overlay/config/config.xml befindet, werden Overlays mithilfe dieser Datei konfiguriert und android:isStatic und android:priority haben keine Auswirkung auf Overlays, die sich in der Partition befinden. Durch das Definieren einer Overlay-Konfigurationsdatei in einer beliebigen Partition wird die Priorität der Overlay-Partition erzwungen.

Darüber hinaus entfernt Android 11 oder höher die Möglichkeit, statische Overlays zu verwenden, um die Werte von Ressourcen zu beeinflussen, die während der Paketinstallation gelesen werden. Für den allgemeinen Anwendungsfall der Verwendung statischer Overlays zum Ändern des Werts von Booleschen Werten, die den aktivierten Zustand der Komponente konfigurieren, verwenden Sie das SystemConfig Tag <component-override> (neu in Android 11).

Debug-Overlays

Um Overlays manuell zu aktivieren, zu deaktivieren und zu sichern, verwenden Sie den folgenden Overlay-Manager-Shell-Befehl.

adb shell cmd overlay

OverlayManagerService verwendet idmap2 um Ressourcen-IDs im Zielpaket den Ressourcen-IDs im Overlay-Paket zuzuordnen. Die generierten ID-Zuordnungen werden in /data/resource-cache/ gespeichert. Wenn Ihr Overlay nicht ordnungsgemäß funktioniert, suchen Sie die entsprechende idmap Datei für Ihr Overlay in /data/resource-cache/ und führen Sie dann den folgenden Befehl aus.

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

Dieser Befehl druckt die Ressourcenzuordnung wie unten gezeigt.

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