Skip to content

[bug] Android template's keepDebugSymbols applies to every build type — release .so ships unstripped and ndk.debugSymbolLevel extracts nothing #15884

Description

@borntoeatt

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:

  1. 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.
  2. 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

  1. tauri android init on any app; add ndk { debugSymbolLevel = "SYMBOL_TABLE" } to the release build type.
  2. tauri android build --aab
  3. 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.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions