Question: How to prevent Flutter app crash on iOS 18 during cold start when iOS traverses view hierarchy before Flutter engine is fully initialized?
Help needed: Looking for a way to either delay iOS view hierarchy traversal or ensure Flutter is fully initialized before iOS lifecycle callbacks fire.
Problem Summary
Our Flutter app crashes on cold start for approximately 1-2% of iOS users. The crash occurs specifically on iOS and only under these exact conditions:
When crash happens:
- User opens app and uses it normally ✅
- User minimizes app (goes to background) ✅
- User returns to app from background ✅ (works fine)
- User kills app from app switcher (swipe up to close)
- User taps app icon to launch again → CRASH ❌
Key observations:
- Crash is intermittent - app may open on 2nd, 3rd, or 5th attempt
- 100% reproducible on affected devices by repeating kill→launch cycle
- ~98% of users have no issues
Environment
- Flutter: 3.38.3
Crash Logs (from Sentry)
Crash Type 1: Stack Overflow (most common)
OS Version: iOS 18.7.2 (22H124) Exception Type: EXC_BAD_ACCESS (SIGBUS) Exception Codes: BUS_NOOP at 0x000000016ad5be90
Application Specific Information: compare:options:range:locale: > Stack overflow in (null)
Thread 0 Crashed: 0 CoreFoundation CFStringGetLength 1 CoreFoundation CFStringCompareWithOptionsAndLocale 2 CoreFoundation <redacted> 3 libsystem_c bsearch 4 CoreFoundation <redacted> 5 UIKitCore <redacted> ... 15-99: UIKitCore 0x30e177148 [inlined] <redacted> // 85+ recursive calls
Crash Type 2: Use-After-Free
Exception Type: EXC_BAD_ACCESS (SIGSEGV) Exception Codes: SEGV_NOOP at 0x0500007f14000000 KERN_INVALID_ADDRESS at 0x500007f14000000
Thread 0 Crashed: 0 libobjc.A.dylib objc_retainAutoreleaseReturnValue 1 UIKitCore <redacted> ... 6 libobjc.A.dylib objcrootDealloc 7 QuartzCore <redacted> // CALayer operations
What We Tried (nothing solved cold start crash)
Increased stack size to 64MB (-Wl,-stack_size,0x4000000) | ❌ No effect |
| Disabled iOS State Restoration | ❌ No effect |
Added isViewLoaded checks in AppDelegate | ❌ No effect |
| Added try-catch around GetStorage/SecureStorage init | ❌ No effect |
Added isAppActive flag to track app state | ❌ No effect |
Snapshot overlay in applicationWillResignActive | ✅ Fixed background→foreground crash, ❌ but NOT cold start |
Current AppDelegate.swift
import UIKit import Flutter
@main
@objc
class AppDelegate: FlutterAppDelegate {
private var snapshotView: UIView?
private var isAppActive = false
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
GeneratedPluginRegistrant.register(with: self)
window?.overrideUserInterfaceStyle = .light
isAppActive = true
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
override func application(_ application: UIApplication, shouldSaveSecureApplicationState coder: NSCoder) -> Bool {
return false
}
override func application(_ application: UIApplication, shouldRestoreSecureApplicationState coder: NSCoder) -> Bool {
return false
}
override func applicationWillResignActive(_ application: UIApplication) {
guard isAppActive,
let window = self.window,
let rootVC = window.rootViewController,
rootVC.isViewLoaded,
snapshotView == nil
else { return }
let snapshot = UIView(frame: window.bounds)
snapshot.backgroundColor = .white
snapshot.tag = 999
window.addSubview(snapshot)
snapshotView = snapshot
}
override func applicationDidBecomeActive(_ application: UIApplication) {
guard snapshotView != nil else {
isAppActive = true
return
}
snapshotView?.removeFromSuperview()
snapshotView = nil
}
}