Personalize quais recursos manter

Quando você ativa a otimização de apps, a configuração isShrinkResources = true instrui o otimizador a remover recursos não utilizados, o que ajuda a reduzir o tamanho do app. A redução de recursos funciona apenas em conjunto com a redução de código. Portanto, se você estiver otimizando recursos, defina também isMinifyEnabled = true, por exemplo:

buildTypes {
    release {
        isMinifyEnabled = true
        isShrinkResources = true
        ...
    }
}

Se você quiser manter ou descartar recursos específicos, crie um arquivo XML keep nos recursos do projeto, por exemplo, res/raw/my.package.keep.xml. O arquivo keep tem os seguintes componentes:

  • Tag <resources>: contém todos os elementos de recursos filhos e atributos de manter/descartar.
  • Atributo tools:keep: aceita uma lista separada por vírgulas de nomes de recursos que identificam os recursos a serem mantidos.
  • Atributo tools:discard: aceita uma lista separada por vírgulas de nomes de recursos que identificam os recursos a serem descartados.

Use o caractere asterisco como curinga para referenciar vários recursos na mesma pasta, por exemplo:

<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:tools="http://schemas.android.com/tools"
    tools:keep="@layout/l_used*_c,@layout/l_used_a,@layout/l_used_b*"
    tools:discard="@layout/unused2" />

Pode parecer desnecessário especificar quais recursos descartar quando você pode excluí-los, mas isso pode ser útil ao usar variantes de build.

Segmentar variantes de build específicas

Para remover recursos em apenas algumas variantes de build, coloque todos os recursos no diretório de projeto comum e crie um arquivo my.package.build.variant.keep.xml diferente para cada variante de build no diretório de recursos da variante. No arquivo keep, especifique manualmente os recursos a serem removidos quando um determinado recurso parecer ser usado no código (e, portanto, não for removido pelo redutor), mas você sabe que ele não será usado para a variante de build.

Remover recursos alternativos não utilizados

O otimizador só remove recursos que não são referenciados pelo código do app, o que significa que ele não remove recursos alternativos para diferentes configurações de dispositivo.

Use a propriedade resConfigs do Gradle para Android no arquivo build.gradle do módulo do app para remover arquivos de recursos alternativos que não são usados pelo app.

Por exemplo, se você estiver usando uma biblioteca que inclua recursos de idioma (como o Google Play Services), seu app vai incluir todas as strings de idiomas traduzidas para as mensagens nessas bibliotecas, independentemente do restante do seu app estar traduzido para os mesmos idiomas ou não. Para manter apenas os idiomas com os quais o app tem suporte oficial, especifique esses idiomas usando a propriedade resConfigs. Quaisquer recursos para idiomas não especificados serão removidos.

Os snippets a seguir mostram como limitar seus recursos de idioma apenas ao inglês e francês:

android {
    defaultConfig {
        ...
        resourceConfigurations.addAll(listOf("en", "fr"))
    }
}

ou

android {
    defaultConfig {
        ...
        resConfigs "en", "fr"
    }
}

Quando você publica um app usando o formato Android App Bundle (AAB), por padrão, somente os idiomas configurados no dispositivo do usuário são transferidos por download quando o usuário instala o app. Da mesma forma, apenas os recursos que correspondem à densidade da tela do dispositivo e as bibliotecas nativas correspondentes à ABI do dispositivo são incluídos no download. Para mais informações, consulte Reativar ou desativar tipos de APKs de configuração.

Para apps legados lançados com APKs (criados antes de agosto de 2021), você pode personalizar a densidade da tela ou os recursos de ABI a serem incluídos no seu APK criando vários APKs voltados a diferentes configurações de dispositivos.

Evitar conflitos ao mesclar recursos

Por padrão, o plug-in do Gradle para Android (AGP) mescla recursos com nomes idênticos, como drawables com o mesmo nome em pastas de recursos diferentes. Esse comportamento não é controlado pela propriedade shrinkResources e não pode ser desativado, porque ele é necessário para evitar erros quando vários recursos têm o mesmo nome que o código está referenciando.

A mesclagem de recursos ocorre apenas quando dois ou mais arquivos compartilham um nome, tipo ou qualificador de recurso idêntico. O AGP seleciona o arquivo que identifica como a melhor escolha entre as cópias (com base na ordem de prioridade descrita abaixo) e transmite apenas esse recurso ao AAPT para distribuição no artefato de build final.

O AGP procura recursos duplicados nos seguintes locais:

  • Recursos principais associados ao conjunto de origem principal, geralmente localizados em src/main/res/
  • Sobreposições de variantes, do tipo e das variações de build
  • Dependências de biblioteca do projeto

O AGP mescla recursos duplicados na seguinte ordem de prioridade em cascata:

Dependências → Principal → Variação de compilação → Tipo de compilação

Por exemplo, se um recurso duplicado aparece tanto nos recursos principais quanto em uma variação de build, o Gradle seleciona o recurso na variação de build.

Se recursos idênticos aparecerem no mesmo conjunto de origem, o Gradle não poderá mesclá-los e emitirá um erro de mesclagem de recursos. Isso pode acontecer se você definir vários conjuntos de origem na propriedade sourceSet do arquivo build.gradle do módulo. Por exemplo, se src/main/res/ e src/main/res2/ contiverem recursos idênticos.

Solucionar problemas com a redução de recursos

Quando você reduz recursos, a janela Build mostra um resumo dos recursos removidos do app. Clique em Toggle view no lado esquerdo da janela para mostrar a saída de texto detalhada do Gradle. Exemplo:

:android:shrinkDebugResources
Removed unused resources: Resource data reduced from 2570KB to 1711KB: Removed 33%
:android:validateDebugSigning

O Gradle também cria um arquivo de diagnóstico chamado resources.txt em <module-name>/build/outputs/mapping/release/ (a mesma pasta dos arquivos de saída do ProGuard). O arquivo inclui detalhes como quais recursos fazem referência a outros e quais são utilizados ou removidos.

Por exemplo: para descobrir por que @drawable/ic_plus_anim_016 ainda está no app, abra o arquivo resources.txt e pesquise o nome desse arquivo. Para descobrir se ele é referenciado em outro recurso, faça o seguinte:

16:25:48.005 [QUIET] [system.out] @drawable/add_schedule_fab_icon_anim : reachable=true
16:25:48.009 [QUIET] [system.out] @drawable/ic_plus_anim_016

Agora é preciso saber por que @drawable/add_schedule_fab_icon_anim está acessível. Se você procurar de baixo para cima, vai encontrar o recurso listado em The root reachable resources are: no resources.txt.

Isso significa que há uma referência de código para add_schedule_fab_icon_anim, ou seja, o ID R.drawable foi encontrado no código acessível.

A menos que você esteja usando a verificação rígida, os IDs de recursos poderão ser marcados como alcançáveis se houver constantes de string que pareçam poder ser usadas para construir nomes de recursos para recursos carregados dinamicamente. Nesse caso, se você pesquisar na saída de build pelo nome do recurso, poderá encontrar uma mensagem como esta:

10:32:50.590 [QUIET] [system.out] Marking drawable:ic_plus_anim_016:2130837506
    used because its format-string matches string pool constant ic_plus_anim_%1$d.

Se você encontrar uma dessas strings e tiver certeza de que ela não está sendo usada para carregar o recurso em questão de forma dinâmica, use o atributo tools:discard no arquivo keep para informar ao sistema de build que o recurso precisa ser removido.