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 tem suporte.
  • 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 ou mais recente (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 você quiser manter ou descartar recursos específicos, crie um arquivo XML keep nos recursos do projeto, por exemplo, res/raw/keep_my_package.xml. O arquivo de manutenção 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" />

Especificar quais recursos descartar pode parecer supérfluo quando você pode excluí-los. No entanto, descartar recursos 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 keep_my_package_build_variant.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 for removido pelo encolhedor), mas você sabe que ele não será usado para a variante de build especificada.

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 idioma traduzidas para as mensagens nessas bibliotecas, independentemente de o restante do app estar traduzido ou não para os mesmos idiomas. Para manter apenas os idiomas que o app oficialmente oferece suporte, especifique-os usando a propriedade resConfigs. Os 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, apenas os idiomas configurados no dispositivo de um usuário são baixados quando ele instala o app. Da mesma forma, apenas os recursos que correspondem à densidade de tela do dispositivo e as bibliotecas nativas que correspondem à 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), é possível personalizar a densidade da tela ou os recursos de ABI para incluir no APK criando vários APKs que segmentam diferentes configurações de dispositivo.

Evitar conflitos ao mesclar recursos

Por padrão, o plug-in do Android para Gradle (AGP) mescla recursos com nomes idênticos, como elementos gráficos 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 nome que seu código está referenciando.

A mesclagem de recursos só ocorre quando dois ou mais arquivos compartilham um nome, tipo e qualificador de recurso idênticos. O AGP seleciona o arquivo que identifica como a melhor opção entre os duplicados (com base em uma ordem de prioridade descrita abaixo) e transmite apenas esse recurso para o 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 do projeto de biblioteca

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 aparecer nos recursos principais e em uma variante de build, o Gradle vai selecionar o recurso na variante.

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 referenciam outros recursos 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. Talvez ele seja referenciado em outro recurso:

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, você precisa saber por que @drawable/add_schedule_fab_icon_anim está acessível. Se você pesquisar para cima, vai encontrar o recurso listado no título Os recursos acessíveis da raiz são: em resources.txt.

Isso significa que há uma referência de código a 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 estrita, os IDs de recursos podem ser marcados como acessíveis se houver constantes de string que pareçam 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 de manutenção para instruir o sistema de build a remover o recurso.