Describe the bug
The generated app/build.gradle.kts (both the tauri-cli mobile template and cargo-mobile2's android-studio template) writes:
buildTypes {
getByName("debug") {
...
packaging {
jniLibs.keepDebugSymbols.add("*/arm64-v8a/*.so")
jniLibs.keepDebugSymbols.add("*/armeabi-v7a/*.so")
jniLibs.keepDebugSymbols.add("*/x86/*.so")
jniLibs.keepDebugSymbols.add("*/x86_64/*.so")
}
}
The intent is clearly debug-only — but AGP's BuildType DSL has no packaging block, so Kotlin resolves that call against the outer android {} extension (com.android.build.api.dsl.ApplicationExtension.packaging). The keep-globs therefore apply to every variant, including release.
Consequences for every Tauri Android app built from this template:
- Release
.so files ship unstripped. AGP's stripReleaseDebugSymbols task sees the glob match and silently copies the lib verbatim instead of running llvm-strip --strip-unneeded (this is the one fallback path in StripDebugSymbolsTask that logs nothing). For our app that's ~1.2 MB of .symtab per ABI delivered to every player for no benefit.
ndk.debugSymbolLevel cannot work. ExtractNativeDebugMetadataTask decides "already stripped" by comparing byte lengths of the merged lib vs the strip task's output (AGP 8.11.1 sources, ExtractNativeDebugMetadataTask.kt — it never inspects the ELF). Since the "stripped" file is a verbatim copy, lengths are equal, extraction is skipped with an info-level "native debug metadata has already been stripped", and no BUNDLE-METADATA/com.android.tools.build.debugsymbols/ is produced. Google Play's "you've not uploaded debug symbols" warning is unresolvable from the DSL, and native crash/ANR reports stay unsymbolicated.
Evidence
Dumping the release strip task's effective input in CI (init script printing task.keepDebugSymbols.get() from taskGraph.beforeTask) on an untouched generated project:
KEEPDEBUGSYMBOLS=[*/arm64-v8a/*.so, */armeabi-v7a/*.so, */x86/*.so, */x86_64/*.so]
— on :app:stripUniversalReleaseDebugSymbols, i.e. the globs written inside the debug block are live on the release variant. llvm-readelf confirms the packaged release lib retains its full .symtab, and adding ndk { debugSymbolLevel = "SYMBOL_TABLE" } to the release build type produces an AAB with no debugsymbols metadata.
After moving the globs to a properly scoped variant-API block, the same project produces .sym files for both ABIs in BUNDLE-METADATA and actually-stripped packaged libs.
Suggested fix
Replace the mis-scoped block in the template with variant-API scoping, preserving the debug-only intent (unstripped libs for on-device LLDB):
androidComponents {
onVariants(selector().withBuildType("debug")) { variant ->
listOf("*/arm64-v8a/*.so", "*/armeabi-v7a/*.so", "*/x86/*.so", "*/x86_64/*.so")
.forEach { variant.packaging.jniLibs.keepDebugSymbols.add(it) }
}
}
(Verified working on AGP 8.11.0 / Gradle 8.14.3.)
Affected templates:
crates/tauri-cli/templates/mobile/android/app/build.gradle.kts
cargo-mobile2: templates/platforms/android-studio/app/build.gradle.kts.hbs
Reproduction
tauri android init on any app; add ndk { debugSymbolLevel = "SYMBOL_TABLE" } to the release build type.
tauri android build --aab
unzip -l the AAB: no BUNDLE-METADATA/com.android.tools.build.debugsymbols/; llvm-readelf -S on base/lib/arm64-v8a/*.so shows .symtab present.
Expected behavior
Release native libs are stripped by AGP's default pipeline, and debugSymbolLevel produces the debug-symbols bundle metadata; keepDebugSymbols applies only to debug builds as the template's placement implies.
Full tauri info output
tauri-cli 2.11.3 (npm @tauri-apps/cli 2.11.3), tauri 2.11.3
AGP 8.11.0, Gradle 8.14.3, NDK 27.0.12077973, JDK 17 (Temurin)
Host app: production Tauri v2 game (Rust cdylib + WebView frontend), Android target
Stack trace
No crash — the failure is silent; that's the core of the report.
Describe the bug
The generated
app/build.gradle.kts(both the tauri-cli mobile template and cargo-mobile2's android-studio template) writes:buildTypes { getByName("debug") { ... packaging { jniLibs.keepDebugSymbols.add("*/arm64-v8a/*.so") jniLibs.keepDebugSymbols.add("*/armeabi-v7a/*.so") jniLibs.keepDebugSymbols.add("*/x86/*.so") jniLibs.keepDebugSymbols.add("*/x86_64/*.so") } }The intent is clearly debug-only — but AGP's
BuildTypeDSL has nopackagingblock, so Kotlin resolves that call against the outerandroid {}extension (com.android.build.api.dsl.ApplicationExtension.packaging). The keep-globs therefore apply to every variant, including release.Consequences for every Tauri Android app built from this template:
.sofiles ship unstripped. AGP'sstripReleaseDebugSymbolstask sees the glob match and silently copies the lib verbatim instead of runningllvm-strip --strip-unneeded(this is the one fallback path inStripDebugSymbolsTaskthat logs nothing). For our app that's ~1.2 MB of.symtabper ABI delivered to every player for no benefit.ndk.debugSymbolLevelcannot work.ExtractNativeDebugMetadataTaskdecides "already stripped" by comparing byte lengths of the merged lib vs the strip task's output (AGP 8.11.1 sources,ExtractNativeDebugMetadataTask.kt— it never inspects the ELF). Since the "stripped" file is a verbatim copy, lengths are equal, extraction is skipped with an info-level "native debug metadata has already been stripped", and noBUNDLE-METADATA/com.android.tools.build.debugsymbols/is produced. Google Play's "you've not uploaded debug symbols" warning is unresolvable from the DSL, and native crash/ANR reports stay unsymbolicated.Evidence
Dumping the release strip task's effective input in CI (init script printing
task.keepDebugSymbols.get()fromtaskGraph.beforeTask) on an untouched generated project:— on
:app:stripUniversalReleaseDebugSymbols, i.e. the globs written inside the debug block are live on the release variant.llvm-readelfconfirms the packaged release lib retains its full.symtab, and addingndk { debugSymbolLevel = "SYMBOL_TABLE" }to the release build type produces an AAB with no debugsymbols metadata.After moving the globs to a properly scoped variant-API block, the same project produces
.symfiles for both ABIs inBUNDLE-METADATAand actually-stripped packaged libs.Suggested fix
Replace the mis-scoped block in the template with variant-API scoping, preserving the debug-only intent (unstripped libs for on-device LLDB):
androidComponents { onVariants(selector().withBuildType("debug")) { variant -> listOf("*/arm64-v8a/*.so", "*/armeabi-v7a/*.so", "*/x86/*.so", "*/x86_64/*.so") .forEach { variant.packaging.jniLibs.keepDebugSymbols.add(it) } } }(Verified working on AGP 8.11.0 / Gradle 8.14.3.)
Affected templates:
crates/tauri-cli/templates/mobile/android/app/build.gradle.ktscargo-mobile2: templates/platforms/android-studio/app/build.gradle.kts.hbsReproduction
tauri android initon any app; addndk { debugSymbolLevel = "SYMBOL_TABLE" }to the release build type.tauri android build --aabunzip -lthe AAB: noBUNDLE-METADATA/com.android.tools.build.debugsymbols/;llvm-readelf -Sonbase/lib/arm64-v8a/*.soshows.symtabpresent.Expected behavior
Release native libs are stripped by AGP's default pipeline, and
debugSymbolLevelproduces the debug-symbols bundle metadata;keepDebugSymbolsapplies only to debug builds as the template's placement implies.Full
tauri infooutputStack trace
No crash — the failure is silent; that's the core of the report.