Uma sobreposição de recursos de tempo de execução (RRO) é um pacote que muda os valores de recursos de um pacote de destino durante a execução. Por exemplo, um app instalado na imagem do sistema pode mudar o comportamento com base no valor de um recurso. Em vez de codificar o valor do recurso no momento da build, uma RRO instalada em uma partição diferente pode mudar os valores dos recursos do app no ambiente de execução.
As RROs podem ser ativadas ou desativadas. É possível definir programaticamente o estado de ativação/desativação para alternar a capacidade de um RRO de mudar valores de recursos. As RROs são desativadas por padrão. No entanto, as RROs estáticas são ativadas por padrão.
Recursos de sobreposição
As sobreposições funcionam mapeando recursos definidos no pacote de sobreposição para recursos definidos no pacote de destino. Quando um app tenta resolver o valor de um recurso no pacote de destino, o valor do recurso de sobreposição ao qual o recurso de destino está mapeado é retornado.
Configurar o manifesto
Um pacote é considerado um pacote RRO se contiver uma tag <overlay>
como filha da tag <manifest>
.
O valor do atributo obrigatório
android:targetPackage
especifica o nome do pacote que o RRO pretende substituir.O valor do atributo opcional
android:targetName
especifica o nome do subconjunto de recursos sobreponíveis do pacote de destino que a RRO pretende sobrepor. Se o destino não definir um conjunto de recursos sobreponíveis, esse atributo não deverá estar presente.
O código a seguir mostra um exemplo de 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>
As sobreposições não podem sobrepor o código e, portanto, não podem ter arquivos DEX. Além disso, o atributo
android:hasCode
da tag <application
> no manifesto precisa ser
definido 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 diretório res/xml
do pacote de sobreposição, enumerar os recursos de destino que devem ser
substituídos e os valores de substituição e definir o valor do atributo
android:resourcesMap
da tag de manifesto <overlay>
como uma referência
ao arquivo de mapeamento de recursos.
O código a seguir 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 do Soong para
sobreposições que impede que o Android Asset Packaging Tool 2 (AAPT2) tente
remover configurações duplicadas de recursos com o mesmo valor
(--no-resource-deduping
) e remover recursos sem configurações
padrão (--no-resource-removal
). O código a seguir mostra um exemplo de 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 consultado, o tempo de execução de recursos vai retornar o valor da configuração que melhor corresponde à configuração do dispositivo. Para determinar qual configuração é a melhor correspondente, mescle o conjunto de configurações de recursos de sobreposição com o conjunto de configurações de recursos de destino e siga o fluxo normal de resolução de recursos. Para mais detalhes, consulte Como o Android encontra o recurso mais adequado.
Por exemplo, se uma sobreposição definir um valor para a configuração drawable-en
e o destino definir um valor para drawable-en-port
, drawable-en-port
terá uma correspondência melhor. Assim, o valor da configuração de destino drawable-en-port
será escolhido no ambiente 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 os próprios recursos, com comportamentos diferentes entre versões do Android.
No Android 11 ou versões mais recentes, cada sobreposição tem seu próprio espaço de ID de recurso reservado que não se sobrepõe ao espaço de ID de recurso de destino ou a outros espaços de ID de recurso de sobreposição. Assim, as sobreposições que fazem referência aos próprios recursos funcionam como esperado.
No Android 10 ou versões anteriores, as sobreposições e os pacotes de destino compartilham o mesmo espaço de ID de recurso, o que pode causar colisões e comportamento inesperado quando tentam referenciar os próprios recursos usando a sintaxe
@type/name
.
Ativar/desativar sobreposições
As sobreposições podem ser ativadas/desativadas manualmente e de forma programática.
Desativar ou ativar manualmente as sobreposições
Para ativar e verificar manualmente um RRO, execute:
adb shell cmd overlay enable --user current com.example.carrro
adb shell cmd overlay list --user current | grep -i com.example com.example.carrro
Isso ativa a RRO para o usuário do sistema (userId = 0
) que possui a SystemUI.
Esta instrução não afeta os apps iniciados pelo usuário em primeiro plano
(userId = 10
). Para ativar o RRO para o usuário em primeiro plano, use o
parâmetro -–user 10
:
adb shell cmd overlay enable --user 10 com.example.carrro
Ativar ou desativar sobreposições de forma programática
Use a API OverlayManager
para ativar e desativar sobreposições mutáveis (recupere a interface da API usando Context#getSystemService(Context.OVERLAY_SERVICE)
). Uma sobreposição só pode ser ativada pelo pacote a que se destina ou por um pacote com a permissão android.permission.CHANGE_OVERLAY_PACKAGES
. Quando uma sobreposição é
ativada ou desativada, os eventos de mudança de configuração são propagados para o pacote de destino
e as atividades de destino são reiniciadas.
Restringir recursos sobreponíveis
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 de arquivo res/values/overlayable.xml
a seguir, string/foo
e integer/bar
são recursos usados para estilizar a aparência do dispositivo. Para substituir esses recursos, uma substituição precisa segmentar explicitamente a coleção de recursos substituíveis 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 uma precisa ter um nome exclusivo no pacote. Por exemplo, ele é:
É permitido que dois pacotes diferentes definam
<overlayable name="foo">
.Não é permitido que um único APK tenha dois blocos
<overlayable name="foo">
.
O código a seguir mostra um exemplo de sobreposição no arquivo 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 segmentam esse app:
É necessário especificar
targetName
.Só pode substituir os recursos listados na tag
<overlayable>
.Só é possível segmentar um nome de
<overlayable>
.
Não é possível ativar uma sobreposição segmentando um pacote que expõe recursos
sobreponíveis, mas não usa android:targetName
para segmentar uma tag
<overlayable>
específica.
Restringir políticas
Use a tag <policy>
para aplicar restrições aos recursos sobreponíveis. O atributo
type
especifica quais políticas uma sobreposição precisa atender para substituir
os recursos incluídos. Os tipos compatíveis incluem:
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 de 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 named-actor na configuração do sistema.config_signature
. Qualquer sobreposição assinada com a mesma assinatura do APK overlay-config pode substituir os recursos. A overlay-config é declarada na tag overlay-config-signature na configuração do sistema.
O código a seguir mostra um exemplo de tag <policy>
no
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 delas para substituir os recursos listados na tag <policy>
.
Configurar sobreposições
O Android oferece suporte a diferentes mecanismos para configurar a mutabilidade, o estado padrão e a prioridade das sobreposições, dependendo da versão do Android.
Dispositivos com Android 11 ou versões mais recentes podem usar um arquivo
OverlayConfig
(config.xml
) em vez de atributos de manifesto. Usar um arquivo de sobreposição é o método recomendado para sobreposições.Todos os dispositivos podem usar atributos de manifesto (
android:isStatic
eandroid:priority
) para configurar RROs estáticos.
Usar OverlayConfig
No Android 11 ou versões mais recentes, é possível 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 da
sobreposição a ser configurada. Para ser configurada, uma sobreposição precisa estar no
diretório overlay/
da partição em que ela está configurada. 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>
exige um atributo package
que indica qual pacote de
sobreposição está sendo configurado. O atributo opcional enabled
controla se a sobreposição está ativada por padrão (o padrão é false
). O atributo opcional mutable
controla se a sobreposição é mutável e se o estado ativado dela pode ser alterado de forma programática durante a 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 de sobreposição
Quando várias substituições substituem os mesmos recursos, a ordem delas é importante. Uma sobreposição tem maior precedência do que outras com configurações anteriores à dela. A ordem de precedência das sobreposições em diferentes partições (da 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 na posição especificada 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áticos
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 comotrue
, a sobreposição é ativada por padrão e é imutável, o que impede que ela seja desativada.android:priority
. O valor desse atributo numérico (que afeta apenas sobreposições estáticas) configura a precedência da sobreposição quando várias sobreposições estáticas têm como destino o mesmo valor de recurso. Um número maior indica uma precedência maior.
O código a seguir 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 estiver
localizado em partition/overlay/config/config.xml
, as sobreposições serão configuradas usando
esse arquivo, e android:isStatic
e android:priority
não terão efeito nas
sobreposições localizadas na partição. Definir um arquivo de configuração de sobreposição em qualquer
partição impõe a precedência da partição de sobreposição.
Além disso, o Android 11 ou versões mais recentes removem a capacidade
de usar sobreposições estáticas para afetar os valores de recursos lidos durante a instalação
de pacotes. Para o caso de uso comum de usar sobreposições estáticas para mudar o
valor de booleanos que configuram o estado ativado do componente, use a
tag <component-override>
SystemConfig
(nova no Android
11).
Sobreposições de depuração
Para ativar, desativar e despejar sobreposições manualmente, use o seguinte comando de shell do gerenciador de sobreposições.
adb shell cmd overlay
Usar enable
sem especificar um usuário afeta o usuário atual, ou seja, o usuário do sistema (userId = 0
), que é proprietário da interface do sistema. Isso não afeta o usuário em primeiro plano (userId = 10
), que é o proprietário dos apps. Para ativar o RRO para o usuário em primeiro plano, use o parâmetro –-user 10
:
adb shell cmd overlay enable --user 10 com.example.carrro
O OverlayManagerService
usa o idmap2
para mapear IDs de recursos no pacote
de destino para IDs de recursos no pacote de sobreposição. Os mapeamentos de ID gerados são
armazenados em /data/resource-cache/
. Se a sobreposição não estiver funcionando corretamente, encontre
o arquivo idmap
correspondente em /data/resource-cache/
e
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