Alterar o valor dos recursos de um aplicativo no tempo de execução

Uma sobreposição de recursos no ambiente de execução (RRO) é um pacote que altera os valores de recursos de um pacote de destino no ambiente de execução. Por exemplo, um app instalado no sistema imagem pode mudar de comportamento com base no valor de um recurso. Em vez de fixar no código o valor do recurso no tempo de build, uma RRO instalada em um pode alterar os valores dos recursos do aplicativo no ambiente de execução.

As RROs podem ser ativadas ou desativadas. Você pode definir programaticamente o ativar/desativar o estado para alternar a capacidade de uma RRO de alterar valores de recursos. RROs ficam desativados por padrão. No entanto, as RROs estáticas são ativadas padrão).

Recursos de sobreposição

As sobreposições funcionam mapeando os recursos definidos no pacote de sobreposição para recursos definidos no pacote de destino. Quando um aplicativo tenta resolver o valor de um no pacote de destino, o valor do recurso de sobreposição que o destino recurso é mapeado será retornado.

Configurar o manifesto

Um pacote é considerado RRO se tiver uma tag <overlay> como filho da tag <manifest>.

  • O valor do atributo obrigatório android:targetPackage especifica o nome. do pacote que a RRO pretende sobrepor.

  • O valor do atributo opcional android:targetName especifica o nome do o subconjunto sobreposto de recursos do pacote de destino que a RRO pretende sobreposição. Se o destino não definir um conjunto de recursos sobreposto, este não deve estar presente.

O código a seguir mostra um exemplo de sobreposição 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>

As sobreposições não podem sobrepor código, por isso não podem ter arquivos DEX. Além disso, Atributo android:hasCode de <application> no manifesto precisa ser Defina como false.

Definir o mapa de recursos

No Android 11 ou versões mais recentes, o mecanismo recomendado para definir o mapa de recursos de sobreposição é criar um arquivo no res/xml do pacote de sobreposição, enumerar os recursos de destino que devem ser sobrepostas e seus valores de substituição, defina o valor do android:resourcesMap da tag de manifesto <overlay> a uma referência ao arquivo de mapeamento de recursos.

O código abaixo mostra um exemplo de arquivo 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>

O código a seguir mostra um exemplo de manifesto de sobreposição.

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

Criar o pacote

O Android 11 ou versões mais recentes oferecem suporte a uma regra de build Soong para sobreposições que impedem o Android Asset Packaging Tool 2 (AAPT2) de tentar eliminar a duplicação de configurações de recursos com o mesmo valor (--no-resource-deduping) e da remoção de recursos sem padrão (--no-resource-removal). O código a seguir mostra um exemplo arquivo Android.bp.

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

Resolver recursos

Se um recurso de destino ou de sobreposição tiver várias configurações definidas para o recurso que está sendo consultado, o ambiente de execução de recursos retorna o valor do que melhor corresponda à configuração do dispositivo. Para determinar qual é a configuração mais adequada, mescle o um conjunto de configurações de recursos de sobreposição no conjunto de recursos de destino e seguir o fluxo regular de resolução de recursos (por exemplo, detalhes, consulte Como o Android encontra as melhores recurso).

Por exemplo, se uma sobreposição define um valor para a configuração drawable-en e o destino define um valor para drawable-en-port, drawable-en-port tem uma correspondência melhor, portanto, o valor da configuração de destino drawable-en-port é escolhido no tempo de execução. Para sobrepor todas as configurações de drawable-en, a sobreposição precisa definir um valor para cada configuração de drawable-en definida pelo destino.

As sobreposições podem referenciar seus próprios recursos, com comportamentos diferentes entre Versões do Android.

  • No Android 11 ou versões mais recentes, cada sobreposição tem espaço de ID de recurso reservado que não se sobrepõe ao espaço de ID do recurso de destino ou outros espaços de ID de recurso de sobreposição, de modo que as sobreposições que fazem referência aos próprios recursos funcionar da forma esperada.

  • No Android 10 ou versões anteriores, as sobreposições e os pacotes de destino compartilham o mesmo recurso ID do cliente, que pode causar colisões e comportamentos inesperados quando tentam para referenciar os próprios recursos usando a sintaxe @type/name.

Ativar/desativar sobreposições

