Skip to content

Most visited

Recently visited

navigation

Reduza seus códigos e recursos

Para que o arquivo APK seja o menor possível, ative a redução para remover códigos e recursos não utilizados da sua compilação de lançamento. Esta página descreve como fazer isso e como especificar quais códigos e recursos devem ser mantidos ou descartados durante a compilação.

O recurso de redução de código é disponibilizado pelo ProGuard, que detecta e remove classes, campos, métodos e atributos não utilizados do aplicativo empacotado, incluindo elementos adicionados de bibliotecas de códigos (o que o torna uma ferramenta valiosa para superar o limite de 64 mil referências). O ProGuard também otimiza o bytecode, remove instruções de códigos não utilizados e ofusca as classes, os campos e os métodos restantes com nomes curtos. O código ofuscado dificulta a engenharia inversa do seu APK, o que é especialmente importante quando seu aplicativo utiliza recursos que exigem segurança, como a verificação de licenças.

A redução de recursos é disponibilizada pelo Android Plugin para Gradle, que remove os recursos não utilizados do aplicativo empacotado, incluindo os que estiverem em bibliotecas de código. Ele trabalha em conjunto com a redução de código, de forma que, depois que um código não utilizado é removido, qualquer recurso não referenciado também pode ser removido com segurança.

Os recursos mencionados neste documento exigem:

Reduza seus códigos

Para ativar a redução de código com o ProGuard, adicione minifyEnabled true ao tipo de compilação apropriado no arquivo build.gradle.

Esteja ciente de que a redução de código torna o tempo de compilação mais lento, portanto evite usar esse recurso na sua compilação de depuração se possível. Entretanto, é importante ativar a redução de código no APK final para teste, pois ele pode introduzir erros se você não personalizar quais códigos manter de forma eficiente.

Por exemplo, o snippet de um arquivo build.gradle a seguir ativa a redução de código para a compilação de lançamento:

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

Observação: o Android Studio desativa o ProGuard quando usa o Instant Run. Se você precisar da redução de código em compilações incrementais, experimente o redutor experimental do Gradle.

Além da propriedade minifyEnabled, a propriedade proguardFiles define as regas do ProGuard:

Para adicionar mais regras do ProGuard específicas de cada variação de compilação, adicione outra propriedade proguardFiles no bloco productFlavor correspondente. Por exemplo, o arquivo do Gradle a seguir adiciona flavor2-rules.pro à variação do produto flavor2. Agora, flavor2 usa todas as três regras do ProGuard porque as do bloco release também são aplicadas.

android {
    ...
    buildTypes {
        release {
            minifyEnabled true
            proguardFiles getDefaultProguardFile('proguard-android.txt'),
                   'proguard-rules.pro'
        }
    }
    productFlavors {
        flavor1 {
        }
        flavor2 {
            proguardFile 'flavor2-rules.pro'
        }
    }
}

Com cada compilação o ProGuard gera os seguintes arquivos:

dump.txt
Descreve a estrutura interna de todos os arquivos de classe no APK.
mapping.txt
Fornece uma conversão entre os nomes original e ofuscado da classe, do método e do campo.
seeds.txt
Lista as classes e os membros que não foram ofuscados.
usage.txt
Lista os códigos que foram removidos do APK.

Esses arquivos são salvos em <module-name>/build/outputs/mapping/release/.

Personalize quais códigos manter

Para algumas situações, o arquivo de configuração padrão do ProGuard (proguard-android.txt) é suficiente e o ProGuard remove todo (e somente) o código não utilizado. Entretanto, muitas situações são difíceis para o ProGuard analisar corretamente e ele pode remover códigos dos quais seu aplicativo precisa. Alguns dos exemplos de quando códigos podem ser removidos por engano incluem:

Os testes do aplicativo devem revelar todos os erros causados por código removido indevidamente, mas você também pode inspecionar o código removido examinando o arquivo de saída usage.txt salvo em <module-name>/build/outputs/mapping/release/.

Para corrigir erros e forçar o ProGuard a manter código específico, adicione uma linha -keep ao arquivo de configuração do ProGuard. Por exemplo:

