Modifica il valore delle risorse di un'app in fase di esecuzione

Mantieni tutto organizzato con le raccolte Salva e classifica i contenuti in base alle tue preferenze.

Un runtime resource overlay (RRO) è un pacchetto che modifica i valori delle risorse di un pacchetto di destinazione in fase di esecuzione. Ad esempio, un'app installata nell'immagine di sistema potrebbe cambiare il proprio comportamento in base al valore di una risorsa. Invece di codificare il valore della risorsa in fase di compilazione, un RRO installato su una partizione diversa può modificare i valori delle risorse dell'app in fase di esecuzione.

Gli RRO possono essere abilitati o disabilitati. È possibile impostare a livello di codice lo stato di abilitazione/disabilitazione per attivare o disattivare la capacità di un RRO di modificare i valori delle risorse. Gli RRO sono disabilitati per impostazione predefinita (tuttavia, gli RRO statici sono abilitati per impostazione predefinita).

Risorse sovrapposte

Gli overlay funzionano mappando le risorse definite nel pacchetto overlay alle risorse definite nel pacchetto di destinazione. Quando un'app tenta di risolvere il valore di una risorsa nel pacchetto di destinazione, viene invece restituito il valore della risorsa di sovrapposizione a cui è mappata la risorsa di destinazione.

Impostazione del manifesto

Un pacchetto è considerato un pacchetto RRO se contiene un tag <overlay> come figlio del tag <manifest> .

  • Il valore dell'attributo android:targetPackage richiesto specifica il nome del pacchetto che l'RRO intende sovrapporre.

  • Il valore dell'attributo facoltativo android:targetName specifica il nome del sottoinsieme sovrapponibile di risorse del pacchetto di destinazione che l'RRO intende sovrapporre. Se la destinazione non definisce un set di risorse sovrapponibili, questo attributo non dovrebbe essere presente.

Il codice seguente mostra un esempio di 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>

Gli overlay non possono sovrapporre il codice, quindi non possono avere file DEX. Inoltre, l'attributo android:hasCode del tag <application > nel manifest deve essere impostato su false .

Definizione della mappa delle risorse

In Android 11 o versioni successive, il meccanismo consigliato per definire la mappa delle risorse di sovrapposizione consiste nel creare un file nella directory res/xml del pacchetto di sovrapposizione, enumerare le risorse di destinazione che devono essere sovrapposte e i relativi valori di sostituzione, quindi impostare il valore di android:resourcesMap attributo del tag manifest <overlay> a un riferimento al file di mapping delle risorse.

Il codice seguente mostra un esempio di file 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>

Il codice seguente mostra un manifest di sovrapposizione di esempio.

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

Costruire il pacchetto

Android 11 o versioni successive supporta una regola di build Soong per gli overlay che impedisce ad Android Asset Packaging Tool 2 (AAPT2) di tentare di deduplicare configurazioni di risorse con lo stesso valore ( --no-resource-deduping ) e di rimuovere risorse senza configurazioni predefinite ( --no-resource-removal ). Il codice seguente mostra un file Android.bp di esempio.

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

Risorse risolutive

Se una risorsa di destinazione o una risorsa di sovrapposizione ha più configurazioni definite per la risorsa sottoposta a query, il runtime delle risorse restituisce il valore della configurazione che meglio corrisponde alla configurazione della configurazione del dispositivo. Per determinare quale configurazione è quella con la migliore corrispondenza, unisci il set di configurazioni delle risorse di sovrapposizione nel set di configurazioni delle risorse di destinazione e quindi segui il normale flusso di risoluzione delle risorse (per i dettagli, fai riferimento a Come Android trova la risorsa con la migliore corrispondenza ).

Ad esempio, se un overlay definisce un valore per la configurazione drawable-en e la destinazione definisce un valore per drawable-en-port , drawable-en-port ha una corrispondenza migliore, quindi il valore della configurazione di destinazione drawable-en-port è scelto in fase di esecuzione. Per sovrapporre tutte le configurazioni drawable-en , la sovrapposizione deve definire un valore per ogni configurazione drawable-en definita dalla destinazione.