Usar a API OverlayManager para ativar e desativar sobreposições mutáveis (extrair a interface da API usando Context#getSystemService(Context.OVERLAY_SERVICE)). Um sobreposição pode ser ativada somente pelo pacote que ela segmenta ou por um pacote com o android.permission.CHANGE_OVERLAY_PACKAGES. Quando uma sobreposição é ativados ou desativados, os eventos de alteração de configuração são propagados para o pacote de destino e das atividades de destino.

Restringir recursos sobrepostos

No Android 10 ou versões mais recentes, a tag XML <overlayable> expõe um conjunto de recursos que as RROs podem sobrepor. No exemplo a seguir, O arquivo res/values/overlayable.xml, string/foo e integer/bar são recursos usado para aplicar temas à aparência do dispositivo; para sobrepor esses recursos, uma sobreposição precisa segmentar explicitamente o conjunto de recursos que podem ser sobrepostos por 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>

Um APK pode definir várias tags <overlayable>, mas cada tag precisa ter uma tag exclusiva. dentro do pacote. Por exemplo, ela é:

  • OK para dois pacotes diferentes definirem <overlayable name="foo">.

  • Não é aceitável que um único APK tenha dois blocos <overlayable name="foo">.

O código abaixo mostra um exemplo de sobreposição na 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 um app define uma tag <overlayable>, as sobreposições que segmentam esse app:

  • É necessário especificar targetName.

  • Pode sobrepor apenas os recursos listados na tag <overlayable>.

  • É possível segmentar apenas um nome <overlayable>.

Não é possível ativar uma sobreposição que segmenta um pacote que expõe recursos, mas não usa android:targetName para visar um <overlayable>.

Políticas de restrição

Use a tag <policy> para aplicar restrições a recursos que podem ser sobrepostos. A O atributo type especifica quais políticas uma sobreposição precisa preencher para substituir os recursos incluídos. Os tipos compatíveis incluem os seguintes.

  • public: Qualquer sobreposição pode substituir o recurso.
  • system: Qualquer sobreposição na partição do sistema pode substituir os recursos.
  • vendor: Qualquer sobreposição na partição do fornecedor pode substituir os recursos.
  • product: Qualquer sobreposição na partição do produto pode substituir os recursos.
  • oem: Qualquer sobreposição na partição do OEM pode substituir os recursos.
  • odm: Qualquer sobreposição na partição odm pode substituir os recursos.
  • signature: Qualquer sobreposição assinada com a mesma assinatura do APK de destino pode substituir os recursos.
  • actor: Qualquer sobreposição assinada com a mesma assinatura do APK do ator pode substituir os recursos. O ator é declarado na tag names-actor do sistema. configuração
  • config_signature: Qualquer sobreposição com a mesma assinatura do O apk overlay-config pode substituir os recursos. O overlay-config é declarado na tag overlay-config-signature na configuração do sistema.

O código a seguir mostra um exemplo de tag <policy> na arquivo 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 várias políticas, use barras verticais (|) como caracteres separadores. Quando várias políticas são especificadas, uma sobreposição precisa atender a apenas uma para substituir os recursos listados na tag <policy>.

Configurar sobreposições

O Android oferece suporte a diferentes mecanismos para configurar a mutabilidade, a estado e prioridade das sobreposições, dependendo da versão de lançamento do Android.

  • Dispositivos com o Android 11 ou versões mais recentes podem usar uma OverlayConfig (config.xml) em vez de atributos de manifesto. Usar um é o método recomendado para sobreposições.

  • Todos os dispositivos podem usar atributos de manifesto (android:isStatic e android:priority) para configurar RROs estáticas.

.

Usar OverlayConfig

No Android 11 ou versões mais recentes, você pode usar OverlayConfig para configurar a mutabilidade, o estado padrão e a prioridade das sobreposições. Para configurar uma sobreposição, crie ou modifique o arquivo localizado em partition/overlay/config/config.xml, em que partition é a partição do a ser configurada. Para ser configurada, uma sobreposição deve residir no Diretório overlay/ da partição em que a sobreposição está configurada. A o código a seguir mostra um exemplo 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>"

A tag <overlay> requer um atributo package que indica qual sobreposição está sendo configurado. O atributo opcional enabled controla se a sobreposição será ativada por padrão (o padrão é false). O parâmetro opcional O atributo mutable controla se a sobreposição é mutável e pode ter o estado ativado mudou programaticamente no momento da execução (o padrão é true). As sobreposições não listadas em um arquivo de configuração são mutáveis e desativadas por padrão.

Precedência da sobreposição

Quando várias sobreposições substituem os mesmos recursos, a ordem delas é muito importante. Uma sobreposição tem maior precedência do que as sobreposições com configurações anterior à própria configuração. A ordem de precedência de sobreposições em diferentes partições diferentes (da precedência menor para a maior) é a seguinte.

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

Mesclar arquivos

O uso de tags <merge> permite que outros arquivos de configuração sejam mesclados no no arquivo de configuração. O atributo path da tag representa o caminho do arquivo a ser mesclado em relação ao diretório que contém arquivos de configuração de sobreposição.

Usar atributos de manifesto/RROs estáticas

No Android 10 ou versões anteriores, a imutabilidade e a precedência de sobreposição são configuradas usando os seguintes atributos de manifesto.

  • android:isStatic: Quando o valor desse atributo booleano é definido como true, a sobreposição é ativada por padrão e é imutável, o que impede que a sobreposição sejam desativados.

  • android:priority: O valor desse atributo numérico (que afeta apenas sobreposições estáticas) configura a precedência da sobreposição quando vários as sobreposições segmentam o mesmo valor de recurso. Quanto maior o número, maior precedência.

O código abaixo mostra um exemplo 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>

Mudanças no Android 11

No Android 11 ou mais recente, se um arquivo de configuração for localizados em partition/overlay/config/config.xml, as sobreposições são configuradas usando esse arquivo e android:isStatic e android:priority não afetam superposições de dados localizadas na partição. Definir um arquivo de configuração de sobreposição em qualquer a partição aplica a precedência da partição de sobreposição.

Além disso, o Android 11 ou versões mais recentes removem a capacidade usar sobreposições estáticas para afetar os valores de recursos lidos durante o pacote e instalação. Para o caso de uso comum de se usar sobreposições estáticas para alterar o de booleanos que configuram o estado ativado do componente, use o valor Tag SystemConfig <component-override> (nova no Android) 11).

Depurar sobreposições

Para ativar, desativar e despejar sobreposições manualmente, use a seguinte sobreposição gerenciador de shell do Cloud.

adb shell cmd overlay

OverlayManagerService usa idmap2 para mapear IDs de recursos no destino. aos IDs de recursos no pacote de sobreposição. Os mapeamentos de ID gerados são armazenada em /data/resource-cache/. Se sua sobreposição não estiver funcionando corretamente, encontre o arquivo idmap correspondente para sua sobreposição em /data/resource-cache/ e, em seguida, execute o comando a seguir.

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

Esse comando imprime o mapeamento de recursos conforme mostrado abaixo.

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