Как сократить и оптимизировать код Unity с помощью R8

Хотя основная логика игры в Unity написана на C# (скомпилирована с помощью IL2CPP), сборки Android включают значительный объем байт-кода Java и Kotlin (classes.dex) для обработки событий жизненного цикла UnityPlayerActivity, сервисов Google Play, платежей, рекламы и SDK социальных сетей.

Включите R8 – стандартный инструмент для сокращения и оптимизации кода в плагине Android Gradle (AGP). Он удаляет неиспользуемые классы и методы и оптимизирует байт-код. Это не только уменьшает размер скачиваемого приложения, но и снижает объем потребляемой памяти для страниц DEX, сопоставленных с памятью (mmap), и базовых процессов Java. В результате снижается нагрузка на физическую память и уменьшается количество принудительных остановок из-за нехватки памяти. Google Play также отслеживает уровень оптимизации DEX-файлов игры с помощью показателя Оптимизация DEX-кода в Android Vitals.

Режим работы по умолчанию и поддержка версий Unity

В Unity минификация кода по умолчанию отключена (false) как для рабочих, так и для отладочных сборок при создании нового проекта.

Впервые R8 был представлен в Unity 2020.1.0f1 как необязательный переключатель. Начиная с версии Unity 2022.2.0f1 (и в бэкпорте Unity 2021.3.41f1 LTS) в Unity обновлен встроенный набор инструментов до AGP 7.1.2+, удалена поддержка устаревшего ProGuard и используется только R8, если включена минификация.

Версия Unity Пакетный AGP Выпуск по умолчанию Поддержка R8 и необходимая конфигурация
2019.4 LTS и более ранние версии Ранние версии (до 3.4) Отключено (false) Не поддерживается (только устаревший ProGuard).
2020.1.0f1–2021.3.40f1 3,4–4,0 Отключено (false) Необязательно (по умолчанию используется ProGuard). Включите параметры Minify > Release (Минификация > Выпуск) и Use R8 (Использовать R8).
2021.3.41f1 и более поздние версии (2021 LTS) 7.1 и более поздних версий Отключено (false) Только R8. Чтобы R8 запускался автоматически, включите параметр Minify (Минификация) > Release (Выпуск).
2022.2.0f1 – Unity 6+ 7.1–8.x Отключено (false) Только R8. Чтобы R8 запускался автоматически, включите параметр Minify (Минификация) > Release (Выпуск).

Включите R8 в настройках проигрывателя

Чтобы включить сокращение и оптимизацию кода R8 для конечных сборок:

  1. В Unity Editor выберите Edit (Редактировать) > Project Settings (Настройки проекта) и нажмите Player (Проигрыватель).
  2. Выберите вкладку Android и разверните раздел Publishing Settings (Настройки публикации) > Build (Сборка).
  3. В разделе Minify (Минификация) настройте параметры для своей версии Unity:
    • Unity 2021.3.41f1+ и 2022.2.0f1+: выберите Release (Выпуск). Unity автоматически запускает R8 во время выполнения задачи Gradle minifyReleaseWithR8.
    • Unity 2020.1.0f1–2021.3.40f1. Выберите Release (Выпуск) и Use R8 (Использовать R8).

Если вы автоматизируете сборки с помощью скриптов C# Editor, настройте эти свойства через PlayerSettings.Android:

using UnityEditor;

public static class AndroidBuildConfig
{
    public static void EnableR8ForRelease()
    {
        PlayerSettings.Android.minifyRelease = true;

        // Required only in Unity 2020.1.0f1 to 2021.3.40f1 and 2022.1 or earlier
        // (In Unity 2021.3.41f1+ and 2022.2+, R8 is always used when minification is enabled)
#if !UNITY_2022_2_OR_NEWER
        PlayerSettings.Android.minifyWithR8 = true;
#endif
    }
}

Добавьте правила сохранения для JNI и рефлексии

Классы и методы Java, динамически вызываемые из скриптов C# с помощью AndroidJavaClass или AndroidJavaObject, не имеют статических сайтов вызова Java. Без явных правил сохранения R8 может посчитать эти классы неиспользуемыми и удалить или переименовать их.

Чтобы сохранить пользовательские мосты Java:

  1. В разделе Project Settings (Настройки проекта) > Player (Проигрыватель) > Android > Publishing Settings (Настройки публикации) > Build (Сборка) включите параметр Custom Proguard File (Пользовательский файл Proguard).
  2. Откройте созданный файл Assets/Plugins/Android/proguard-user.txt.
  3. Добавьте правила -keep для классов, доступ к которым осуществляется через JNI или которые требуются сторонним плагинам:
# Keep custom Java classes invoked from C# using JNI bridges
-keep class com.example.yourgame.** { *; }

# Keep callback interfaces passed between C# and Java
-keep interface com.example.yourgame.IPluginCallback { *; }

Устранение неполадок

В этом разделе описывается, как устранять распространенные проблемы со сборкой и выполнением при использовании R8 в Unity.

Ошибки сборки: Missing classes detected while running R8

В версиях Unity, использующих AGP 7.0 и выше (2021.3.41f1+ и 2022.2+), R8 выполняет строгие проверки на отсутствие классов. Если сборка завершается с этой ошибкой, проверьте сгенерированный файл missing_rules.txt в выходном каталоге сборки (в Library/Bee/Android/Prj/.../build/outputs/mapping/release/missing_rules.txt или Temp/gradleOut/...) и добавьте необходимые зависимости или правила в proguard-user.txt. Подробнее о том, как настроить сохранение кода…

Совместимость полного режима R8 со сторонними плагинами

В AGP 8.0 и более поздних версиях (Unity 6 и более поздних версиях) по умолчанию включен полный режим R8, который позволяет выполнять более агрессивную оптимизацию. Если устаревший плагин Android не работает во время выполнения из-за проблем с рефлексией, обновите правила ProGuard для плагина или верните R8 в режим совместимости:

  1. В разделе Publishing Settings (Настройки публикации) > Build (Сборка) включите параметр Custom Gradle Properties Template (Пользовательский шаблон свойств Gradle).
  2. Откройте файл Assets/Plugins/Android/gradleTemplate.properties и добавьте следующее свойство:
android.enableR8.fullMode=false