Reduzir e otimizar o código do Unreal Engine com o R8

Embora a lógica principal do jogo no Unreal Engine seja escrita em C++ ou Blueprints, o empacotamento do Android compila o bytecode Java e Kotlin (classes.dex) para processar eventos de ciclo de vida do GameActivity, o Google Play Services, o faturamento, o áudio e os plug-ins de análise.

O R8, o redutor e otimizador de código padrão no Plug-in do Android para Gradle (AGP), remove classes e métodos não utilizados e otimiza o bytecode. Isso não apenas diminui o tamanho do download do pacote, mas também reduz o consumo de memória em tempo de execução das páginas DEX mapeadas na memória (mmap) e a sobrecarga do processo Java de referência, mitigando a pressão da memória física e as finalizações do low memory killer (LMK). O Google Play também monitora os níveis de otimização de DEX do seu jogo com a métrica Otimização de código DEX no Android vitals.

Comportamento padrão e suporte à versão do Unreal Engine

A partir do UE 4.22.0, o UEDeployAndroid.cs do Unreal Engine injeta minifyEnabled true na configuração do build de lançamento do Android gerada (buildAdditions.gradle) por padrão. Como o UE 4.25 fez upgrade do conjunto de ferramentas incluído para o AGP 4.0.0, o R8 está ativado por padrão (true) em todos os builds de lançamento (envio e distribuição) no UE 4.25 e versões mais recentes sem configuração adicional.

Versão do Unreal Engine AGP em pacote Versão padrão Depurar padrão Comportamento
UE 4.21 e anteriores Gradle ou Ant legados Desativado (false) Desativado (false) Nenhuma configuração de minifyEnabled foi injetada pelo mecanismo.
UE 4.22 a 4.24 Anterior à 3.4 Ativado (ProGuard) Desativado (false) minifyEnabled true ativado por padrão em builds de lançamento (executa o ProGuard).
UE 4.25 a 5.3 4.0.0 Ativado (R8) Desativado (false) A adoção do AGP 4.0 executa o R8 por padrão em builds de lançamento.
UE 5.4 a 5.7 7.4.2 Ativado (R8) Desativado (false) O AGP 7.x remove as opções legadas do useProguard. O R8 é executado exclusivamente.
UE 5.8 (5.8.3+) 8.13.0 Ativado (R8) Desativado (false) Usa o AGP 8.x e pipelines de otimização modernos do R8 por padrão.

Diferenças entre builds de lançamento e de depuração

A UnrealBuildTool (UEDeployAndroid.cs) configura o arquivo buildAdditions.gradle gerado de maneira diferente para builds de lançamento e de depuração:

buildTypes {
    release {
        signingConfig signingConfigs.release
        minifyEnabled true
        proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
    }
    debug {
        debuggable true
        signingConfig signingConfigs.debug
    }
}
  • Versão (envio ou distribuição): define minifyEnabled true e aplica proguard-rules.pro por padrão, executando a redução e a ofuscação de código do R8.
  • Depuração (desenvolvimento): ativa debuggable true e omite minifyEnabled (o padrão é false) para preservar a iteração de build rápida e a depuração de símbolos.

Adicionar regras de manutenção usando a Unreal Plugin Language (UPL)

Como o R8 é executado automaticamente em builds de lançamento no UE 4.25 e versões mais recentes, é necessário preservar as classes Java acessadas apenas pela JNI do C++ (JNIEnv->FindClass, GetMethodID) ou pelo manifesto. As classes sem sites de chamada Java são tratadas como não usadas e removidas pelo R8, o que pode fazer com que os recursos que funcionam em builds de desenvolvimento falhem com ClassNotFoundException ou NoSuchMethodError em builds de envio.

Use a tag <proguardAdditions> em um arquivo XML da Unreal Plugin Language (UPL) para mesclar regras de manutenção personalizadas em proguard-rules.pro durante o empacotamento. Adicione o seguinte bloco ao arquivo *_UPL.xml do projeto ou plug-in:

<root xmlns:android="http://schemas.android.com/apk/res/android">
    <proguardAdditions>
        <insert>
            -keep class com.epicgames.unreal.** { *; }
            -keep class com.example.plugin.** { public *; }
            -dontwarn com.example.plugin.**
        </insert>
    </proguardAdditions>
</root>

Solução de problemas comuns

Nesta seção, descrevemos como resolver problemas comuns de empacotamento e de ambiente de execução ao usar o R8 no Unreal Engine.

Desativar temporariamente o R8 para depuração

Para isolar se uma falha exclusiva da versão é causada pela remoção de classes necessárias pelo R8, insira DISABLE_MINIFY=1 em <gradleProperties> no arquivo UPL. Quando presente, UEDeployAndroid.cs gera minifyEnabled false:

<gradleProperties>
    <insert>
        DISABLE_MINIFY=1
    </insert>
</gradleProperties>

Missing classes detected while running R8 erro de empacotamento

No UE 5.4 e versões mais recentes (AGP 7.4.2+), o R8 aplica verificações rigorosas de classes ausentes. Se o empacotamento falhar com esse erro, inspecione missing_rules.txt no diretório de build intermediário (em Intermediate/Android/.../gradle/app/build/outputs/mapping/release/missing_rules.txt) e adicione as dependências de biblioteca ausentes ou as regras necessárias a <proguardAdditions> no arquivo UPL.

Compatibilidade do modo completo do R8 com SDKs de terceiros

No UE 5.8 e versões mais recentes (AGP 8.13.0+), o modo completo do R8 é ativado por padrão para realizar otimizações mais agressivas. Se um SDK do Android legado de terceiros falhar no ambiente de execução devido a problemas de reflexão, atualize as regras do ProGuard do plug-in ou reverta o R8 para o modo de compatibilidade adicionando a seguinte propriedade ao arquivo UPL:

<gradleProperties>
    <insert>
        android.enableR8.fullMode=false
    </insert>
</gradleProperties>