Personalize quais recursos manter

Quando você ativa a otimização de apps, o comportamento padrão do otimizador é diferente para diferentes versões do R8.

  • Com a DSL atualizada, disponível no AGP 9.3 e versões mais recentes, a redução de recursos é ativada por padrão quando a otimização está ativada. A DSL legada, que exige que a otimização de código e recursos seja ativada de forma distinta, ainda é compatível.
  • Para versões anteriores ao AGP 9.3, 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, também defina isMinifyEnabled = true.

AGP 9.3+ (Kotlin)

buildTypes {
    release {
        optimization {
            enable = true // Enables code and resource optimizations.
        }
    }
}

AGP 9.3+ (Groovy)

buildTypes {
    release {
        optimization {
            enable = true // Enables code and resource optimizations.
        }
    }
}

DSL legada (Kotlin)

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

DSL legada (Groovy)

buildTypes {
    release {
        minifyEnabled = true
        shrinkResources = true
        ...
    }
}

Se 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 de permanência 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 asterisco como um caractere 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 bobagem especificar quais recursos descartar quando se poderia simplesmente excluí-los, mas essa ferramenta pode ser útil ao usar variantes de build.

Segmentar variantes de build específicas

Para remover recursos apenas em algumas variantes de build, coloque todos os recursos no diretório comum do projeto 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 de preservação, especifique manualmente os recursos a serem removidos quando um determinado recurso parecer ser usado no código (e, portanto, não removido pelo redutor), mas você sabe que ele não será usado para a variante de build especificada.

Remover recursos alternativos não utilizados

O otimizador remove apenas os recursos nã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 idioma traduzidas para as mensagens nessas bibliotecas, independentemente do restante do app estar traduzido ou não para os mesmos idiomas. Para manter apenas os idiomas com os quais o app é oficialmente compatível, use a propriedade resConfigs para especificá-los. Os recursos para idiomas não especificados serão removidos.

Os snippets a seguir mostram como limitar seus recursos de idioma para apenas 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 de um usuário são baixados quando ele instala o app. Da mesma forma, apenas os recursos correspondentes à densidade de 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 da ABI que serão incluídos no seu APK criando vários APKs para diferentes configurações de dispositivos.

Evitar conflitos ao mesclar recursos

Por padrão, o Plug-in do Android para Gradle (AGP) mescla recursos com nomes idênticos, como drawables com o mesmo nome que estão em pastas de recursos diferentes. Esse comportamento não é controlado pela propriedade shrinkResources e não pode ser desativado porque é 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 e qualificador de recurso idêntico. O AGP seleciona o arquivo que considera ser a melhor opção entre os duplicados (com base em uma 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, dos tipos de build e variações de build
  • Dependências do projeto de biblioteca

O AGP combina os recursos duplicados na seguinte ordem de prioridade (crescente):

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 vai 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/ tiverem 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 usados 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 dele. 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, verá que esse recurso está listado no título The root reachable resources are: em 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 strings que pareçam poder ser usadas para construir nomes para recursos dinamicamente carregados. 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 de manutenção para instruir o sistema de build a remover o recurso.