Wert der Ressourcen einer App während der Laufzeit ändern

Ein Laufzeitressourcen-Overlay (RRO) ist ein Paket, das die Ressourcenwerte eines Zielpakets zur Laufzeit ändert. Beispielsweise kann eine auf dem System-Image installierte App ihr Verhalten basierend auf dem Wert einer Ressource ändern. Anstatt den Ressourcenwert zur Buildzeit hartzucodieren, kann ein auf einer anderen Partition installiertes RRO die Werte der App-Ressourcen zur Laufzeit ändern.

RROs können aktiviert oder deaktiviert werden. Sie können den Status „Aktivieren“/„Deaktivieren“ programmatisch festlegen, um die Möglichkeit eines RRO, Ressourcenwerte zu ändern, zu aktivieren oder zu deaktivieren. RROs sind standardmäßig deaktiviert (statische RROs sind jedoch standardmäßig aktiviert).

Ressourcen einblenden

Bei Overlays werden Ressourcen, die im Overlay-Paket definiert sind, Ressourcen im Zielpaket zugeordnet. Wenn eine Anwendung versucht, den Wert einer Ressource im Zielpaket aufzulösen, wird stattdessen der Wert der Overlay-Ressource zurückgegeben, der die Zielressource zugeordnet ist.

Manifest einrichten

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

  • Der Wert des erforderlichen android:targetPackage-Attributs gibt den Namen des Pakets an, das mit dem RRO eingeblendet werden soll.

  • Der Wert des optionalen android:targetName-Attributs gibt den Namen der einblendbaren Teilmenge von Ressourcen des Zielpakets an, das mit dem RRO überlagert werden soll. Wenn durch das Ziel keine überschaubare Gruppe von Ressourcen definiert wird, sollte dieses Attribut nicht vorhanden sein.

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

<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. Außerdem muss das android:hasCode-Attribut des <application>-Tags im Manifest auf false gesetzt sein.

Ressourcenzuordnung definieren

Ab Android 11 wird zum Definieren der Overlay-Ressourcenzuordnung empfohlen, eine Datei im Verzeichnis res/xml des Overlay-Pakets zu erstellen, die zu überlagernden Zielressourcen und ihre Ersatzwerte aufzulisten und dann den Wert des Attributs android:resourcesMap des Manifest-Tags <overlay> auf einen Verweis auf die Ressourcenzuordnungsdatei zu setzen.

Der folgende Code zeigt eine res/xml/overlays.xml-Beispieldatei.

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

Paket erstellen

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

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

Ressourcen auflösen

Wenn für eine Zielressource oder eine 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 den Zielressourcenkonfigurationen zusammen und folgen dann dem regulären Ablauf der Ressourcenauflösung. Weitere Informationen finden Sie unter So findet Android die am besten übereinstimmende Ressource.

Wenn ein Overlay beispielsweise einen Wert für die drawable-en-Konfiguration 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 zur Laufzeit ausgewählt wird. Damit alle drawable-en-Konfigurationen überlagert werden, muss das Overlay einen Wert für jede drawable-en-Konfiguration definieren, die das Ziel definiert.

Overlays können auf ihre eigenen Ressourcen verweisen und unterscheiden sich in den Android-Versionen.

  • Unter Android 11 oder höher hat jedes Overlay einen eigenen reservierten Ressourcen-ID-Bereich, der sich nicht mit dem Ziel-Ressourcen-ID-Bereich oder anderen Overlay-Ressourcen-ID-Bereichen überschneidet. Overlays, die auf ihre eigenen Ressourcen verweisen, funktionieren daher wie erwartet.

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

Overlays aktivieren/deaktivieren

