Android ProGuard / R8 source maps

When your Android app ships with code shrinking and obfuscation (R8 or ProGuard), crash and ANR stack traces in Middleware show short class names such as a.b.c instead of your real types and methods. Uploading the mapping.txt file produced by the minifier lets Middleware resolve those frames back to your source when you use Unminify in the RUM stack trace view (and in related flows that reuse the same Android deobfuscation pipeline).

This works the same way as browser source maps: each upload is stored under your account and application (RUM) configuration, keyed by app version. The version you upload must match the app.version attribute sent with telemetry (see Android SDK and BuildConfig.VERSION_NAME).

Prerequisites#

  • Minification enabled for the build variant you ship. The Gradle plugin only registers an upload task when minifyEnabled is true for that variant; otherwise there is no mapping.txt to upload.
  • Your RUM account key (the same credential you use for the Android SDK and for browser sourcemap uploads—not your general Middleware API key unless your product docs state otherwise).
  • Repositories that can resolve the plugin from the Gradle Plugin Portal (typically gradlePluginPortal() in pluginManagement).

1. Apply the Gradle plugin#

In your root settings.gradle or settings.gradle.kts, ensure plugin management includes the plugin portal:

pluginManagement {
    repositories {
        google()
        mavenCentral()
        gradlePluginPortal()
    }
}

In the app module build.gradle (Kotlin DSL: build.gradle.kts), apply the Android application plugin first, then the Middleware source map plugin:

plugins {
    id 'com.android.application'
    id 'io.github.middleware-labs.sourcemap' version '1.0.0'
}

Use the latest published version from the Gradle Plugin Portal if it differs from the example above.

2. Configure upload settings#

Still in the app module, add a middlewareSourcemap block after the plugins { } section:

middlewareSourcemap {
    apiKey     = '<your_rum_account_key>'
    backendUrl = 'https://app.middleware.io/api/v1/rum/getSasUrl'
    // Optional: override version (defaults to the variant’s versionName, e.g. BuildConfig.VERSION_NAME)
    // appVersion = "2.0.0"
    // Optional: remove local mapping after successful upload
    // deleteAfterUpload = false
}

apiKey — Your RUM account key. For CI, you can omit this in the script and set the environment variable MW_API_KEY instead; the plugin falls back to it when apiKey is not set.

backendUrl — Endpoint that returns a pre-signed upload URL for your tenant. For most SaaS deployments this is https://app.middleware.io/api/v1/rum/getSasUrl. If you use a regional or dedicated Middleware host, use the same origin you use for RUM ingestion and the path /api/v1/rum/getSasUrl (your Installation page in the product lists the correct base URL).

The plugin uploads a single file named mapping.txt per variant, using the same storage layout as JavaScript source maps so Middleware can load it when deobfuscating Android traces.

3. Enable minification for the variant you release#

R8/ProGuard must run so that mapping.txt exists. Example:

android {
    buildTypes {
        release {
            minifyEnabled true
            shrinkResources true   // optional; independent of mapping upload
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
        debug {
            // Only if you need mapping for debug builds (e.g. internal testing)
            minifyEnabled true
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
}

If minifyEnabled is false for a variant, the plugin skips that variant and logs that minification is disabled.

4. Align app.version with the uploaded mapping#

Middleware picks the mapping file using account, RUM application / agent configuration, and app version. Set the global attribute on the device to the same string as the version you upload (commonly BuildConfig.VERSION_NAME):

Middleware.builder()
    // ...
    .setGlobalAttributes(
        Attributes.of(APP_VERSION, BuildConfig.VERSION_NAME)
    )
    .build(this);

If you set appVersion in middlewareSourcemap, it must match what you send as app.version in telemetry for that build.

5. Run the upload task#

For each minified variant, the plugin registers a task named:

uploadMiddlewareMapping + capitalized variant name (for example uploadMiddlewareMappingRelease).

The task depends on the corresponding minify…WithR8 or minify…WithProguard task so mapping.txt exists before upload. If you run assembleRelease (or another assemble* task), the upload task is attached as a finalizer so a successful assemble triggers upload when minification ran.

Typical CI step after building the release artifact:

./gradlew uploadMiddlewareMappingRelease

How deobfuscation works in the product#

When you open an Android error in RUM and choose to unminify the stack trace, the UI sends the obfuscated lines to Middleware’s Android source map service. That service loads mapping.txt from secure storage (using the same path convention as browser source maps) and runs the retrace tool from the ProGuard/R8 toolchain to produce human-readable frames. On Middleware’s hosted platform this runs as part of the service; if you operate a self-hosted stack, the source map service must have the retrace command available (for example via the ANDROID_RETRACE_CMD environment variable on the worker that handles /api/v1/sourcemap/android).

Troubleshooting#

SymptomWhat to check
No uploadMiddlewareMapping* taskConfirm minifyEnabled true for that variant and that com.android.application is applied before this plugin.
Upload succeeds but Unminify still failsVerify app.version on spans matches the uploaded version; verify the build uses the same RUM application / key as the upload.
Wrong environmentPoint backendUrl at the same Middleware base URL you use for setTarget in the SDK.
CI secretsPrefer MW_API_KEY and inject it in the CI job instead of committing keys to the repo.

See also#

Questions? Contact [email protected] or the Middleware community Slack.