Mobile Development 14 min read

Migrating Flutter iOS Apps to the New UIScene Lifecycle (iOS 26+)

This guide explains why Apple now mandates UIScene for all UIKit apps built with the latest SDK after iOS 26, how UIScene differs from the traditional UIApplicationDelegate model, and provides step‑by‑step instructions—both automated and manual—for Flutter developers to migrate their iOS projects and plugins.

Sohu Tech Products
Sohu Tech Products
Sohu Tech Products
Migrating Flutter iOS Apps to the New UIScene Lifecycle (iOS 26+)

At WWDC25 Apple released Technical Note TN3187, stating that any UIKit app built with the latest SDK for iOS 26 or later must adopt the UIScene lifecycle, otherwise it will fail to launch.

Although UIScene was introduced in iOS 13, its core idea is to separate the application process lifecycle from the UI instance lifecycle, allowing multiple independent UI instances.

Before iOS 13 the lifecycle was managed by a monolithic UIApplicationDelegate model, handling process start/termination, UI state changes, window management and system‑level events. application(_:didFinishLaunchingWithOptions:) / applicationWillTerminate(_:) – start and end of the process. applicationDidBecomeActive(_:), applicationDidEnterBackground(_:) – UI state changes. AppDelegate owned the single UIWindow instance.

System events such as remote notifications and URL schemes were also handled here.

This single‑model architecture binds the app process tightly to a single UI state, which works for Flutter because Flutter’s default architecture is a single‑page model. However, with TN3187 Flutter must fully migrate to the UIScene model.

The UIScene model introduces three key concepts: UIScene – represents an independent UI instance, typically a UIWindowScene that manages one or more windows. UISceneSession – a persistent object storing configuration and state for a scene, enabling state restoration. UISceneDelegate – the delegate that handles scene‑level lifecycle events such as connect, disconnect, foreground, and background transitions.

Consequently, responsibilities split between UIApplicationDelegate (process‑level tasks) and UISceneDelegate (UI‑level tasks). For example, applicationDidBecomeActive(_:) moves to sceneDidBecomeActive(_:), and applicationWillEnterForeground(_:) moves to sceneWillEnterForeground(_:).

Old → New mapping (excerpt)
application(_:didFinishLaunchingWithOptions:) → scene(_:willConnectTo:options:)
applicationDidBecomeActive(_) → sceneDidBecomeActive(_)
applicationWillResignActive(_) → sceneWillResignActive(_)
applicationDidEnterBackground(_) → sceneDidEnterBackground(_)
applicationWillEnterForeground(_) → sceneWillEnterForeground(_)
applicationWillTerminate(_) → sceneDidDisconnect(_)

For Flutter the migration impacts three layers:

Engine rendering logic : the engine must listen to UIScene notifications instead of the global UIApplication notifications to pause and resume rendering correctly in multi‑window scenarios.

Deprecated API replacement : calls such as UIApplication.shared.keyWindow must be replaced with scene‑aware window retrieval.

Plugin registration : plugins that depend on UI lifecycle events (e.g., url_launcher_ios, local_auth_darwin, image_picker_ios, google_sign_in_ios, quick_actions_ios) need to handle both the old AppDelegate callbacks and the new SceneDelegate callbacks.

Flutter offers two migration paths:

Automated migration (recommended)

Enable the experimental migration flag: flutter config --enable-uiscene-migration Run flutter build ios or flutter run. The tool will modify AppDelegate, create a SceneDelegate, and update Info.plist with the required UIApplicationSceneManifest configuration.

Successful migration prints “Finished migration to UIScene lifecycle” in the build log.

Manual migration (for complex projects)

Remove all UI‑related methods from AppDelegate.swift (e.g., applicationDidBecomeActive(_:), applicationWillResignActive(_:), etc.) while keeping application(_:didFinishLaunchingWithOptions:) for global initialization.

Create SceneDelegate.swift inheriting from FlutterSceneDelegate and implement needed scene callbacks.

Update Info.plist to include UIApplicationSceneManifest with UIWindowSceneSessionRoleApplication and the SceneDelegate class name.

Move any custom logic that depends on a UI window (e.g., method channel registration, platform view setup) from didFinishLaunchingWithOptions to scene(_:willConnectTo:options:) or didInitializeImplicitFlutterEngine.

For plugins, register both AppDelegate and SceneDelegate listeners, implement dual lifecycle methods (e.g., applicationDidEnterBackground and sceneDidEnterBackground) with a flag to avoid duplicate execution, and replace deprecated window APIs with scene‑aware equivalents.

Example of a minimal SceneDelegate:

import UIKit
import Flutter

class SceneDelegate: FlutterSceneDelegate {
    // Override FlutterSceneDelegate methods here to add custom scene‑level logic.
}

Example of updating a plugin’s window access:

// Before migration
if let window = UIApplication.shared.keyWindow {
    // use window
}

// After migration
if let window = self.pluginRegistrar.view?.window?.windowScene?.keyWindow {
    // use scene‑aware window
}

Plugin authors must ensure compatibility with both pre‑ and post‑migration apps, handling dual lifecycle callbacks and replacing any single‑window APIs.

Adapting plugins to the new UIScene model increases development cost, especially for third‑party developers, because the change revives historical technical debt in the iOS ecosystem.

Flutter 3.38.0‑0.1.pre has just been released, bringing the migration challenges to the next Flutter release.

FlutteriOSUIKitUIScene
Sohu Tech Products
Written by

Sohu Tech Products

A knowledge-sharing platform for Sohu's technology products. As a leading Chinese internet brand with media, video, search, and gaming services and over 700 million users, Sohu continuously drives tech innovation and practice. We’ll share practical insights and tech news here.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.