Verwenden Sie die OverlayManager API, um änderbare Overlays zu aktivieren und zu deaktivieren (die API-Schnittstelle mit Context#getSystemService(Context.OVERLAY_SERVICE) abrufen). Ein Overlay kann nur vom Zielpaket oder von einem Paket mit der Berechtigung android.permission.CHANGE_OVERLAY_PACKAGES aktiviert werden. Wenn ein Overlay aktiviert oder deaktiviert wird, werden Ereignisse zu Konfigurationsänderungen an das Zielpaket weitergegeben und die Zielaktivitäten werden neu gestartet.

Überlagerbare Ressourcen einschränken

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

<!-- 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. Beispiel:

  • Es ist zulässig, dass <overlayable name="foo"> in zwei verschiedenen Paketen definiert wird.

  • Ein einzelnes APK darf nicht zwei <overlayable name="foo">-Blöcke enthalten.

Der folgende Code zeigt ein Beispiel für ein Overlay 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 in einer App ein <overlayable>-Tag definiert ist, werden folgende Overlays angezeigt, die auf diese App ausgerichtet sind:

  • Muss targetName angeben.

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

  • Es kann nur auf einen <overlayable>-Namen ausgerichtet werden.

Sie können kein Overlay aktivieren, das auf ein Paket ausgerichtet ist, das überblendbare Ressourcen verfügbar macht, aber android:targetName nicht für die Ausrichtung auf ein bestimmtes <overlayable>-Tag verwendet.

Richtlinien einschränken

Mit dem Tag <policy> können Sie Einschränkungen für überspringbare Ressourcen erzwingen. Mit dem Attribut type wird angegeben, welche Richtlinien ein Overlay erfüllen muss, um die enthaltenen Ressourcen zu überschreiben. Folgende Typen werden unterstützt.

  • public. Jedes Overlay kann die Ressource überschreiben.
  • system. Jedes Overlay auf der Systempartition kann die Ressourcen überschreiben.
  • vendor. Jedes Overlay auf der Anbieterpartition kann die Ressourcen überschreiben.
  • product. Die Ressourcen können von jedem Overlay in der Produktaufteilung überschrieben werden.
  • oem. Jedes Overlay auf der OEM-Partition kann die Ressourcen überschreiben.
  • odm. Jedes Overlay 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 Actor-APK signiert ist, kann die Ressourcen überschreiben. Der Akteur wird im Tag named-actor in der Systemkonfiguration deklariert.
  • config_signature: Jedes Overlay, das mit derselben Signatur wie die APK-Datei overlay-config 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 für ein <policy>-Tag 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>

Wenn Sie mehrere Richtlinien angeben möchten, verwenden Sie vertikale Balken (|) 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.

Overlays konfigurieren

Android unterstützt je nach Android-Release-Version verschiedene Mechanismen zur Konfiguration der Mutabilität, des Standardstatus und der Priorität von Overlays.

  • Auf Geräten mit Android 11 oder höher kann anstelle von Manifestattributen eine OverlayConfig-Datei (config.xml) verwendet werden. Für Overlays wird die Verwendung einer Overlay-Datei empfohlen.

  • Auf allen Geräten können Manifestattribute (android:isStatic und android:priority) verwendet werden, um statische RROs zu konfigurieren.

OverlayConfig verwenden

Unter Android 11 oder höher können Sie mit OverlayConfig die Mutabilität, den Standardstatus und die Priorität von Overlays konfigurieren. Zum Konfigurieren eines Overlays erstellen oder ändern Sie die Datei unter partition/overlay/config/config.xml, wobei partition die Partition des Overlays ist, die konfiguriert werden soll. Ein Overlay muss sich zum Konfigurieren im Verzeichnis overlay/ der Partition befinden, in der es konfiguriert ist. Der folgende Code zeigt ein Beispiel für 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>"

Für das Tag <overlay> ist ein package-Attribut erforderlich, das angibt, welches Overlay-Paket konfiguriert wird. Das optionale Attribut enabled steuert, ob das Overlay standardmäßig aktiviert ist (Standardeinstellung ist false). Das optionale Attribut mutable steuert, ob das Overlay änderbar ist und seinen Aktivierungsstatus zur Laufzeit programmatisch ändern kann (Standardeinstellung ist true). Overlays, die nicht in einer Konfigurationsdatei aufgeführt sind, sind änderbar und standardmäßig deaktiviert.

Overlay-Vorrang

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 voraus sind. Die Rangfolge der Overlays in verschiedenen Partitionen (von der niedrigsten bis zur größten Priorität) lautet wie folgt.

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

Dateien zusammenführen

Mit <merge>-Tags können andere Konfigurationsdateien an der angegebenen Position in der Konfigurationsdatei zusammengeführt werden. Das Attribut path des Tags stellt den Pfad der zusammenzuführenden Datei relativ zu dem Verzeichnis dar, das die Overlay-Konfigurationsdateien enthält.

Manifest-Attribute/statische RROs verwenden

Unter Android 10 oder niedriger werden die Unveränderlichkeit und die Priorität von Overlays mit den folgenden Manifest-Attributen konfiguriert.

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

  • android:priority. Mit dem Wert dieses numerischen Attributs (das sich nur auf statische Overlays auswirkt) wird die Priorität des Overlays konfiguriert, wenn mehrere statische Overlays auf denselben Ressourcenwert ausgerichtet sind. Je höher die Zahl, desto höher die Priorität.

Der folgende Code zeigt ein AndroidManifest.xml-Beispiel.

<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 bei Android 11

Wenn sich unter Android 11 oder höher eine Konfigurationsdatei in partition/overlay/config/config.xml befindet, werden Overlays mit dieser Datei konfiguriert. android:isStatic und android:priority haben dann keine Auswirkungen auf Overlays in der Partition. Wenn Sie eine Overlay-Konfigurationsdatei in einer beliebigen Partition definieren, wird die Vorrangstellung der Overlay-Partition erzwungen.

Außerdem können unter Android 11 oder höher keine statischen Overlays mehr verwendet werden, um die Werte von Ressourcen zu beeinflussen, die während der Paketinstallation gelesen werden. Für den häufigen Anwendungsfall, bei dem mithilfe von statischen Overlays der Wert von Booleschen Werten geändert wird, die den aktivierten Status der Komponente konfigurieren, verwenden Sie das Tag <component-override> SystemConfig (neu in Android 11).

Overlays zur Fehlerbehebung

Mit dem folgenden Shell-Befehl für Overlay-Manager können Sie Overlays manuell aktivieren, deaktivieren und speichern.

adb shell cmd overlay

In OverlayManagerService werden mit idmap2 Ressourcen-IDs im Zielpaket Ressourcen-IDs im Overlay-Paket zugeordnet. Die generierten ID-Zuordnungen werden in /data/resource-cache/ gespeichert. Wenn das Overlay nicht richtig funktioniert, suchen Sie in /data/resource-cache/ nach der entsprechenden idmap-Datei für das Overlay und führen Sie dann den folgenden Befehl aus.

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

Dieser Befehl gibt die Zuordnung der Ressourcen wie unten dargestellt aus.

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