KORTRESS
2026-10-04• engineering

Why Flutter Apps Working on iOS 26 Crash in iOS 27 Simulators (and How to Fix It)

by Ko

The Symptom: Instant SIGTRAP Crash on Launch

A Flutter application running cleanly on iOS 26 simulators without any warnings crashed immediately upon launch on the iOS 27 simulator when built with Xcode 27 (iOS 27 SDK).

The actual crash report (~/Library/Logs/DiagnosticReports/Runner-*.ips) recorded the following trace:

Exception Type:  EXC_BREAKPOINT (SIGTRAP)

Thread 0 Crashed:
0  UIKitCore          ___UIApplicationEvaluateRuntimeIssueForNoSceneLifecycleAdoption_block_invoke
1  libdispatch.dylib  _dispatch_client_callout
2  libdispatch.dylib  _dispatch_once_callout
3  UIKitCore          -[UIApplication workspace:didCreateScene:withTransitionContext:completion:]
4  UIKitCore          -[UIApplicationSceneClientAgent scene:didInitializeWithEvent:completion:]
5  FrontBoardServices __95-[FBSScene _callOutQueue_didCreateWithTransitionContext:alternativeCreationCallout:completion:]_block_invoke

The critical error symbol is UIApplicationEvaluateRuntimeIssueForNoSceneLifecycleAdoption, throwing a SIGTRAP signal that immediately halts the main thread before any user application code runs, right at the system scene creation stage.


Root Cause: Hard Enforcement of the UIScene Lifecycle

This crash is not a bug; it is an intentional runtime block enforced by Apple's lifecycle policy.

1. The Demise of the Single-Window Legacy Pattern

Historically, iOS apps relied solely on UIApplicationDelegate to manage both the application lifecycle and the UIWindow. While iOS 13 introduced UIScene and UISceneDelegate for multi-window support, single-window apps using only UIApplicationDelegate were permitted to run for backward compatibility.

2. The Trigger: "Was It Built with the iOS 27 SDK?"

Apple announced in TN3187:

In the next major release following iOS 26, UIScene lifecycle will be required when building with the latest SDK; otherwise, your app won't launch.

The decisive factor is not the device's operating system version, but the SDK version used to compile the binary. Verified results:

Identical Xcode 27 BuildBefore FixAfter Fix
iOS 27 SimulatorCrashes immediatelyLaunches normally
iOS 26.4 SimulatorLaunches normallyLaunches normally

Binaries compiled with Xcode 26 and deployed to the App Store remain largely unaffected on iOS 27 devices. The vulnerability arises when new builds are compiled using Xcode 27. If Xcode updated automatically, verify whether the archive's DTSDKName is set to iphoneos27.0.


Solution: Flutter App Migration (Battle-Tested)

1) Upgrade to Flutter 3.38+

FlutterSceneDelegate and FlutterImplicitEngineDelegate are officially available starting in Flutter 3.38. Prior versions lack these primitives. In my setup, the project was pinned to 3.41.9 using fvm:

fvm use 3.41.9
fvm flutter clean
fvm flutter pub get

Always execute flutter clean after modifying Flutter versions to prevent residual build artifacts from triggering header or architecture linkage errors.

2) Add UIApplicationSceneManifest to Info.plist

Specify FlutterSceneDelegate as the scene delegate. If your app launches FlutterViewController via Main.storyboard (the default template), you must also supply UISceneStoryboardFile.

<key>UIApplicationSceneManifest</key>
<dict>
    <key>UIApplicationSupportsMultipleScenes</key>
    <false/>
    <key>UISceneConfigurations</key>
    <dict>
        <key>UIWindowSceneSessionRoleApplication</key>
        <array>
            <dict>
                <key>UISceneClassName</key>
                <string>UIWindowScene</string>
                <key>UISceneDelegateClassName</key>
                <string>FlutterSceneDelegate</string>
                <key>UISceneConfigurationName</key>
                <string>flutter</string>
                <key>UISceneStoryboardFile</key>
                <string>Main</string>
            </dict>
        </array>
    </dict>
