Google Play Pre-Launch Report ANR in Unity IL2CPP Build - Startup Thread and Splash Flow Fix
Problem: Google Play Console shows an ANR (Application Not Responding) in the pre-launch report, Android Vitals, or crash reports, often with stack traces pointing at UnityPlayer, native, or your first activity during cold start. The dialog users never see on a lab device still counts as a blocked main thread long enough that the system would have shown “app isn’t responding.”
Quick direction: On Unity IL2CPP Android builds, most startup ANRs mean the main thread is doing too much work before the first frame—or waiting on I/O, network, synchronous asset loads, or plugins that initialize on the UI thread. Your job is to shorten and split that work, then prove it with a capture or a clean pre-launch run.
Why this happens
- Heavy
Awake/Start/OnEnablechains – LargeResources.Load,Addressablessynchronous waits (for exampleWaitForCompletion()on an async handle), bigInstantiatebatches, or LINQ over huge lists on the first scene. - Splash screen held too long – Unity splash plus custom static splash plus blocking init before
SceneManagerloads gameplay. - Synchronous third-party SDKs – Ads, analytics, attribution, or social SDKs that block during
Applicationstartup hooks. - Shader or pipeline warmup – First-frame compilation or graphics setup spikes on low pre-launch devices.
- IL2CPP and linking – Less often the direct cause of ANR, but larger binaries and more static constructors can stretch startup if combined with the above.
- Deadlock or lock contention – Rare but real: main thread waits on background work that waits on main.
Google’s pre-launch devices are not your dev phone; they are often mid-range with stricter watchdog timing—so “works on my device” is weak evidence.
Fix 1 - Audit first scene and strip blocking calls
- Identify everything that runs before the first interactive frame: boot scene, splash scene,
RuntimeInitializeOnLoadMethod, and static constructors in types touched early. - Search for
.WaitForCompletion(),LoadAsset(synchronous),File.ReadAllText,WebRequestwithout async,Thread.Sleep,lockaround long work on the main thread. - Replace with async
Addressablesloads,async/await,UniTask(if you use it), or deferred init on frame 2+ viaStartCoroutine/ next frame callbacks. - Move non-critical SDK Init to after first frame or after menu shown—only if their docs allow late init (ads often need early registration; split consent vs heavy work per vendor guidance).
Verification: Run Development Build with Autoconnect Profiler, capture first 5 seconds, and confirm CPU main thread is not pegged continuously without yielding.
Fix 2 - Shorten and decouple the splash flow
- In Player Settings → Splash Image, avoid unnecessarily long fixed splash if you use Unity splash plus your art—combine branding into one phase where possible.
- If you use Unity’s Splash Screen API, ensure you are not performing blocking work while splash is visible without async progress.
- Load a minimal bootstrap scene first (camera + progress UI only), then asynchronously load the heavy scene.
Verification: Time from tap icon to first Update of gameplay UI on a mid-tier device; aim for no multi-second main-thread stall in profiler.
Fix 3 - Plugins and native callbacks
- List all Android plugins under Assets/Plugins/Android and Packages that run on launch.
- For each, read the vendor’s Unity integration note: move initialization off the critical path where supported (e.g. background thread safe APIs only).
- Disable non-essential plugins in a test build and re-run pre-launch to bisect which library correlates with ANR stacks.
Verification: Compare systrace / perfetto or Android Studio CPU capture with and without a suspect plugin.
Fix 4 - Graphics and first-frame cost
- Pre-warm critical shaders in a controlled moment (loading screen with progress), not hidden inside blocking calls on frame 0.
- Reduce default quality tier on low devices so first scene does not allocate huge shadow / post stacks immediately.
- Avoid sync
Shader.FindinAwakeon startup paths.
Verification: Frame Debugger / Profiler on release-like build with development options enabled for profiling.
Fix 5 - Capture and read the ANR properly
- In Play Console, open Android Vitals or Pre-launch report and download ANR or traces if offered; note “Input dispatching timed out” and main thread stack.
- If stacks show
UnityMainstuck in your C# (symbols), enable symbol upload / line numbers for IL2CPP builds so managed frames are readable (Unity Cloud Diagnostics or Play deobfuscation / symbols as applicable). - Reproduce locally with
adb shell am start -Wand strict mode / ANR settings where useful; some teams use Android Studio Profiler attached on cold start.
Verification: After fixes, upload a new .aab to internal testing and wait for a fresh pre-launch cycle; compare ANR rate before and after.
Alternative fixes
- Mono backend (if still available for your Unity version) – Useful only as a diagnostic A/B; shipping backend should match store policy and Unity support. Do not switch blindly.
- Strip managed code carefully – Over-aggressive stripping can cause lazy exceptions or unexpected paths; fix root blocking first.
- Multidex / large dex issues – Rare for typical Unity games but if you merged many Java libs, startup class loading can hurt; profile Java side if stacks point there.
Prevention tips
- Maintain a “startup budget” document: max milliseconds of main-thread work per phase (splash, menu, game).
- Add a development-only overlay that logs frame time during first N seconds.
- Run pre-launch or Firebase Test Lab on every release candidate, not only after rejection.
FAQ
Does every pre-launch ANR mean users see a dialog?
No. The system detects unresponsiveness; lab robots still record it as quality risk and it can hurt ranking.
Are IL2CPP and ANR the same problem?
IL2CPP changes build layout; ANR is main-thread responsiveness. Fix threading and init order first.
Can Addressables cause ANR?
Yes, if you use synchronous wait APIs or massive synchronous catalog parse on first frame.
Related links
- Our Unity Cloud Build Android fails after AGP or JDK update article for Gradle and pipeline stability around Android builds.
- Our Unity IL2CPP build fails symbol not found guide if you are also fighting linking and stripping.
- Our Unity guide section Building and Publishing Your Game for release hygiene.
- Official Unity manual: Android troubleshooting and Application lifecycle.
- Official Google documentation: ANRs and pre-launch reports in Play Console help.
Bookmark this fix if you ship Android often, and share it with anyone who owns SDK initialization or first-scene loading.