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.
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
.sofiles 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'sCompress-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)
- Open the
libfolder shown above in File Explorer. - Select all four ABI folders (
arm64-v8a,armeabi-v7a,x86,x86_64). - Right-click → Send to → Compressed (zipped) folder.
- 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
- Open Google Play Console.
- Select the app → Release → App bundle explorer.
- Pick the release whose warning you want to clear.
- Open the Downloads tab.
- Under Assets, find Native debug symbols and click the upload icon.
- Select the
.zipproduced 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.