You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Crashlytics mapping-file-id resource silently dropped under AGP 9.3.1
Summary
Under AGP 9.3.1, the Crashlytics Gradle plugin's InjectMappingFileIdTask generates a valid, correctly-formed resource file containing the mapping-file ID (com.google.firebase.crashlytics.mapping_file_id), and registers it via the documented Variant API (variant.sources.res?.addGeneratedSourceDirectory(...)). The registration call completes without error, and AGP's own resource-merge validator recognizes the resource as a declared entry (it is caught in duplicate-resource conflict detection when a competing declaration is added). However, the resource never appears in the final compiled resources.arsc / packaged APK. Crashlytics is therefore unable to associate crash reports with the correct build/mapping file, and no crashes are received in the Firebase console for any release built this way — despite Play Console's own separate crash/ANR vitals confirming the app is genuinely crashing in production.
This worked correctly on AGP 8.13.2 with the same Crashlytics Gradle plugin version and stopped working immediately after upgrading to AGP 9.3.1.
Environment
AGP: 9.3.1 (regression from working AGP 8.13.2)
Crashlytics Gradle plugin: reproduced on both 3.0.4 and 3.0.7 (latest available at time of testing)
Configure a release build type with isMinifyEnabled = true and the Crashlytics Gradle plugin applied.
Build the release variant with AGP 9.3.1 (./gradlew assembleRelease).
Inspect the generated task output at build/generated/res/injectCrashlyticsMappingFileId<Variant>/values/com_google_firebase_crashlytics_mappingfileid.xml — this file is present and correctly formed with a valid UUID.
Inspect the final packaged APK's resource table (e.g. aapt2 dump resources app-release.apk, or strings on the extracted resources.arsc) for com.google.firebase.crashlytics.mapping_file_id — it is absent.
Repeat steps 1–4 on AGP 8.13.2 with the same Crashlytics plugin version — the resource is present and correct.
What we verified while diagnosing this
The task itself (injectCrashlyticsMappingFileId<Variant>) runs successfully and produces a correct output file every time — this rules out a generation-side bug.
variant.sources.res is non-null at the point the plugin (and our own replicated call) invokes addGeneratedSourceDirectory — rules out the null-safe-call-skips-registration theory.
AGP's own android_res_source_set_path_map intermediate file lists the generated directory as a known, registered resource source for the variant — so the directory is not being ignored at the source-set level.
The resource is absent from every intermediate compiled .flat file in merged_res/<variant>/merge<Variant>Resources/, not just the final packaged output — so it is dropped before or during compilation, not at a later packaging step.
Independently re-implementing the exact same wiring the plugin uses (variant.sources.res?.addGeneratedSourceDirectory(task, Task::resourceDir), called directly from the app's own build.gradle.kts against the plugin's own InjectMappingFileIdTask type) reproduces the same silent failure — this is not specific to how the plugin itself is written, and confirms it's not fixable purely from the plugin's side without an AGP-level fix, or not fixable from consuming build scripts either.
AGP's own native resValue(...) mechanism (an unrelated, hand-declared static string resource already used elsewhere in this project's debug build type) works correctly under the exact same AGP 9.3.1 setup — ruling out a general "AGP 9.3.1 can't generate resources at all" explanation. The issue is specific to resources registered via addGeneratedSourceDirectory in this particular code path/timing, not resource generation in general.
Attempting to work around this by supplying the same resource value through variant.resValues.put(...) (a mechanism confirmed working in this project) fails with a duplicate-resource merge error against the original, non-functional Crashlytics-generated declaration — i.e. AGP's resource merger still "sees" the broken declaration as a real, conflicting entry during validation, even though that same declaration never survives into the actual compiled output. This inconsistency between what the merger validates against and what it actually includes is itself worth flagging as part of the bug.
This is not the known isShrinkResources issue where an unreferenced resource gets stripped by the resource shrinker (see Crashes when isShrinkResources is set to true, it reports "The Crashlytics build ID is missing..." #5562) — we tested explicitly protecting the resource via a tools:keep entry in res/raw/keep.xml, and it made no difference. This is consistent with the resource being dropped before the merge/compile stage, well before shrinking would ever run on it.
Also tested migrating the release build type to AGP 9.3+'s new unified optimization { enable = true } DSL (which changes how R8 handles code and resource optimization together) in place of the legacy isMinifyEnabled/isShrinkResources/proguardFiles DSL — no difference; the resource is still absent from the final compiled resource table either way.
Expected behavior
The mapping-file-id resource generated by InjectMappingFileIdTask should be included in the final compiled resource table under AGP 9.3.1, exactly as it is under AGP 8.13.2, so that Crashlytics can correctly tag and de-obfuscate crash reports.
Actual behavior
The resource is generated correctly, registered via the documented API without error, and recognized by AGP's resource-merge validator — but is absent from every compiled intermediate and the final packaged resource table. As a direct consequence, Firebase Crashlytics receives zero crash reports for any release built with this AGP version, even though the app is confirmed to be crashing in production (verified via Google Play Console's separate Android vitals, which uses a different, non-Firebase-SDK-based reporting path).
Crashlytics mapping-file-id resource silently dropped under AGP 9.3.1
Summary
Under AGP 9.3.1, the Crashlytics Gradle plugin's
InjectMappingFileIdTaskgenerates a valid, correctly-formed resource file containing the mapping-file ID (com.google.firebase.crashlytics.mapping_file_id), and registers it via the documented Variant API (variant.sources.res?.addGeneratedSourceDirectory(...)). The registration call completes without error, and AGP's own resource-merge validator recognizes the resource as a declared entry (it is caught in duplicate-resource conflict detection when a competing declaration is added). However, the resource never appears in the final compiledresources.arsc/ packaged APK. Crashlytics is therefore unable to associate crash reports with the correct build/mapping file, and no crashes are received in the Firebase console for any release built this way — despite Play Console's own separate crash/ANR vitals confirming the app is genuinely crashing in production.This worked correctly on AGP 8.13.2 with the same Crashlytics Gradle plugin version and stopped working immediately after upgrading to AGP 9.3.1.
Environment
firebase-crashlytics-ktx18.1.0Steps to reproduce
isMinifyEnabled = trueand the Crashlytics Gradle plugin applied../gradlew assembleRelease).build/generated/res/injectCrashlyticsMappingFileId<Variant>/values/com_google_firebase_crashlytics_mappingfileid.xml— this file is present and correctly formed with a valid UUID.aapt2 dump resources app-release.apk, orstringson the extractedresources.arsc) forcom.google.firebase.crashlytics.mapping_file_id— it is absent.What we verified while diagnosing this
injectCrashlyticsMappingFileId<Variant>) runs successfully and produces a correct output file every time — this rules out a generation-side bug.variant.sources.resis non-null at the point the plugin (and our own replicated call) invokesaddGeneratedSourceDirectory— rules out the null-safe-call-skips-registration theory.android_res_source_set_path_mapintermediate file lists the generated directory as a known, registered resource source for the variant — so the directory is not being ignored at the source-set level..flatfile inmerged_res/<variant>/merge<Variant>Resources/, not just the final packaged output — so it is dropped before or during compilation, not at a later packaging step.variant.sources.res?.addGeneratedSourceDirectory(task, Task::resourceDir), called directly from the app's ownbuild.gradle.ktsagainst the plugin's ownInjectMappingFileIdTasktype) reproduces the same silent failure — this is not specific to how the plugin itself is written, and confirms it's not fixable purely from the plugin's side without an AGP-level fix, or not fixable from consuming build scripts either.resValue(...)mechanism (an unrelated, hand-declared static string resource already used elsewhere in this project'sdebugbuild type) works correctly under the exact same AGP 9.3.1 setup — ruling out a general "AGP 9.3.1 can't generate resources at all" explanation. The issue is specific to resources registered viaaddGeneratedSourceDirectoryin this particular code path/timing, not resource generation in general.variant.resValues.put(...)(a mechanism confirmed working in this project) fails with a duplicate-resource merge error against the original, non-functional Crashlytics-generated declaration — i.e. AGP's resource merger still "sees" the broken declaration as a real, conflicting entry during validation, even though that same declaration never survives into the actual compiled output. This inconsistency between what the merger validates against and what it actually includes is itself worth flagging as part of the bug.isShrinkResourcesissue where an unreferenced resource gets stripped by the resource shrinker (see Crashes whenisShrinkResourcesis set totrue, it reports "The Crashlytics build ID is missing..." #5562) — we tested explicitly protecting the resource via atools:keepentry inres/raw/keep.xml, and it made no difference. This is consistent with the resource being dropped before the merge/compile stage, well before shrinking would ever run on it.optimization { enable = true }DSL (which changes how R8 handles code and resource optimization together) in place of the legacyisMinifyEnabled/isShrinkResources/proguardFilesDSL — no difference; the resource is still absent from the final compiled resource table either way.Expected behavior
The mapping-file-id resource generated by
InjectMappingFileIdTaskshould be included in the final compiled resource table under AGP 9.3.1, exactly as it is under AGP 8.13.2, so that Crashlytics can correctly tag and de-obfuscate crash reports.Actual behavior
The resource is generated correctly, registered via the documented API without error, and recognized by AGP's resource-merge validator — but is absent from every compiled intermediate and the final packaged resource table. As a direct consequence, Firebase Crashlytics receives zero crash reports for any release built with this AGP version, even though the app is confirmed to be crashing in production (verified via Google Play Console's separate Android vitals, which uses a different, non-Firebase-SDK-based reporting path).