-keep public class MyClass

Como alternativa, você pode adicionar a anotação @Keep ao código que deseja manter. A adição de @Keep a uma classe mantém a classe inteira como está. Adicioná-la a um método ou campo manterá esse método ou campo (e seu nome), além do nome da classe, intacto. Observe que essa anotação só está disponível quando você estiver usando a biblioteca de suporte a anotações.

Há muitos fatores a serem considerados para usar a opção -keep. Para saber mais sobre como personalizar o arquivo de configuração, leia o Manual do ProGuard. A seção Solução de problemas descreve outros problemas comuns que você pode encontrar quando seu código for removido.

Decodifique e ofusque o rastreamento de pilha

Depois que o ProGuard reduz seu código, é difícil (se não impossível) ler um rastreamento de pilha, pois os nomes dos métodos ficam ofuscados. Felizmente, o ProGuard cria um arquivo mapping.txt sempre que é executado, mostrando os nomes originais das classes, dos métodos e dos campos associados aos nomes ofuscados. O ProGuard salva o arquivo no diretório <module-name>/build/outputs/mapping/release/ do aplicativo.

Note que o arquivo mapping.txt será substituído sempre que você criar uma compilação de lançamento com o ProGuard. Portanto, salve uma cópia sempre que publicar uma nova versão. A retenção de uma cópia do arquivo mapping.txt para cada compilação de lançamento permitirá depurar o problema quando um usuário enviar um rastreamento de pilha ofuscado de uma versão anterior do aplicativo.

Quando publicar o aplicativo no Google Play, você poderá fazer o upload do arquivo mapping.txt para cada versão do APK. O Google Play desofuscará os rastreamentos de pilha recebidos de problemas reportados por usuários, assim você poderá analisá-los no Google Play Developer Console. Para saber mais, consulte o artigo da Central de Ajuda sobre como desofuscar rastreamentos de pilha de falhas.

Para converter um rastreamento de pilha ofuscado em um que você possa entender, use o script retrace (retrace.bat no Windows ou retrace.sh no Mac/Linux). Esse script está no diretório <sdk-root>/tools/proguard/. O script usa o arquivo mapping.txt e seu rastreamento de pilha e gera um rastreamento de pilha legível. A sintaxe para usar a ferramenta retrace é:

retrace.bat|retrace.sh [-verbose] mapping.txt [<stacktrace_file>]

Por exemplo:

retrace.bat -verbose mapping.txt obfuscated_trace.txt

Se você não especificar o arquivo do rastreamento de pilha, a ferramenta retrace lerá na entrada padrão.

Ative a redução de código com o Instant Run

Se a redução de código for importante na compilação incremental do aplicativo, tente usar o redutor de código experimental incorporado ao Android Plugin para Gradle. Ao contrário do ProGuard, esse redutor é compatível com o Instant Run.

Você pode configurar o redutor do plug-in do Android usando os mesmos arquivos de configuração do ProGuard. No entanto, o redutor do plug-in do Android não ofusca nem otimiza o código. Ele apenas remove código não utilizado. Portanto, use-o somente para compilações de depuração. Nas compilações de lançamento, ative o ProGuard para o código do APK de lançamento seja ofuscado e otimizado.

Para ativar o redutor do plug-in do Android, basta definir useProguard como false no tipo de compilação de depuração (e manter minifyEnabled definido como true):

android {
    buildTypes {
        debug {
            minifyEnabled true
            useProguard false
            proguardFiles getDefaultProguardFile('proguard-android.txt'),
                    'proguard-rules.pro'
        }
        release {
            minifyEnabled true
            proguardFiles getDefaultProguardFile('proguard-android.txt'),
                    'proguard-rules.pro'
        }
    }
}

Observação: Se o redutor do plug-in do Android remover inicialmente um método e você fizer uma alteração no código para tornar o método disponível, o Instant Run tratará essa alteração como alteração de código estrutural e executará um cold swap.

Reduza seus recursos

