Comprimindo aplicativos com Gradle para Android

David Tiago Conceição
Android Dev BR
Published in
4 min readSep 23, 2015

English version here.

É quase impossível escrever um bom aplicativo para Android sem o uso de muitas bibliotecas. Vários recursos como redes, carregamento de imagens, cache, operações de banco de dados, redes sociais e muitos outros podem ser facilmente incorporados com bibliotecas de diferentes fontes. Isso torna o desenvolvimento muito mais fácil e rápido, mas também traz algumas conseqüências.

O problema

Cada biblioteca adicionada a um projeto traz muitas possibilidades e características. Para conseguir isso, as bibliotecas normalmente contêm uma grande quantidade de arquivos de código e recursos. Quase todas as bibliotecas que eu uso contêm mais recursos do que o que eu preciso. Isso cria uma espécie de resíduo: os aplicativos têm um monte de coisas que nunca são realmente utilizadas. Mais do que isso, o tamanho dos pacotes está crescendo em um ritmo rápido. Um dos aplicativos que eu tenho trabalhado alcançou 6.5MB recentemente. Isso é muito, eu posso fazer melhor.

É uma grande apk.

Entra o Gradle

O plugin Gradle para Android tem algumas opções interessantes para melhorar as aplicações. Uma delas é a opção para diminuir o código-fonte (minify, em inglês). Com essa opção ativada, o tamanho dos arquivos de código fonte será diminído através da alteração dos identificadores e exclusão de trechos de código que não podem ser alcançados. Como consequência, o código fonte também será ofuscado, dificultando a leitura em caso de decompilação. Tudo isso ocorre de maneira automática, nos arquivos gerados para a compilação. Vamos ativá-lo no build.gradle.

//...
buildTypes {
release {
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
signingConfig signingConfigs.release
}
//...

O resultado é um APK de 6.0MB. É um bom começo.

Um pouco melhor.

Resource Shrink

Outra opção interessante do Android Gradle é a redução dos recursos (do inglês shrink resources). Quando esta opção for ativada, os recursos não utilizados são removidos do apk final, reduzindo o seu tamanho. Vamos habilitá-la.

release {
minifyEnabled true
shrinkResources true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
signingConfig signingConfigs.release
}

O resultado é, bem, decepcionante.

Nenhuma mudança no tamanho do arquivo.

Lendo um pouco mais da documentação técnica, existem algumas opções para fazer a compressão mais agressiva. No caso da aplicação que estou trabalhando, a opção resConfigs fez um bom trabalho. Ao criar uma lista de configurações de recursos usadas pelo aplicativo, a ferramenta pode eliminar mais arquivos que nunca serão utilizados.

Este post recomendava o uso de uma opção para restringir também quais configurações de tela suportadas pelo aplicativo. Esta opção foi removida nas versões mais novas do Android Build Tools e substituída pela opção de gerar múltiplas APKs.

resConfigs "en", "pt"
Bem melhor.

Ao diminuir o tamanho do código fonte e remover os recursos não utilizados, a apk foi reduzida de 6.5MB para cerca de 5MB. Essa é uma boa melhora.

Mas não tão rápido

Uma das razões que faz alguns desenvolvedores desativarem a opção de compressão são os problemas que podem ocorrer em tempo de execução. No caso da minha aplicação, as classes do gson não conseguiam efetuar a conversão dos valores retornados pelo servidor. Para fazer isso funcionar, eu tive que adicionar um conjunto de instruções no arquivo proguard-rules.pro. O conjunto inicial pode ser encontrada no repositório gson. Para completar, tive que fazer as ferramentas ignorarem (ou manterem) as classes usadas com o gson na conversão.

-keep class com.package.model.** { *; }

As bibliotecas também têm suas próprias configurações. Glide tem as instruções detalhadas na sua página. Okio, que é usado de uma forma indireta, funciona ignorando as advertências.

-dontwarn okio.**

SnappyDB exige um pouco mais de complexidade.

-dontwarn sun.reflect.**
-dontwarn java.beans.**
-keep,allowshrinking class com.esotericsoftware.** {
<fields>;
<methods>;
}
-keep,allowshrinking class java.beans.** { *; }
-keep,allowshrinking class sun.reflect.** { *; }
-keep,allowshrinking class com.esotericsoftware.kryo.** { *; }
-keep,allowshrinking class com.esotericsoftware.kryo.io.** { *; }
-keep,allowshrinking class sun.nio.ch.** { *; }
-dontwarn sun.nio.ch.**
-dontwarn sun.misc.**
-keep,allowshrinking class com.snappydb.** { *; }
-dontwarn com.snappydb.**

No fim das contas, não há escolha além de pesquisar as configurações específicas para cada biblioteca. O detalhe aqui é prestar atenção a cada uma dessas configurações. Uma das sugestões para fazer o funcionar SnappyDB recomenda desativar a opção minifyEnabled. Isso é algo que não irá acontecer :). Cada vez que uma dessas opções for alterada, verifique o tamanho final da apk e teste possíveis erros de execução.

Indo além

O tamanho da apk provavelmente pode ser reduzido ainda mais. Em algum momento eu irei mais além, seguindo as instruções apresentadas por Cyril Mottier em seu blog, além de outros recursos espalhados pela web. Isso certamente vai consumir mais tempo do que ajustar alguns arquivos de compilação como eu fiz. O resultado desses ajustes iniciais, porém, foi muito bom. Remover 1.5MB de material não utilizado do apk é certamente uma coisa boa. A partir de agora, essas opções ficarão habilitadas em todos os meus projetos e certamente economizarão alguns megabytes.

--

--

David Tiago Conceição
Android Dev BR

Android Application Engineer @ Involves; Admin @ Android Dev Br; Organizer @ GDG Floripa www.androiddevbr.org