Skip to main content

Uploading native debug symbols to Google Play Console

Google Play Console shows the following warning after uploading an App Bundle (.aab):

This App Bundle contains native code, and you've not uploaded debug symbols. We recommend you upload a symbol file to make your crashes and ANRs easier to analyze and debug.

This document describes how to package the native libraries produced by the release build into a .zip file and upload it to Play Console to clear that warning.

Reference: Stack Overflow — Play Store error: App Bundle contains native code, and you've not uploaded debug symbols

Why this project uses the manual zip workaround

The Android docs recommend setting ndk.debugSymbolLevel = "SYMBOL_TABLE" (or "FULL") in app/build.gradle.kts so that AGP extracts symbols and embeds them in the AAB automatically. That approach does not work for LockView and has already been tried and reverted in a prior session. Keep this section so the same dead end isn't re-explored next time.

The only native library bundled in LockView is libandroidx.graphics.path.so, pulled in transitively by Compose via androidx.graphics:graphics-path. Inspecting the file shows it is already stripped upstream by Google:

$ file libandroidx.graphics.path.so
ELF 64-bit LSB shared object, ARM aarch64, ... built by NDK r25c (9519653), stripped

Because the .so ships without debug symbols, AGP's extractReleaseNativeDebugMetadata task has nothing to extract — installing the NDK, matching ndkVersion, and switching debugSymbolLevel between SYMBOL_TABLE and FULL all produce an empty app/build/intermediates/native_debug_metadata/release/ and no BUNDLE-METADATA/com.android.tools.build.debugsymbols/ entry inside the AAB. Play Console therefore keeps showing the warning.

The manual zip method below is the practical workaround:

  • The uploaded .so files have no useful symbols either, so crash symbolication will not actually improve.
  • But Play Console only checks that something was uploaded against the symbols slot — it does not validate the contents — so the warning disappears.
  • Treat this as "silencing an informational warning," not "enabling native crash symbolication."

If a future release introduces a native library that LockView itself builds (rather than a pre-stripped third-party AAR), revisit the Gradle approach — it would work for that library.

Prerequisites

  • A release build has been produced at least once. Run one of the following from the project root so the native libraries are merged into the intermediates directory:
    ./gradlew bundleRelease
    # or
    ./gradlew assembleRelease
  • A zip tool is available (Windows Explorer, 7z, zip, or PowerShell's Compress-Archive).

Source path

After a release build, the merged native libraries live at this path, relative to the project root:

app/build/intermediates/merged_native_libs/release/mergeReleaseNativeLibs/out/lib/

On the current machine this resolves to:

D:\Documents\MyProjects\LockView\app\build\intermediates\merged_native_libs\release\mergeReleaseNativeLibs\out\lib\

The folder contains one subdirectory per supported ABI:

lib/
├── arm64-v8a/
├── armeabi-v7a/
├── x86/
└── x86_64/

These four ABI folders are exactly what Play Console expects inside the symbols .zip.

Packaging steps

The archive must contain the four ABI folders at its root (not nested inside an extra lib/ folder). The file name itself does not matter — native-debug-symbols.zip is a fine default.

Option A — PowerShell (Windows, cross-machine)

Run from the project root:

$libDir = "app\build\intermediates\merged_native_libs\release\mergeReleaseNativeLibs\out\lib"
$output = "native-debug-symbols.zip"

if (Test-Path $output) { Remove-Item $output }
Compress-Archive -Path (Join-Path $libDir '*') -DestinationPath $output

Join-Path $libDir '*' ensures the ABI folders are placed at the root of the archive.

Option B — zip (Linux / macOS / Git Bash)

Run from the project root:

LIB_DIR="app/build/intermediates/merged_native_libs/release/mergeReleaseNativeLibs/out/lib"
(cd "$LIB_DIR" && zip -r "$OLDPWD/native-debug-symbols.zip" .)

cd into the lib/ directory before zipping so the ABI folders end up at the archive root.

Option C — Windows Explorer (manual)

  1. Open the lib folder shown above in File Explorer.
  2. Select all four ABI folders (arm64-v8a, armeabi-v7a, x86, x86_64).
  3. Right-click → Send toCompressed (zipped) folder.
  4. Rename the resulting file to anything you like (e.g. native-debug-symbols.zip).

Verifying the archive

Open the .zip and confirm the top level looks like this:

native-debug-symbols.zip
├── arm64-v8a/
├── armeabi-v7a/
├── x86/
└── x86_64/

If you see an extra wrapping folder (e.g. lib/arm64-v8a/...), repackage — Play Console will reject the symbols.

Uploading to Play Console

  1. Open Google Play Console.
  2. Select the app → ReleaseApp bundle explorer.
  3. Pick the release whose warning you want to clear.
  4. Open the Downloads tab.
  5. Under Assets, find Native debug symbols and click the upload icon.
  6. Select the .zip produced above and confirm.

After upload completes, the warning disappears from that release, and future crash and ANR reports for native code will include symbolicated stack traces.

Notes

  • Repeat these steps for every new release build that ships native code — each App Bundle has its own symbols slot.
  • The intermediates folder is wiped by ./gradlew clean. If you have already cleaned, rebuild before zipping.
  • The path is identical on any machine that builds this project, because it lives under the project's own app/build/ tree. Only the prefix (the absolute path to the project root) differs.