A redução de recurso funciona apenas em conjunto com a redução de código. Depois que o redutor de código remover todos os códigos não utilizados, o redutor de recursos pode identificar quais recursos ainda são usados pelo aplicativo. Isso é válido especialmente ao adicionar bibliotecas de códigos que contêm recursos — é necessário remover o código não utilizado da biblioteca para que as referências aos recursos da biblioteca sejam removas e, dessa forma, o redutor de recursos possa removê-los.

Para ativar a redução de recursos, defina a propriedade shrinkResources como true no arquivo build.gradle (juntamente com minifyEnabled para a redução de código). Por exemplo:

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

Se você ainda não tiver compilado o aplicativo usando minifyEnabled para reduzir o código, tente fazê-lo antes de ativar shrinkResources, pois pode ser necessário editar o arquivo proguard-rules.pro para manter classes ou métodos criados ou invocados dinamicamente antes de começar a remover recursos.

Observação: no momento, o redutor de recursos não remove recursos definidos em uma pasta values/ (como strings, dimensões, estilos e cores). Isso ocorre porque a Android Asset Packaging Tool (AAPT) não permite que o plug-in do Grade especifique versões predefinidas de recursos. Para obter detalhes, consulte o problema 70869.

Personalize quais recursos manter

Se quiser manter ou descartar recursos específicos, crie um arquivo XML no projeto com uma tag <resources> e especifique os recursos a serem mantidos no atributo tools:keep e os a serem descartados no atributo tools:discard. Os dois atributos aceitam uma lista separada por vírgulas de nomes de recursos. Você pode usar o caractere asterisco como curinga.

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" />

Salve esse arquivo nos recursos do projeto como, por exemplo, em res/raw/keep.xml. A compilação não empacota esse arquivo no APK.

Pode parecer bobagem especificar quais recursos descartar quando se poderia simplesmente exclui-los, mas essa ferramenta pode ser útil ao usar variantes de compilação. Por exemplo, é possível colocar todos os seus recursos no diretório comum do projeto e criar um arquivo keep.xml diferente para cada variação de compilação quando um recurso for aparentemente usado no código (e, portanto, não foi removido pelo redutor), mas você sabe que esse recurso não será usado pela variação de compilação em questão. Também é possível que as ferramentas de compilação identifiquem incorretamente um recurso como necessário. Isso pode acontecer porque o compilador adiciona os IDs de recursos em linha e o analisador de recursos pode desconhecer a diferença entre um recurso realmente referenciado e um valor inteiro no código que tem acidentalmente o mesmo valor.

Ative verificações de referências rígidas

Normalmente, o redutor de recursos pode determinar com precisão se um recurso está sendo usado. No entanto, se o código chamar Resources.getIdentifier() (ou se uma das bibliotecas fizer isso – a biblioteca AppCompat faz), isso significa que código está procurando nomes de recursos com base em strings geradas dinamicamente. Ao fazê-lo, o redutor de recursos se comporta de maneira defensiva por padrão e marca todos os recursos que tenham um formato de nome correspondente como potencialmente utilizado e indisponível para remoção.

O código a seguir, por exemplo, faz com que todos os recursos com o prefixo img_ sejam marcados como utilizados.

String name = String.format("img_%1d", angle + 1);
res = getResources().getIdentifier(name, "drawable", getPackageName());

O redutor de recursos também examina todas as constantes de strings no código, bem como em vários recursos res/raw/, procurando por URLs de recursos com formato semelhante a file:///android_res/drawable//ic_plus_anim_016.png. Se ele encontrar strings como essa ou outras que pareçam poder ser usadas para construir URLs como esse, elas não serão removidas.

Esses são exemplos do modo de redução segura que é ativado por padrão. No entanto, você pode desativar essa abordagem de “melhor prevenir do que remediar” e especificar que o redutor de recursos deve manter apenas os recursos que com certeza estão sendo usados. Para fazer isso, defina shrinkMode como strict no arquivo keep.xml, da seguinte forma:

<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:tools="http://schemas.android.com/tools"
    tools:shrinkMode="strict" />

Se ativar o modo de redução rígida e o código também fizer referência a recursos com strings geradas dinamicamente, como mostrado acima, você deverá manter manualmente esses recursos usando o atributo tools:keep.

Remova recursos alternativos não utilizados

O redutor de recursos do Gradle remove apenas os recursos não referenciados pelo código do seu aplicativo, o que significa que ele não removerá recursos alternativos para diferentes configurações de dispositivo. Se necessário, você pode usar a propriedade resConfigs do plug-in Android do Gradle para remover os arquivos de recursos alternativos não usados pelo aplicativo.

Por exemplo, se você estiver usando uma biblioteca que contenha recursos de idioma (como a AppCompat ou a Google Play Services), seu APK conterá todas as strings de idiomas traduzidas para as mensagens nessas bibliotecas, independentemente do restante do seu aplicativo estar traduzido ou não para os mesmos idiomas. Se quiser manter apenas os idiomas com os quais o aplicativo é oficialmente compatível, use a propriedade resConfig para especificá-los. Quaisquer recursos para idiomas não especificados serão removidos.

O snippet a seguir mostra como limitar seus recursos de idioma para apenas inglês e francês.

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

Da mesma forma, é possível personalizar a densidade da tela ou os recursos de ABI a incluir no seu APK usando divisões de APK para compilar diferentes APKs para diferentes dispositivos.

Mescle recursos duplicados

Por padrão, o Gradle também mescla recursos com nomes idênticos, como drawables com o mesmo nome que possam estar em pastas de recursos diferentes. Esse comportamento não é controlado pela propriedade shrinkResources e não pode ser desativado, pois é necessário para evitar erros quando vários recursos têm o mesmo nome que o código está procurando.

A mesclagem de recursos ocorre apenas quando dois ou mais recursos compartilham um nome, tipo ou qualificador de recurso idêntico. O Gradle seleciona o arquivo que considera ser a melhor escolha entre as duplicadas (com base na ordem de prioridade descrita abaixo) e passa apenas esse recurso para a AAPT para distribuição no arquivo do APK.

O Gradle procura por recursos duplicados nos seguintes locais:

O Gradle mescla 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 compilação, o Gradle seleciona o recurso na variação de compilação.

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

Solucione problemas com a redução de recursos

Quando você reduz recursos, o console do Gradle mostra um recurso dos recursos que removeu do pacote do aplicativo. Por exemplo:

:android:shrinkDebugResources
Removed unused resources: Binary 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). Esse arquivo contém detalhes como quais recursos fazem referência a outros recursos e quais são utilizados ou removidos.

Por exemplo: para descobrir por que @drawable/ic_plus_anim_016 ainda está no APK, 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 precisa saber por que @drawable/add_schedule_fab_icon_anim pode ser alcançado. Se você olhar para cima, verá que esse recurso está listado em "The root reachable resources are:". Isso significa que há uma referência de código para add_schedule_fab_icon_anim (ou seja, seu ID R.drawable foi encontrado em código alcançável).

Se você não estiver usando a verificação rígida, os IDs de recursos podem ser marcados como alcançáveis se houver constantes de strings que pareçam poder ser usadas para construir nomes de recursos para recursos dinamicamente carregados. Nesse caso, se você pesquisar na saída da compilação pelo nome do recurso, você poderá obter uma mensagem como esta:

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

Se vir uma dessas strings e estiver certo de que ela não está sendo usada para carregar dinamicamente o recurso em questão, você poderá usar o atributo tools:discard para instruir o sistema de compilação a removê-lo, conforme descrito na seção sobre como personalizar quais recursos serão mantidos.

This site uses cookies to store your preferences for site-specific language and display options.

Get the latest Android developer news and tips that will help you find success on Google Play.

* Required Fields

Hooray!

Follow Google Developers on WeChat

Browse this site in ?

You requested a page in , but your language preference for this site is .

Would you like to change your language preference and browse this site in ? If you want to change your language preference later, use the language menu at the bottom of each page.

This class requires API level or higher

This doc is hidden because your selected API level for the documentation is . You can change the documentation API level with the selector above the left navigation.

For more information about specifying the API level your app requires, read Supporting Different Platform Versions.

Take a short survey?
Help us improve the Android developer experience.
(Sep 2017 survey)