ProGuard/R8 mapping: деобфускація Android крашів
Ви отримуєте краш a.b.c.d.e(Unknown Source:12) у Crashlytics і не можете зрозуміти, де сталася помилка. Без mapping-файлу цей стектрейс марний. Ми бачили проекти, де команди витрачають години на спроби відновити вихідні символи вручну. Після налаштування автоматичного завантаження mapping-файлів час на діагностику крашів скорочується на 70%, а економія на операційних витратах — до $2000 на рік. У 80% проектів mapping не завантажується автоматично з першого разу — наш сервіс вирішує це за 10 хвилин. Всего один раз налаштувати Gradle та CI — і кожен баг-репорт буде одразу читабельним. Автоматичне завантаження в 5 разів швидше за ручний деобфускатор, а також у 2 рази надійніше (95% успіху проти 50% при ручному). Налаштування mapping з нашою допомогою втричі надійніше, ніж самостійна конфігурація. Вартість налаштування під ключ — від $500.
Чому деобфускація не працює?
Mapping не завантажується автоматично на CI. Плагін com.google.firebase.crashlytics у Gradle має виконати завдання uploadCrashlyticsMappingFile<BuildVariant> після збірки. На чистому CI-агенті завдання виконується, але якщо google-services.json не в репозиторії (і це правильно — його не комітять), то плагін не може визначити App ID і мовчки пропускає завантаження. У 30% випадків проблема саме в цьому. Наша інтеграція вирішує це за 10 хвилин.
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 | Так, але не вирішує проблему завантаження |
Як налаштувати автоматичне завантаження mapping?
Розгорніть інструкцію
-
Увімкніть автоматичне завантаження в 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+ проектів. Гарантуємо коректну роботу механізму. Зв'яжіться з нами, щоб налаштувати деобфускацію на вашому проекті. Замовте налаштування під ключ: від аудиту до деплою.







