How do I automate native debug symbols upload for Android on Codemagic?
Last updated: August 6, 2026
Context
When building Android apps, Google Play may warn you about missing native debug symbols (.so files). Previously, uploading these symbols had to be done manually. Codemagic now supports automating this process through several options.
Answer
There are three ways to handle native debug symbols automatically. Try them in order, starting with the simplest.
Option 1: Have Gradle package the symbols inside the AAB
This is the recommended approach as it requires no upload at all. Add the following to your android/app/build.gradle.kts:
android {
buildTypes {
release {
ndk { debugSymbolLevel = "SYMBOL_TABLE" }
}
}
}On Android Gradle Plugin 4.1 and above, symbols are packaged directly into the .aab, and Google Play reads them from the bundle on upload. It is recommended to use SYMBOL_TABLE rather than FULL, since FULL adds file and line numbers but produces much larger output, and Play caps the symbols payload at 1.6 GB.
To verify the bundle contains the symbols (rather than relying on the build log), run:
unzip -l build/app/outputs/bundle/release/app-release.aab | grep debugsymbolsIf you see entries under BUNDLE-METADATA/com.android.tools.build.debugsymbols/, you are all set and can stop here.
Option 2: Automate the upload from the Workflow Editor
If Option 1 does not work for your project, you can use Codemagic's CLI tools (preinstalled on Codemagic build machines) to upload native debug symbols to Google Play directly. Add the following two custom scripts:
Post-build script:
#!/usr/bin/env sh
set -e
SYMBOLS_DIR=$CM_BUILD_DIR/build/app/intermediates/merged_native_libs/release/mergeReleaseNativeLibs/out/lib
cd "$SYMBOLS_DIR" && zip -qr "$CM_EXPORT_DIR/native-debug-symbols.zip" . -i '*.so' -x '.*/*'Post-publish script:
#!/usr/bin/env sh
set -e
AAB=$(find "$CM_BUILD_DIR/build" -name "*.aab" | head -1)
[ -z "$AAB" ] && echo "No AAB found, skipping" && exit 0
VERSION_CODE=$(android-app-bundle dump manifest --bundle "$AAB" \
--xpath '/manifest/@android:versionCode' | tr -d '"')
google-play deobfuscation-files upload \
--package-name "com.example.app" \
--version-code "$VERSION_CODE" \
--deobfuscation-file "$CM_EXPORT_DIR/native-debug-symbols.zip" \
--type nativeCodeThe upload must run after the bundle exists in Google Play, which is why it belongs in the post-publish slot. Note that post-publish scripts run even if a build fails, hence the guard on the AAB path. Both commands use your Google Play service account JSON from the GOOGLE_PLAY_SERVICE_ACCOUNT_CREDENTIALS environment variable, so you can reuse credentials you already have configured. The zip is also copied to $CM_EXPORT_DIR, making it available as a build artifact.
Option 3: Automate the upload using codemagic.yaml
If you are using codemagic.yaml, your existing publishing: google_play: block stays as-is. Add the packaging script to the scripts: key and the upload to the scripts: key under publishing::
scripts:
- name: Package native debug symbols
script: |
SYMBOLS_DIR=$CM_BUILD_DIR/build/app/intermediates/merged_native_libs/release/mergeReleaseNativeLibs/out/lib
cd "$SYMBOLS_DIR" && zip -qr "$CM_EXPORT_DIR/native-debug-symbols.zip" . -i '*.so' -x '.*/*'
publishing:
google_play:
credentials: $GCLOUD_SERVICE_ACCOUNT_CREDENTIALS
track: internal
scripts:
- name: Upload native debug symbols
script: |
AAB=$(find build -name "*.aab" | head -1)
[ -z "$AAB" ] && echo "No AAB found, skipping" && exit 0
VERSION_CODE=$(android-app-bundle dump manifest --bundle "$AAB" \
--xpath '/manifest/@android:versionCode' | tr -d '"')
google-play deobfuscation-files upload \
--package-name "com.example.app" \
--version-code "$VERSION_CODE" \
--deobfuscation-file "$CM_EXPORT_DIR/native-debug-symbols.zip" \
--type nativeCodeFor additional context on Flutter-related debug symbol log warnings, refer to the following Flutter issues: