ProGuard/R8 mapping: деобфускация Android крашей
Вы получаете краш a.b.c.d.e(Unknown Source:12) в Crashlytics и не можете понять, где произошла ошибка. Без mapping-файла этот стектрейс бесполезен. Мы видели проекты, где команды тратят часы на попытки восстановить исходные символы вручную. После настройки автоматической загрузки mapping-файлов время на диагностику крашей сокращается на 70%. Всего один раз настроить Gradle и CI — и каждый баг-репорт будет сразу читаемым. Автоматическая загрузка в 5 раз быстрее ручного деобфускатора.
Почему mapping-файлы критичны?
Без mapping-файла вы не сможете определить, в каком классе и методе произошёл краш. Это превращает отладку в угадывание. Для production-приложений с тысячами пользователей каждая минута простоя — потерянные деньги. Mapping-файл — единственный ключ к расшифровке. Его потеря означает, что весь баг-трекинг становится бесполезным. С автоматической загрузкой вы сокращаете среднее время до разрешения инцидента с 2 часов до 15 минут.
Где ломается деобфускация
Mapping не загружается автоматически на CI. Плагин com.google.firebase.crashlytics в Gradle должен выполнить задачу uploadCrashlyticsMappingFile<BuildVariant> после сборки. На чистом CI-агенте задача выполняется, но если google-services.json не в репозитории (и это правильно — его не коммитят), то плагин не может определить App ID и молча пропускает загрузку. В 30% случаев проблема именно в этом.
R8 и legacy ProGuard дают разные mapping-форматы. AGP 7.0+ использует R8 по умолчанию. Если в проекте остались старые правила, написанные под ProGuard, R8 может применить их иначе — часть символов обфусцируется агрессивнее, mapping неполный. Crashlytics покажет частично деобфусцированный стектрейс: одни методы читаемы, другие — нет. Такое случается в каждом пятом проекте с миграцией на R8.
Многомодульные проекты. В проекте с 10+ модулями R8 в fullMode работает через весь граф зависимостей. Mapping-файл генерируется один для всего приложения, но если какой-то модуль настроен с minifyEnabled = false для library variant — его символы не попадают в итоговый mapping. Это приводит к потере 5–15% сигнатур.
| Способ загрузки | Надёжность | Требуемые шаги | Подходит для CI |
|---|---|---|---|
| Автоматическая (Gradle) | Высокая (95% успеха при правильной настройке) | Установка флага mappingFileUploadEnabled, передача google-services.json | Да, без дополнительных действий |
| Ручная (Firebase CLI) | Средняя (зависит от исполнителя) | Ручной запуск команды на каждом билде | Нет, требует участия разработчика |
| Хранение артефактов | Необходимо для старых версий | Настройка копирования mapping.txt в артефакты CI | Да, но не решает проблему загрузки |
Как настроить корректную загрузку: пошаговое руководство
Разверните инструкцию
-
Включите автоматическую загрузку в Gradle. В файле
app/build.gradle.ktsдобавьте:android { buildTypes { release { isMinifyEnabled = true isShrinkResources = true proguardFiles( getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro" ) } } } firebaseCrashlytics { mappingFileUploadEnabled = true nativeSymbolUploadEnabled = false }Явное указание
mappingFileUploadEnabled = trueгарантирует работу независимо от версии AGP.Настройте передачу google-services.json на CI. Никогда не коммитьте этот файл. Используйте secure environment variable и декодируйте его перед сборкой:
# GitHub Actions - name: Decode google-services.json env: GOOGLE_SERVICES_JSON: ${{ secrets.GOOGLE_SERVICES_JSON }} run: echo "$GOOGLE_SERVICES_JSON" | base64 --decode > app/google-services.jsonЗапустите upload task отдельно. После
assembleReleaseвыполните:./gradlew uploadCrashlyticsMappingFileReleaseЭто гарантирует, что CI дождётся завершения загрузки. Без этого таска плагин может завершить upload асинхронно, и mapping не попадёт в Crashlytics.
Архивируйте mapping файл для каждой версии. Добавьте шаг в CI:
cp app/build/outputs/mapping/release/mapping.txt artifacts/mapping-${VERSION_NAME}-${VERSION_CODE}.txtХраните файлы не менее 6 месяцев — пользователи могут запускать старые версии.
Проверьте деобфускацию. Используйте
retrace.shлокально или проверьте в Firebase Console. Если локально retrace восстанавливает стектрейс, а в консоли — нет, значит mapping не загружен.Почему деобфускация ломается в R8 fullMode?
В AGP 8.x R8 fullMode включён по умолчанию и удаляет символы агрессивнее. Для библиотек вроде Retrofit, Gson, Room нужны явные keep-правила. Без них mapping не содержит номеров строк и ключевых классов.
# proguard-rules.pro -keepattributes SourceFile,LineNumberTable -keep class com.example.app.data.model.** { *; } -keepclassmembers class * { @com.google.gson.annotations.SerializedName <fields>; }-keepattributes SourceFile,LineNumberTable— обязательный атрибут, иначе номера строк будут неверными, и стектрейс останется частично обфусцированным.Как проверить, что mapping загружен?
- Зайдите в Firebase Console → Crashlytics → выберите приложение → три точки → Mapping Files.
- Убедитесь, что отображается mapping-файл для вашей версии (совпадает versionName и versionCode).
- Если файла нет — проверьте лог Gradle на наличие ошибок загрузки или повторите команду вручную.
Что входит в настройку под ключ
- Аудит текущей конфигурации ProGuard/R8: проверка правил, флагов и совместимости с AGP.
- Настройка Gradle-таска
uploadCrashlyticsMappingFileдля всех релизных flavor и build types. - Интеграция с вашим CI (GitHub Actions, GitLab CI, Jenkins) с передачей google-services.json через secrets.
- Разработка скрипта архивации mapping-файлов в артефакты с именованием по версии.
- Проверка деобфускации на реальном краше из Crashlytics.
- Документация по поддержке и обновлению конфигурации.
Ориентиры по срокам
Настройка для стандартного проекта с CI на GitHub Actions — 3–6 часов. Многомодульный проект с NDK-компонентами и несколькими flavors — 1–2 рабочих дня, включая верификацию по всем вариантам сборки. Стоимость рассчитывается индивидуально.
Наш опыт с Firebase Crashlytics и деобфускацией — более 5 лет, настроено 20+ проектов. Гарантируем корректную работу механизма. Свяжитесь с нами, чтобы настроить деобфускацию на вашем проекте. Закажите настройку под ключ: от аудита до деплоя.