Gli overlay possono fare riferimento alle proprie risorse, con comportamenti diversi tra le versioni di Android.

  • In Android 11 o versioni successive, ogni overlay ha il proprio spazio ID risorsa riservato che non si sovrappone allo spazio ID risorsa di destinazione o ad altri spazi ID risorsa overlay, quindi gli overlay che fanno riferimento alle proprie risorse funzionano come previsto.

  • In Android 10 o versioni precedenti, gli overlay e i pacchetti di destinazione condividono lo stesso spazio ID risorsa, che può causare collisioni e comportamenti imprevisti quando tentano di fare riferimento alle proprie risorse utilizzando la sintassi @type/name .

Abilitare/disabilitare gli overlay

Utilizzare l'API OverlayManager per abilitare e disabilitare gli overlay modificabili (recuperare l'interfaccia API utilizzando Context#getSystemService(Context.OVERLAY_SERVICE) ). Un overlay può essere abilitato solo dal pacchetto a cui si rivolge o da un pacchetto con l'autorizzazione android.permission.CHANGE_OVERLAY_PACKAGES . Quando un overlay è abilitato o disabilitato, gli eventi di modifica della configurazione si propagano al pacchetto di destinazione e le attività di destinazione vengono riavviate.

Limitazione delle risorse sovrapponibili

In Android 10 o versioni successive, il tag XML <overlayable> espone un set di risorse che gli RRO possono sovrapporre. Nel seguente file di esempio res/values/overlayable.xml , string/foo e integer/bar sono risorse usate per definire il tema dell'aspetto del dispositivo; per sovrapporre queste risorse, una sovrapposizione deve indirizzare esplicitamente la raccolta di risorse sovrapponibili per nome.

<!-- 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 può definire più tag <overlayable> , ma ogni tag deve avere un nome univoco all'interno del pacchetto. Ad esempio, è:

  • OK per due pacchetti diversi per definire entrambi <overlayable name="foo"> .

  • Non va bene che un singolo APK abbia due <overlayable name="foo"> .

Il codice seguente mostra un esempio di overlay nel file 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>

Quando un'app definisce un tag <overlayable> , gli overlay hanno come target quell'app:

  • Devi specificare targetName .

  • Può sovrapporre solo le risorse elencate all'interno del tag <overlayable> .

  • Può scegliere come target solo un nome <overlayable> .

Non puoi abilitare un overlay destinato a un pacchetto che espone risorse sovrapponibili ma non utilizza android:targetName per scegliere come target un tag <overlayable> specifico.

Politiche restrittive

Utilizzare il tag <policy> per imporre restrizioni sulle risorse sovrapponibili. L'attributo type specifica quali criteri deve soddisfare un overlay per sovrascrivere le risorse incluse. I tipi supportati includono quanto segue.

  • public . Qualsiasi overlay può sovrascrivere la risorsa.
  • system . Qualsiasi sovrapposizione sulla partizione di sistema può sovrascrivere le risorse.
  • vendor . Qualsiasi sovrapposizione sulla partizione del fornitore può sovrascrivere le risorse.
  • product . Qualsiasi sovrapposizione sulla partizione del prodotto può sovrascrivere le risorse.
  • oem . Qualsiasi sovrapposizione sulla partizione oem può sovrascrivere le risorse.
  • odm . Qualsiasi sovrapposizione sulla partizione odm può sovrascrivere le risorse.
  • signature . Qualsiasi overlay firmato con la stessa firma dell'APK di destinazione può ignorare le risorse.
  • actor . Qualsiasi overlay firmato con la stessa firma dell'APK dell'attore può sovrascrivere le risorse. L'attore è dichiarato nel tag named-actor nella configurazione di sistema.
  • config_signature . Qualsiasi overlay firmato con la stessa firma dell'apk overlay-config può sovrascrivere le risorse. L'overlay-config è dichiarato nel tag overlay-config-signature nella configurazione di sistema.

Il codice seguente mostra un esempio di tag <policy> nel file 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>

Per specificare più criteri, utilizzare le barre verticali (|) come caratteri separatori. Quando vengono specificate più policy, un overlay deve soddisfare solo una policy per sovrascrivere le risorse elencate all'interno del tag <policy> .

Configurazione degli overlay

