Two iOS changes reach Flutter apps this year, and the Flutter tool handles only part of each.
The first is the scene life cycle. The Flutter breaking-change page says: "Flutter apps built with Xcode 27 that do not adopt UIScene fail to launch on startup." The second is CocoaPods. The SwiftPM page for app developers notes that "the CocoaPods registry permanently becomes read-only on December 2, 2026."
The question for a Flutter team is not whether Flutter supports both. It does. The question is whether your project is one Flutter can move automatically.
When the automatic migration applies
From the same page: "In Flutter 3.41 and later, if your project uses an unmodified AppDelegate, Flutter migrates it automatically."
The word that matters is unmodified. Many production apps touched AppDelegate.swift years ago: a notification delegate, a method channel, a deep link handler, a Firebase setup line. Any of those takes the app off the automatic path.
To check the difference, I made two copies of a new Flutter app (local Flutter 3.41.5) and put them back in the pre-scene state: no SceneDelegate.swift, no UIApplicationSceneManifest, the old template AppDelegate. One keeps that AppDelegate as it was. The other gets the kind of changes real apps have:
UNUserNotificationCenter.current().delegate = self
application.registerForRemoteNotifications()
GeneratedPluginRegistrant.register(with: self)
plus an application(_:open:options:) override, and shared_preferences, url_launcher, firebase_core and firebase_messaging as plugins.
I ran sdkbump, an open-source CLI I wrote, on both:
npx @mcamdali/sdkbump
The unmodified copy (exit code 1):
ERROR SCN001 No scene configuration
ios/Runner/Info.plist
Fix: [A] Let Flutter 3.41 or later migrate the app; or [B] Migrate the Flutter app by hand
[A] Let Flutter 3.41 or later migrate the app
1. Upgrade to Flutter 3.41 or later.
2. Run `flutter build ios` (or `flutter run`). With an unmodified AppDelegate and
UIMainStoryboardFile set to Main, it rewrites AppDelegate and Info.plist and prints
"Finished migration to UIScene lifecycle".
1 error, 0 warnings
The customised copy (exit code 1):
ERROR SCN001 No scene configuration
... Flutter
will not migrate it automatically: ios/Runner/AppDelegate.swift differs from the templates
Flutter migrates.
Fix: [A] Migrate the Flutter app by hand
WARNING SCN003 application(_:open:options:) is not called with scenes
ios/Runner/AppDelegate.swift:17
Fix: [B] Handle it in a FlutterSceneDelegate subclass
1 error, 1 warning
Same missing manifest, different fix. And a project made today with flutter create --platforms=ios already has the scene files; sdkbump reports 0 errors, 0 warnings on it.
The manual migration, step by step
The Flutter page lists the steps. In short:
1. Register plugins in the new callback. The docs: "you must now register plugins in a new didInitializeImplicitFlutterEngine callback." Their example:
@objc class AppDelegate: FlutterAppDelegate, FlutterImplicitEngineDelegate {
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
func didInitializeImplicitFlutterEngine(_ engineBridge: FlutterImplicitEngineBridge) {
GeneratedPluginRegistrant.register(with: engineBridge.pluginRegistry)
}
}
Method channels and platform views that you set up in didFinishLaunching move there too, according to the sdkbump fix text.
2. Add the scene manifest to Info.plist, with FlutterSceneDelegate as UISceneDelegateClassName and Main as the storyboard. The page has the full XML block.
3. Move UI events to a scene delegate. "UIKit no longer calls AppDelegate methods related to UI state." The page maps application:openURL:options: to scene:openURLContexts:. If you write your own scene delegate, it has to subclass FlutterSceneDelegate (or conform to FlutterSceneLifeCycleProvider), and the sdkbump fix adds: call super, so plugins still receive the event.
What stays early: the Flutter page lists UNUserNotificationCenterDelegate among the Apple APIs that "must be configured before app launch finishes", so the notification delegate is not something to defer to the scene.
The second change: SwiftPM by default, CocoaPods as fallback
"As of the 3.44 release, Flutter's Swift Package Manager (SwiftPM) support is on by default." The next part is the one teams miss: "Flutter falls back to CocoaPods for dependencies that don't yet support Swift Package Manager."
So switching Flutter versions does not remove CocoaPods from your build by itself. Any plugin without a Swift package keeps your app on a registry that stops accepting new versions on December 2. Turning SwiftPM off is not a long-term option either; the page says "disabling SwiftPM won't be allowed in the future."
To see what was still coming from CocoaPods in the customised app, I ran podexit, another tool of mine, on its ios/Podfile.lock:
npx @mcamdali/podexit
ios/Podfile.lock Flutter app · 14 pods, 5 in the Podfile
Firebase 12.19.3 12.19.3 capped at 12.x yes (Firebase) firebase_core +1
FirebaseMessaging 12.19.0 12.19.0 capped at 12.x yes (Firebase) Firebase
GoogleUtilities 8.1.5 8.1.5 capped with Firebase yes FirebaseCore +3
0 frozen on trunk · 9 capped by the publisher · 5 not affected
9 pods with a Swift package · 0 without · 0 unknown
An honest result: in this plugin set, nothing is stuck on trunk. The nine capped pods are Firebase and its dependencies, which the Firebase migration page caps at version 12, and all nine have a Swift package. The five "not affected" pods are the Flutter pod and the four plugin pods, which come from local paths. A project with a plugin that ships only a podspec would look different; that is the case to look for.
Limitations
- My local Flutter is 3.41.5. I did not test the 3.44 SwiftPM default locally; that part comes from the Flutter docs.
- Both tools read files only. Neither builds the app, so confirm with an Xcode 27 build and a launch on a device.
- The test projects are small and made for this check; a production app will have more plugins and more delegate code.
Try it
In the Flutter app root (both tools find ios/ themselves; Node.js 22.12 or later):
npx @mcamdali/sdkbump
npx @mcamdali/podexit
For the CocoaPods side in more depth, see "CocoaPods trunk goes read-only on December 2: what stops, what keeps working, and how to read your Podfile.lock".
Repositories: github.com/muhittincamdali/sdkbump · github.com/muhittincamdali/podexit (MIT).
Muhittin Camdali is a mobile engineer (Flutter, iOS, React Native) and the author of sdkbump and podexit.
Top comments (0)