Flutter 3.47 Decouples Material and Cupertino, Makes Impeller Default on Desktop
With the convening of Google I/O China, Flutter 3.47 has arrived as scheduled. The main updates this time include: Material / Cupertino officially decoupled from the Flutter SDK, Impeller becoming the default renderer for all PC platforms, Widget Preview moving to Stable, continued progress on Wasm defaulting, and migration adaptations for Xcode 27 / iOS 27 / macOS 27. It's a moderate update, but at least the PC side has been strengthened.
Decoupled Packages
First, the independent versions of material_ui and cupertino_ui 1.0 have finally been released. Previously:
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
Now you can switch to:
import 'package:material_ui/material_ui.dart';
import 'package:cupertino_ui/cupertino_ui.dart';
Of course, the most important thing is that Material / Cupertino are now updated independently from Flutter's quarterly Stable cadence. Flutter currently plans for these UI packages to release fixes and new features on a weekly cadence.
Of course, version 3.47 does not force you to migrate immediately; the old import methods still work. You can migrate using Flutter's automatic migration:
dart fix --apply --code=migrate_design_widgets
Migration within your App is generally fine; the main issue is with third-party packages, for example:
Your App
├── material_ui
│
└── plugin A
└── package:flutter/material.dart
In such cases, old and new Material types might cause compatibility issues during the migration period. Flutter provides MaterialUiCompatibilityBridge to bridge this ecosystem migration gap, for example:
MaterialApp(
builder: (context, child) {
return MaterialUiCompatibilityBridge(
child: child!,
);
},
)
The main role of MaterialUiCompatibilityBridge is: to bridge ThemeData and MaterialLocalizations, allowing legacy widgets that still depend on package:flutter/material.dart to work normally within the new widget tree, adapting the correspondence between flutter.material.Theme and material_ui.Theme in scenarios like Theme.of(context).
Of course, package developers also need to pay attention. For example, if you maintain a pub.dev package and migrate it from the old Material/Cupertino API to the standalone design package, you should release it as a major release, a major version break, because this is similar for users.
Also note that Localizations have also been split. Previously:
import 'package:flutter_localizations/flutter_localizations.dart';
localizationsDelegates: [
GlobalCupertinoLocalizations.delegate,
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
]
Now the corresponding localizations for Material / Cupertino have also been moved to their respective packages. The official timeline states that the built-in package imports are planned to be officially deprecated in November this year, so it's best to check if your dependent packages are still maintained and whether migration is needed.
Impeller
Starting with Flutter 3.47, all three PC platforms have fully switched to Impeller by default. This means Flutter GPU and the various 3D rendering and gaming capabilities we mentioned before are officially supported on all platforms except Web. However, fallback interfaces are still provided:
macOS:
FLTEnableImpeller = falseWindows:
project.set_impeller_switch( flutter::ImpellerSwitch::Disabled );Linux:
fl_dart_project_set_enable_impeller( project, FALSE );
The Desktop text issues we mentioned before have also been addressed. Flutter 3.47's Impeller Desktop now uses SDF (Signed Distance Function) for text and vector curve rendering. Because desktops generally have better GPU performance but often lower DPI, issues like blurry fonts are more common. SDF can leverage more GPU computation to achieve sharper, more stable edge performance.
Renderer optimizations are also being reworked for Desktop visual characteristics. Additionally, macOS has enabled Wide Gamut Color by default this time, supporting hardware rendering with a wider color gamut.
This wave finally brings a major boost to the PC side.
Flutter Multi-Window
Multi-window continues to make progress. For example, Windows / Linux now support popup windows, enabling some things that were previously difficult to make truly "desktop native," such as:
- Context Menu
- Floating palette
- Tool window
- Popup
These scenarios now support being implemented through truly independent native windows, and you can even directly access the underlying native window. Now the platform-specific controller can obtain:
- Windows: HWND
- macOS: NSWindow
- Linux: GtkWindow
This capability is very practical. As we discussed in previous articles, this means when Flutter Desktop encounters capabilities not covered by the framework API, you can directly access:
Flutter
↓
windowHandle
↓
Win32 / AppKit / GTK
For example, the official Windows Dockable Pane demo shows that for truly complex Desktop Apps, this is a crucial escape hatch.
Additionally, several old multi-window issues have been fixed. For example, as we mentioned before, on Windows, activating one window might previously pull other background windows to the front, or windows might steal focus after the app resumes. These issues have been fixed.
Linux has also modified the window realization order to avoid warnings/assertions during the first frame. Additionally, sized-to-content has been added, allowing ordinary Windows/Dialogs to automatically calculate window size based on Flutter content.
The only pity is that it's still experimental.
Finally, Windows / Linux finally support Flavors. Now you can:
flutter build windows --flavor flavor_a
and
flutter build linux --flavor flavor_a
Assets can also be differentiated by flavor:
flutter:
assets:
- path: assets/flavor_a/images
flavors:
- flavor_a
- path: assets/flavor_b/images
flavors:
- flavor_c
Xcode 27 / iOS 27 / macOS 27
Starting with Flutter 3.47, the new minimum supported version has been raised to 15 for iOS, and macOS has been raised to 12:
| Platform | Before | Flutter 3.47+ |
|---|---|---|
| iOS | 13 | 15 |
| macOS | 10.15 | 12 |
At the same time, UIScene has become a mandatory requirement. Apps not adapted to UIScene will fail to launch directly on Xcode 27.
Additionally, Intel Mac support has been discontinued. Flutter 3.47 has stopped automated testing for Intel Macs, and Intel Macs are entering the phase-out stage. It is recommended to package directly using flutter config --enable-macos-arm64-only.
Finally, the SwiftPM migration is nearly complete. Among the Top 100 iOS Flutter Plugins, 92 have already migrated to Swift Package Manager:
Since Flutter 3.44, SwiftPM has become the default solution for iOS/macOS native dependency management. CocoaPods will continue to be supported but is in maintenance mode.
Of course, more importantly, the CocoaPods Registry will become permanently read-only on December 2, 2026.
Version 3.47 also optimizes the SwiftPM build pipeline by filtering out package schemes that don't need to be built in advance, so Flutter iOS/macOS projects using SwiftPM will see further build time optimizations.
Web
Wasm now supports Deferred Loading. Version 3.47 provides this experimentally on the main channel:
flutter build web \
--release \
--wasm \
--enable-wasm-deferred-loading
The goal is to split a very large Wasm file into multiple modules, loading only the core at startup and loading other code on demand. This can help solve the problem of pages opening too slowly.
Additionally, the official team has stated that flutter build web --release --wasm will become the default in the future. Flutter Web should completely shift to Wasm as its sole renderer going forward.
Android
The main update for Android this time is the baseline update, primarily:
| Item | Flutter 3.47 |
|---|---|
| Java | 17, minimum required |
| Kotlin Gradle Plugin | 2.4.0 |
| Android Gradle Plugin | 9.1.0 |
| Gradle | 9.3.1 |
Additionally, the default Android API parameters provided by the Flutter SDK are:
compileSdkVersion = API 36
targetSdkVersion = API 36
minSdkVersion = API 24
That is, the default variable value currently provided by the 3.47 SDK suggests a minimum of 24.
Other
Other updates include:
Widget Preview is officially Stable, having graduated. Although I've never used it.
GenUI updated to 0.10.0.
a2ui_corehas been extracted into an independent core package, and it now supports A2UI client-side functions. An Agent can tell the Flutter Client to call client-side functions for certain logic without needing to ask the large model for everything.An Android keyboard bug has been fixed. The key responder will no longer fabricate physical key events for virtual keyboard input.
Accessibility has also received some API updates. Android high contrast and color inversion settings can now be automatically detected (
MediaQueryData.highContrastandMediaQueryData.invertColors). Nested text spans withinText.richcan now match the layout order in the semantic tree. Keyboard focus blocking has also been added toBlockSemantics.Text Selectionhas fixed a batch of details, such as the Selection Handle no longer jumping around during slight scrolling on mobile (the first gif below shows the jumping), and keyboard shortcuts can close the current selection menu.
A crash in
SelectableRegionwhen selecting within an empty scrollable container has also been fixed, along with a visual highlight issue on faded selectable text:PlatformView gestures continue to be fixed. Gesture propagation between Flutter Gesture and UIKit View Gesture has been optimized.
EdgeDraggingAutoScrollernow respectsScrollPhysicssettings, so locked lists like those usingNeverScrollableScrollPhysicswill not auto-scroll due to edge dragging.ImageIcon'sisOriginalColors: truecan preserve the original image colors without forcing them to be treated as an Icon tint.AnimatedCrossFadecan explicitly specify clipping behavior.ImageStreamListenercan now directly track image stream errors.Graphics also has a Breaking Change. Flutter 3.47 adjusted the coordinate handling for OpenGL ES render-to-texture. Previously, fragment shaders might need to do a
Y coordinate flipthemselves when reading a texture; this step has now been moved to the vertex shader, so fragment shaders no longer need to do conditional coordinate flipping.
Finally
This update is a relatively minor version update. The core is the formal logic of package decoupling, followed by a major boost to the PC side. Of course, although multi-window has made a big breakthrough, it still hasn't entered stable. But it's not a big problem; I've been using it for a while, and basic daily multi-window usage is generally fine.
So, young man, start trying the new crab.
Top 1 from juejin.cn, machine-translated. The original thread is authoritative.
Can assets also be differentiated by flavor, and does it support Android and iOS?