R8 mappings
A release build minified with R8 renames your classes and methods and drops source file
names. A crash from a user’s device then reads at a.b.c(SourceFile:12), which says
nothing. R8 writes mapping.txt next to the build, under
app/build/outputs/mapping/<variant>/; it maps every obfuscated frame back to your code:
at com.example.shop.cart.Pricing.applyCoupon(Pricing.kt:42).
Upload the mapping of each release to FuseScope and the Errors tab shows Retraced stack traces. It is the Android counterpart of source maps.
- Mappings stay private. They are stored on the FuseScope server; never ship them in the app.
- Retracing happens when you read an error. The stored events keep their raw stack, so uploading a mapping later also fixes errors you already received.
- Grouping uses the retraced frames. Until a release’s mapping is uploaded, its errors group on obfuscated names; see How errors are grouped.
- You need a service account key with the Editor role, not the application’s public key: the public key can only send data.
The release rule
Section titled “The release rule”The upload’s release must equal the SDK’s release. The SDK sends release as
service.version on every event, and FuseScope looks up the mapping by that value. Both
default to the variant’s versionName, so leaving both unset is the simplest way to get
it right. With any other value the stack stays obfuscated.
A release keeps one mapping per build, keyed by its map id: the pg_map_id R8
writes in the mapping’s header. The plugin sends it as map_id; otherwise FuseScope
reads it from the header. Uploading the same build again replaces its mapping, so
variants that share a versionName, such as release and staging, keep their own.
R8 names the source file of each obfuscated frame r8-map-id-<id>. FuseScope retraces a
stack with the mapping whose map id matches it, else with the release’s latest upload.
Upload with the Gradle plugin
Section titled “Upload with the Gradle plugin”-
Create a key. In Settings → Service accounts, create a service account with the Editor role, such as
ci-android, and add a key to it. See Service accounts. Keep the key in your CI’s secrets. -
Apply the plugin in the app module, from Maven Central (add
mavenCentral()topluginManagement.repositoriesinsettings.gradle.kts):app/build.gradle.kts plugins {id("com.android.application")id("io.fuseone.fusescope.android.mappings") version "0.1.0-beta.2"}fusescope {endpoint.set("https://fusescope.example.com")applicationId.set("01a16431-12ca-7064-bae9-6ac64cf20a29")// the API key comes from FUSESCOPE_API_KEY}The application’s R8 mappings tab has this block filled in.
-
Build with the key in the environment:
Terminal window export FUSESCOPE_API_KEY=… # Editor service account key./gradlew :app:bundleRelease> Task :app:uploadFuseScopeMappingReleaseFuseScope: uploaded the R8 mapping of release for release 1.8.0 -
Ship the build, then open an error of that release: its stack shows Retraced.
The plugin adds an uploadFuseScopeMapping<Variant> task for every variant with
isMinifyEnabled = true, and runs it after assemble<Variant> and bundle<Variant>.
./gradlew :app:uploadFuseScopeMappingRelease uploads on its own, from the last build.
The fusescope {} block
Section titled “The fusescope {} block”| Setting | Default | |
|---|---|---|
endpoint |
Gradle property fusescope.endpoint, else FUSESCOPE_ENDPOINT |
The FuseScope base URL. |
applicationId |
fusescope.applicationId, else FUSESCOPE_APPLICATION_ID |
The RUM application id. |
apiKey |
fusescope.apiKey, else FUSESCOPE_API_KEY |
An Editor service account key, sent as SigNoz-Api-Key. Never the public rum_pub_… key. |
release |
the variant’s versionName |
The release the mapping belongs to. Set it only if you also set the SDK’s release. |
enabled |
true |
false skips every upload. |
failOnError |
true |
Fail the build when the upload fails; false logs a warning instead. |
uploadPath |
/api/v1/rum/applications/{applicationId}/mappings |
The upload path under endpoint. |
When the endpoint, the application id or the key is missing, the upload is skipped with a warning, and the build succeeds:
FuseScope: mapping upload for release skipped, set apiKey in fusescope { }So local release builds work without a key, and only CI, which has it, uploads.
Upload with curl
Section titled “Upload with curl”Without the plugin, such as from a CI step after the build, POST the mapping to the
application:
export FUSESCOPE_URL=https://fusescope.example.comexport FUSESCOPE_API_KEY=… # Editor service account key
curl -X POST "$FUSESCOPE_URL/api/v1/rum/applications/01a16431-12ca-7064-bae9-6ac64cf20a29/mappings?release=1.8.0" \ -H "SigNoz-Api-Key: $FUSESCOPE_API_KEY" \ -H "Content-Type: text/plain" \ --data-binary @app/build/outputs/mapping/release/mapping.txt-
The body is the raw
mapping.txt, with any content type except multipart. AddContent-Encoding: gzipto send it compressed. -
map_idis optional, such as?release=1.8.0&map_id=<pg_map_id>. Without it, FuseScope reads the map id from the mapping’s header; a given one must match it, or the upload fails with400. -
Or send
multipart/form-data, with the mapping in a part namedfile, andreleaseandmap_idas fields before it or in the query:Terminal window curl -X POST "$FUSESCOPE_URL/api/v1/rum/applications/01a16431-12ca-7064-bae9-6ac64cf20a29/mappings?release=1.8.0" \-H "SigNoz-Api-Key: $FUSESCOPE_API_KEY" \-F "map_id=<pg_map_id>" \-F "file=@app/build/outputs/mapping/release/mapping.txt" -
A
2xxanswer means the mapping is stored.400means the body is empty, not a mapping or over the size limit;413that the application’s quota is full.
The R8 mappings tab
Section titled “The R8 mappings tab”Open an Android application’s Settings, then R8 mappings. It is the Source maps tab of a web application, adapted to Android. Any role can see it; Admin and Editor can upload, delete and change retention.
- Uploaded releases: one row per release with mappings, newest first, with its size, who uploaded it and when, and when it was last used to retrace an error. Expand a release to list its mappings, one per build. Delete removes them; the events are kept and their stacks become obfuscated again.
- Upload: the Gradle plugin settings or the API
curlcall, with this FuseScope’s URL and the application id filled in. There is no drag-and-drop upload for mappings. - Retention: the same settings as for source maps: delete mappings not used for 30 days, 90 days (the default), 1 year or never, and always keep the 3 newest releases. See Retention.
Mappings and source maps share one store, so the same API lists and deletes them:
GET and DELETE on /api/v1/rum/applications/{id}/sourcemaps.
Limits
Section titled “Limits”| Limit | Default |
|---|---|
| Size of one mapping, after decompression | 50 MB |
| Mappings per release | 1 per map id (an upload of the same build replaces it) |
| Mappings and source maps stored per application | 2 GB |
Self-hosted, these are the rum.sourcemaps settings of the
configuration file; see
Source maps.
When a stack stays obfuscated
Section titled “When a stack stays obfuscated”An Android error group whose release has no mapping shows R8 mapping missing in the
Errors tab. Its detail reads Obfuscated · no R8 mapping for 1.8.0 and, under R8
mapping missing for release 1.8.0, the curl command to upload that release’s
mapping.txt, with this FuseScope’s URL, the application id and the release filled in,
and a link to the R8 mappings settings.
| What you see | Check |
|---|---|
| no R8 mapping for 1.8.0 | No mapping is uploaded for release 1.8.0. Compare the release in the error header with the upload’s: 1.8.0 and 1.8.0-debug are different. |
| the mapping resolves none of these frames | The release has mappings, but not the one of the build you shipped, so its latest was used: the app was rebuilt after the upload, or the server is older than 0.156.0 and two variants share the versionName. Upload the mapping of the build you shipped. |
| Some frames retraced, others not | Frames of libraries not minified with your app, or classes kept by -keep rules, keep their names. Normal. |
| The upload task is skipped | The variant isn’t minified (isMinifyEnabled = false), or the endpoint, application id or key is missing; read the Gradle warning. |
The upload fails with 401 or 403 |
The key is wrong, or its service account is not Editor. |