Flutter, React Native & Unity

Unity Android Release Crashes: Keep Native Symbols for the Exact Build

A Unity Android release crash needs symbols from the exact native build to turn addresses into useful locations. A symbol archive from the same source but a different engine, architecture or rebuild may not match.

By , FounderUpdated 3 min read

Archive symbols with release identity

Keep Unity version, source revision, scripting backend, architecture, version code and artifact hash together with native symbols and applicable managed diagnostics.

The IL2CPP documentation explains native/AOT output and diagnostic considerations. The Android crash guide provides the broader crash-investigation context.

Distinguish diagnostic layers

Trace layer Needed evidence
Java/Kotlin plugin Relevant R8 mapping when obfuscated
Native engine/plugin Matching native symbols and architecture
IL2CPP managed context Supported engine/build diagnostic output
Game-specific state Redacted reproduction and build context

One mapping file cannot explain every layer in a mixed Unity/Android crash.

Verify symbols before an incident

Use a controlled internal test and confirm that your crash-reporting workflow resolves representative frames. Do not wait until a public release fails to discover that CI discarded the symbols.

Ensure the team can retrieve the correct archive without exposing it publicly.

Preserve the original report

Keep raw addresses, module names, build identifiers and thread information. Removing native frames because they look unreadable can destroy the evidence needed for symbolization.

Redact user content and credentials separately from technical identity data.

Diagnose after matching

Once symbols are confirmed, investigate the actual failing operation, ownership or plugin boundary. A plausible function name from mismatched symbols can lead the investigation in the wrong direction.

APKLint's Unity Analyzer can identify native package components and its crash tools can help interpret redacted traces. They cannot recover missing proprietary symbols or prove a native address mapping without the exact release artifacts. Make symbol retention a required release output, not an optional debugging convenience.

Collect the symbols produced by the actual build path

For a Unity Android release, symbol collection depends on whether Unity builds the package directly or exports a Gradle project. The Unity 6.0 symbol documentation describes the relevant outputs. Engine libraries and an IL2CPP application library do not necessarily receive their symbols at the same stage of an exported build.

In the documented exported-project workflow, Unity places engine-library symbols under the exported project's architecture-specific symbols directories, while the later Gradle build produces the IL2CPP library's symbols. Collecting only the files present immediately after export can therefore leave the archive incomplete. Make CI collect the required output after the native build finishes, and inspect the archive before its retention step is marked successful.

Match a native plugin frame before investigating its cause

Suppose a crash report contains an address in a vendor audio library rather than the main Unity library. Symbols for the engine cannot explain the vendor's internal frames. Preserve the module identity and request the matching symbol material through the vendor's supported process. Record the plugin version, architecture and release artifact to avoid substituting a similar-looking library from a later SDK.

For an IL2CPP frame, retrieve the exact candidate's symbols, including its architecture. A rebuild from the same source is not automatically the same binary because toolchain inputs or build settings can differ. Keep the original raw trace and the symbolized interpretation together so another reviewer can repeat or correct the mapping.

Test the reporting pipeline with a controlled internal diagnostic case before public release. Verify that representative frames resolve and that the report identifies the expected application version. A successful symbol upload acknowledgement establishes receipt, but the resolved report establishes that the selected material is useful for this candidate.

Retain Java obfuscation mappings separately when Android plugins use that layer, and preserve application context without collecting private player content. A native failure may still require reproduction, thread analysis or plugin-specific investigation after names are resolved. Symbolization improves the evidence; it does not identify the root cause by itself. Set retention according to the releases you still support so a delayed report from an older installed version can be investigated without rebuilding or guessing.

Sources and further reading

  1. Unity: IL2CPP
  2. Android Developers: Diagnose and fix crashes

Reference review: 29 September 2026. Examples illustrate the workflow; check your installed versions, release artifact and account-specific Console requirements before applying them. This guide is not a claim that APKLint executed your project or verified your private account.

APKLint

Android inspection tools and practical release guides. About APKLint · Report a correction