ProGuard/R8 Mapping Upload Setup for Android Crash Deobfuscation

NOVASOLUTIONS.TECHNOLOGY is engaged in the development, support and maintenance of iOS, Android, PWA mobile applications. We have extensive experience and expertise in publishing mobile applications in popular markets like Google Play, App Store, Amazon, AppGallery and others.
Development and support of all types of mobile applications:
Information and entertainment mobile applications
News apps, games, reference guides, online catalogs, weather apps, fitness and health apps, travel apps, educational apps, social networks and messengers, quizzes, blogs and podcasts, forums, aggregators
E-commerce mobile applications
Online stores, B2B apps, marketplaces, online exchanges, cashback services, exchanges, dropshipping platforms, loyalty programs, food and goods delivery, payment systems.
Business process management mobile applications
CRM systems, ERP systems, project management, sales team tools, financial management, production management, logistics and delivery management, HR management, data monitoring systems
Electronic services mobile applications
Classified ads platforms, online schools, online cinemas, electronic service platforms, cashback platforms, video hosting, thematic portals, online booking and scheduling platforms, online trading platforms

These are just some of the types of mobile applications we work with, and each of them may have its own specific features and functionality, tailored to the specific needs and goals of the client.

Showing 1 of 1 servicesAll 1735 services
ProGuard/R8 Mapping Upload Setup for Android Crash Deobfuscation
Medium
from 4 hours to 2 business days
FAQ
Our competencies:
Development stages
Latest works
  • image_mobile-applications_feedme_467_0.webp
    Development of a mobile application for FEEDME
    756
  • image_mobile-applications_xoomer_471_0.webp
    Development of a mobile application for XOOMER
    624
  • image_mobile-applications_rhl_428_0.webp
    Development of a mobile application for RHL
    1052
  • image_mobile-applications_zippy_411_0.webp
    Development of a mobile application for ZIPPY
    947
  • image_mobile-applications_affhome_429_0.webp
    Development of a mobile application for Affhome
    862
  • image_mobile-applications_flavors_409_0.webp
    Development of a mobile application for the FLAVORS company
    445

Setting Up ProGuard/R8 Mapping Upload for Android Crash Deobfuscation

Firebase Crashlytics shows a.b.c.d.e(Unknown Source:12) instead of com.example.app.checkout.PaymentViewModel.processPayment(PaymentViewModel.kt:89). ProGuard and R8 rename classes and methods in minified production builds — without the mapping file, the stack trace is unreadable. The problem occurs not just in new projects: often mapping stops uploading after switching CI or updating AGP.

Where Deobfuscation Breaks

Mapping doesn't upload automatically on CI. The com.google.firebase.crashlytics plugin in Gradle should execute the uploadCrashlyticsMappingFile<BuildVariant> task after build. On a clean CI agent, the task runs, but if google-services.json isn't in the repository (and it shouldn't be — it's never committed), the plugin can't determine the App ID and silently skips the upload.

R8 and legacy ProGuard produce different mapping formats. AGP 7.0+ uses R8 by default. If the project has old rules written for ProGuard, R8 might apply them differently — some symbols get obfuscated more aggressively, mapping is incomplete. Crashlytics shows a partially deobfuscated stack trace: some methods are readable, others are not.

Multi-module projects. In a project with 10+ modules, R8 in fullMode (default in AGP 8.x) works across the entire dependency graph. A single mapping file is generated for the whole app, but if a module is configured with minifyEnabled = false for the library variant — its symbols don't make it to the final mapping.

How to Configure Proper Upload

Gradle Configuration

// app/build.gradle.kts
android {
    buildTypes {
        release {
            isMinifyEnabled = true
            isShrinkResources = true
            proguardFiles(
                getDefaultProguardFile("proguard-android-optimize.txt"),
                "proguard-rules.pro"
            )
        }
    }
}

// Crashlytics mapping upload
firebaseCrashlytics {
    mappingFileUploadEnabled = true
    nativeSymbolUploadEnabled = false // only for NDK crashes
}

mappingFileUploadEnabled = true — explicitly set this, don't rely on defaults. Post-AGP 8.x, the default is true for release, but it's better to be explicit.

Passing google-services.json to CI

google-services.json should not be in the repository. On CI, pass it via 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

- name: Build and upload mapping
  run: ./gradlew assembleRelease uploadCrashlyticsMappingFileRelease

The uploadCrashlyticsMappingFileRelease task runs separately — this is important because on assembleRelease the plugin sometimes completes the upload asynchronously and CI doesn't wait for it.

Manual Upload via Firebase CLI

If automatic upload doesn't work for some reason:

firebase crashlytics:mappingfile:upload \
  --app=1:123456789:android:abcdef \
  app/build/outputs/mapping/release/mapping.txt

The mapping file is always located at app/build/outputs/mapping/<buildType>/mapping.txt. Save it as a CI artifact — without it, deobfuscating old crashes is impossible after code version changes.

Storing Mapping Files

Rule: each production release → archive mapping.txt with version and build number. In 6 months, users might still be running old versions, and crashes from them will come undeobfuscated if the mapping is lost.

# In CI: save as artifact
cp app/build/outputs/mapping/release/mapping.txt \
   artifacts/mapping-${VERSION_NAME}-${VERSION_CODE}.txt

Verification via Retrace

For local verification:

# Android SDK tools
retrace.sh \
  app/build/outputs/mapping/release/mapping.txt \
  obfuscated-stacktrace.txt

If retrace recovers a readable stack trace locally, but Crashlytics still shows obfuscated — the mapping wasn't uploaded. Check in Firebase Console: Crashlytics → App → three dots → Mapping Files.

R8 fullMode and Preserving Required Symbols

In AGP 8.x R8 fullMode is on by default and removes symbols more aggressively. For Retrofit, Gson, Room, you need explicit keep rules:

# proguard-rules.pro
-keepattributes SourceFile,LineNumberTable
-keep class com.example.app.data.model.** { *; }
-keepclassmembers class * {
    @com.google.gson.annotations.SerializedName <fields>;
}

-keepattributes SourceFile,LineNumberTable — without this, mapping exists, but line numbers in the stack trace will be incorrect.

Timeline Estimates

Setup for a standard project with CI on GitHub Actions — 3–6 hours. Multi-module project with NDK components and multiple flavors — 1–2 business days, including verification across all build variants.