Android supporta diversi meccanismi per configurare la mutabilità, lo stato predefinito e la priorità degli overlay a seconda della versione di rilascio di Android.

  • I dispositivi che eseguono Android 11 o versioni successive possono utilizzare un file OverlayConfig ( config.xml ) invece degli attributi manifest. L'utilizzo di un file di sovrapposizione è il metodo consigliato per le sovrapposizioni.

  • Tutti i dispositivi possono utilizzare gli attributi manifest ( android:isStatic e android:priority ) per configurare gli RRO statici.

Utilizzo di OverlayConfig

In Android 11 o versioni successive, puoi utilizzare OverlayConfig per configurare la mutabilità, lo stato predefinito e la priorità degli overlay. Per configurare un overlay, creare o modificare il file che si trova in partition/overlay/config/config.xml , dove partition è la partizione dell'overlay da configurare. Per essere configurato, un overlay deve risiedere nella directory overlay/ della partizione in cui è configurato l'overlay. Il codice seguente mostra un esempio 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>"

Il tag <overlay> richiede un attributo del package che indichi quale pacchetto overlay viene configurato. L'attributo facoltativo enabled controlla se l'overlay è abilitato per impostazione predefinita (il valore predefinito è false ). L'attributo facoltativo mutable controlla se l'overlay è mutabile o meno e se il suo stato abilitato può essere modificato in modo programmatico in fase di esecuzione (il valore predefinito è true ). Gli overlay non elencati all'interno di un file di configurazione sono modificabili e disabilitati per impostazione predefinita.

Precedenza di sovrapposizione

Quando più sovrapposizioni eseguono l'override delle stesse risorse, l'ordine delle sovrapposizioni è importante. Una sovrapposizione ha una precedenza maggiore rispetto alle sovrapposizioni con configurazioni che precedono la propria configurazione. L'ordine di precedenza degli overlay nelle diverse partizioni (dalla minima alla massima) è il seguente.

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

Unione di file

L'utilizzo dei tag <merge> consente di unire altri file di configurazione nella posizione specificata nel file di configurazione. L'attributo path del tag rappresenta il percorso del file da unire rispetto alla directory contenente i file di configurazione dell'overlay.

Utilizzo degli attributi manifest (RRO statici)

In Android 10 o versioni precedenti, l'immutabilità e la precedenza dell'overlay sono configurate utilizzando i seguenti attributi manifest.

  • android:isStatic . Quando il valore di questo attributo booleano è impostato su true , l'overlay è abilitato per impostazione predefinita ed è immutabile, il che impedisce la disabilitazione dell'overlay.

  • android:priority . Il valore di questo attributo numerico (che influisce solo sugli overlay statici) configura la precedenza dell'overlay quando più overlay statici hanno come destinazione lo stesso valore di risorsa. Un numero più alto indica una precedenza più alta.

Il codice seguente mostra un esempio 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>

Modifiche in Android 11

In Android 11 o versioni successive, se un file di configurazione si trova in partition/overlay/config/config.xml , gli overlay vengono configurati usando quel file e android:isStatic e android:priority non hanno effetto sugli overlay che si trovano nella partizione. La definizione di un file di configurazione di sovrapposizione in qualsiasi partizione applica la precedenza della partizione di sovrapposizione.

Inoltre, Android 11 o versioni successive rimuove la possibilità di utilizzare sovrapposizioni statiche per influenzare i valori delle risorse lette durante l'installazione del pacchetto. Per il caso d'uso comune di utilizzo di sovrapposizioni statiche per modificare il valore dei booleani che configurano lo stato abilitato del componente, utilizzare il <component-override> SystemConfig (nuovo in Android 11).

Sovrapposizioni di debug

Per abilitare, disabilitare e scaricare manualmente gli overlay, utilizzare il seguente comando della shell di overlay manager.

adb shell cmd overlay

OverlayManagerService usa idmap2 per mappare gli ID risorsa nel pacchetto di destinazione agli ID risorsa nel pacchetto overlay. I mapping degli ID generati vengono archiviati in /data/resource-cache/ . Se il tuo overlay non funziona correttamente, trova il file idmap corrispondente per il tuo overlay in /data/resource-cache/ , quindi esegui il seguente comando.

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

Questo comando stampa la mappatura delle risorse come mostrato di seguito.

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