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 debugsymbols

If 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 nativeCode

The 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 nativeCode

For additional context on Flutter-related debug symbol log warnings, refer to the following Flutter issues: