Escolha as bibliotecas com cuidado

Para ativar a otimização de apps, use bibliotecas compatíveis com a otimização do Android. Se uma biblioteca não estiver configurada para otimização do Android, por exemplo, se ela usar reflexão sem agrupar regras de manutenção associadas, talvez ela não seja adequada para um app Android. Esta página explica por que algumas bibliotecas são mais adequadas para otimização de apps e oferece dicas gerais para ajudar você a escolher.

Preferir codegen em vez de reflexão

Em geral, escolha bibliotecas que usam geração de código (codegen) em vez de reflexão. Com a geração de código, o otimizador pode determinar mais facilmente qual código é realmente usado durante a execução e qual pode ser removido. Pode ser difícil saber se uma biblioteca usa codegen ou reflexão, mas há alguns sinais. Consulte as dicas para ajuda.

Para mais informações sobre codegen x reflexão, consulte Otimização para autores de bibliotecas.

Dicas gerais ao escolher bibliotecas

Use estas dicas para garantir que suas bibliotecas sejam compatíveis com a otimização de apps.

Verificar problemas de otimização

Ao considerar uma nova biblioteca, consulte o rastreador de problemas e as discussões on-line para verificar se há problemas relacionados à minificação ou à configuração da otimização do app. Se houver, tente procurar alternativas para essa biblioteca. Vale lembrar o seguinte:

  • As bibliotecas do AndroidX e bibliotecas como o Hilt funcionam bem com a otimização de apps porque usam codegen em vez de reflexão. Quando usam reflexão, eles fornecem regras de manutenção mínimas para manter apenas o código necessário.
  • As bibliotecas de serialização usam reflexão com frequência para evitar código boilerplate ao instanciar ou serializar objetos. Em vez de abordagens baseadas em reflexão (como Gson para JSON), procure bibliotecas que usam codegen para evitar esses problemas, por exemplo, usando Kotlin Serialization (link em inglês).
  • Evite bibliotecas que incluem regras de manutenção em todo o pacote, se possível. As regras de manutenção em todo o pacote podem ajudar a resolver erros, mas as regras de manutenção amplas precisam ser refinadas para manter apenas o código necessário. Para mais informações, consulte Adotar otimizações de forma incremental.
  • As bibliotecas não devem exigir que você copie e cole regras de manutenção da documentação em um arquivo no seu projeto, principalmente regras de manutenção em todo o pacote. Essas regras se tornam um fardo de manutenção para o desenvolvedor de apps a longo prazo e são difíceis de otimizar e mudar com o tempo.

Ativar a otimização depois de adicionar uma nova biblioteca

Ao adicionar uma nova biblioteca, ative a otimização depois e verifique se há erros. Se houver erros, procure alternativas para essa biblioteca ou escreva regras de manutenção. Se uma biblioteca não for compatível com a otimização, registre um bug com essa biblioteca.

As regras são cumulativas

As regras de retenção são cumulativas. Isso significa que algumas regras incluídas em uma dependência de biblioteca não podem ser removidas e podem afetar a compilação de outras partes do app. Por exemplo, se uma biblioteca incluir uma regra para desativar as otimizações de código, essa regra desativará as otimizações do projeto inteiro.

Verificar o uso de reflexão (avançado)

É possível saber se uma biblioteca usa reflexão inspecionando o código dela. Se a biblioteca usar reflexão, verifique se ela fornece regras de manutenção associadas. Uma biblioteca provavelmente usa reflexão se fizer o seguinte:

  • Usa classes ou métodos dos pacotes kotlin.reflect ou java.lang.reflect.
  • Usa as funções Class.forName ou classLoader.getClass
  • Lê anotações no ambiente de execução, por exemplo, se armazena um valor de anotação usando val value = myClass.getAnnotation() ou val value = myMethod.getAnnotation() e depois faz algo com value.
  • Chama métodos usando o nome do método como uma string. Por exemplo:

    // Calls the private `processData` API with reflection
    myObject.javaClass.getMethod("processData", DataType::class.java)
    ?.invoke(myObject, data)
    

Filtrar regras de retenção inválidas (avançado)

Evite bibliotecas com regras de manutenção que retêm código que realmente precisa ser removido. Mas, se você precisar usá-las, filtre as regras, conforme mostrado no código a seguir:

// If you're using AGP 8.4 and higher
buildTypes {
    release {
        optimization.keepRules {
          it.ignoreFrom("com.somelibrary:somelibrary")
        }
    }
}

// If you're using AGP 7.3-8.3
buildTypes {
    release {
        optimization.keepRules {
          it.ignoreExternalDependencies("com.somelibrary:somelibrary")
        }
    }
}

Estudo de caso: por que o Gson falha com otimizações

Gson é uma biblioteca de serialização que geralmente causa problemas com a otimização de apps porque usa muito a reflexão. O snippet de código a seguir mostra como o Gson é normalmente usado, o que pode causar falhas com facilidade durante a execução. Observe que, quando você usa o Gson para receber uma lista de objetos User, não chama o construtor nem passa uma fábrica para a função fromJson(). Construir ou consumir classes definidas pelo app sem uma das seguintes opções é um sinal de que uma biblioteca pode estar usando reflexão aberta:

  • Classe de app que implementa uma biblioteca, uma interface padrão ou uma classe
  • Plug-in de geração de código, como o KSP
class User(val name: String)
class UserList(val users: List<User>)

// This code runs in debug mode, but crashes when optimizations are enabled
Gson().fromJson("""[{"name":"myname"}]""", User::class.java).toString()

Quando o R8 analisa esse código e não vê o UserList ou o User instanciado em nenhum lugar, ele pode renomear campos ou remover construtores que não parecem ser usados, causando falhas no app. Se você estiver usando outras bibliotecas de maneira semelhante, verifique se elas não vão interferir na otimização do app e, se isso acontecer, evite usá-las.

O Room e o Hilt criam tipos definidos pelo app, mas usam a geração de código para evitar a necessidade de reflexão.