</dict>

3) Refactor AppDelegate.swift: Relocate Channel and Plugin Registrations

This step requires manual intervention. The conventional pattern:

// FlutterViewController does NOT exist yet during didFinishLaunching
let controller = window?.rootViewController as! FlutterViewController

is invalid in the UIScene paradigm because the Flutter view has not been instantiated when the application launches. Adopt FlutterImplicitEngineDelegate and move plugin registrations and FlutterMethodChannel creation to the engine ready callback:

import Flutter
import UIKit

@main
@objc class AppDelegate: FlutterAppDelegate, FlutterImplicitEngineDelegate {
  override func application(
    _ application: UIApplication,
    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
  ) -> Bool {
    // Retain only screen-agnostic configurations like early SDK initializations
    return super.application(application, didFinishLaunchingWithOptions: launchOptions)
  }

  // Invoked once the engine spawned by the storyboard's FlutterViewController is initialized
  func didInitializeImplicitFlutterEngine(_ engineBridge: FlutterImplicitEngineBridge) {
    GeneratedPluginRegistrant.register(with: engineBridge.pluginRegistry)
    let messenger = engineBridge.applicationRegistrar.messenger()

    let channel = FlutterMethodChannel(name: "com.example.app/config", binaryMessenger: messenger)
    channel.setMethodCallHandler { call, result in
      // Existing handler logic
    }
  }
}

Move any calls to GeneratedPluginRegistrant.register(with: self) from didFinishLaunching into this callback.

4) If the App Hangs at the Native Splash Screen: Update Plugins

After applying steps 1–3, the crash disappeared, but the app hung indefinitely on the native splash screen without rendering the Flutter landing screen. All SDK initializations succeeded in logs.

The culprit was legacy plugins lacking UIScene compatibility. The issue was resolved by upgrading:

  • firebase_core ^4.14 and firebase_messaging 16.6.0 (Run pod update Firebase for underlying iOS SDKs)
    • Following the firebase_messaging documentation for "iOS apps using UIScene", remove code setting UNUserNotificationCenter.current().delegate = self, and call FLTFirebaseMessagingPlugin.configureNotificationCenterDelegate() prior to super in didFinishLaunching.
  • google_sign_in 7.x (google_sign_in_ios 6.3.0 explicitly notes "Adds UIScene compatibility", which is consumed in 7.x). Note that 7.x introduces Dart API changes requiring updates to authentication logic.

Run flutter clean after bumping plugins to ensure clean compilation. Check the changelog of each plugin for explicit "UIScene" support.


Note for Native UIKit Applications

For pure UIKit apps, the principle remains identical: implement a SceneDelegate adopting UIWindowSceneDelegate, migrate window attachment logic from AppDelegate to scene(_:willConnectTo:options:), and set UISceneDelegateClassName to $(PRODUCT_MODULE_NAME).SceneDelegate in Info.plist.


Summary

  • Cause: Compiling with the iOS 27 SDK (Xcode 27) enforces the UIScene lifecycle. Missing it triggers UIApplicationEvaluateRuntimeIssueForNoSceneLifecycleAdoption and halts with SIGTRAP. The build SDK is the triggering condition, not the device OS.
  • Flutter Migration Path:
    1. Upgrade to Flutter 3.38+ (e.g., 3.41.9 via fvm)
    2. Declare FlutterSceneDelegate in Info.plist
    3. Remove rootViewController as! FlutterViewController; register plugins and MethodChannels inside didInitializeImplicitFlutterEngine
    4. If frozen at the splash screen, update plugins to versions with UIScene support (firebase_messaging, google_sign_in, etc.)
  • Verification: Run the identical Xcode 27 build against both iOS 26 and iOS 27 simulators to verify parity.

Comments (0)

Be the first to leave a comment.