Flutter 3.41 发布,快来看看有什么更新吧,这是一个有小惊喜的版本
可以看到,3.41 更多是一个问题修复版本,没有什么重大更新,不过一些细节改进,例如 Platform-specific assets和等调整还是挺不错的, Add-to-App 的 UI 自缩放支持也算是难得的更新,PC 多窗口距离稳定版也不远了,那么,你准备好更新 3.41 了吗?最后,提前祝大家,春节快乐~~~
马上就要春节了,Flutter 3.41 突然来袭,当然,作为每年的第一个版本不会有重大更新,3.41 主要涉及:
- 继续推进 Material 和 Cupertino 库的解耦
- 深度集成 Swift Package Manager 并默认支持 iOS 的
UIScene - Android 端新增对 AGP 9 和 Kotlin DSL 的支持
- 新增按平台打包资源(减少应用体积)、同步图像解码(优化着色器性能)以及嵌入式视图自动缩放
- 升级了 DevTools 性能,改善了 Widget Previews 实验性功能对
dart:ffi的支持
另外,Flutter 也公布了 2026 四个大版本的发布计划:
- Flutter 3.41 — 2 月发布,基于 1 月 6 日 分支
- Flutter 3.44 — 5 月发布 ,基于 4 月 7 日分支
- Flutter 3.47 — 8 月发布,基于 7 月 7 日分支
- Flutter 3.50 — 11月发布,基于 10 月 6 日分支
有趣的是,没有看到 4.0 版本规划,官方这是爱上了 3.x ?,天知道我在写 3.41 时打错了多少次 3.14。
Material 和 Cupertino 解耦
目前官方正在持续推动 Material 和 Cupertino 解耦支持,也就是 Flutter 3.41 还没落地,但是计划中应该今年可以落地,对于这个解耦的好处,主要在于:
- 不需要等待季度 SDK 发布才能发布设计更新
- 可以支持较旧的 SDK 版本
- 独立的 “Liquid Glass” 和 “Material 3 Expressive” 可选支持

更多可见之前发布过的 《Flutter UI 设计库解耦重构进度,官方解答未来如何适配》
生态更新
Swift Package Manager 和 UIScene
Flutter 3.41 版本里从 CocoaPods 向 Swift Package Manager 的过渡仍在继续,不过 Flutter 官方强烈建议插件作者采用 Swift Package Manager,因为现在它才是苹果生态系统的标准,另外为了确保与未来 iOS 版本的兼容性,Flutter 现在默认完全支持 UIScene 生命周期 。
关于 UIScene 支持,可见之前的 《iOS 26 开始强制 UIScene ,你的 Flutter 插件准备好迁移支持了吗?》
AGP 9 和 Kotlin DSL
AGP 9 支持还在推进中,所以,暂时不要将你的项目/插件更新到 AGP 9,因为 3.41 还不支持 AGP 9,目前 #181383 仍在持续推进,至于为什么 AGP 9 那么特别?如果你还没了解,可以看 《Android Gradle Plugin 9.0 发布,为什么这会是个史诗级大坑版本》
另外,新的插件项目现在默认使用 Kotlin DSL 来运行 Gradle,也就是 Flutter 在 Android 平台也全面转向 Kotlin DSL 。
Android 生态现在 Gradle、AGP、JDK、Andriod Studio、Kotlin ,环境和构建版本的耦合还真不少····
Platform-specific assets
这算是 Flutter 3.41 里最实用的更新,从 Flutter 3.41 开始,现在可以在 pubspec.yaml 里指定 assets 应该捆绑在哪些平台,这算是一个非常不错的优化,比如可以在移动端版本中剔除大量桌面资源:
lutter:
assets:
- path: assets/logo.png
- path: assets/web_worker.js
platforms: [web]
- path: assets/desktop_icon.png
platforms: [windows, linux, macos]
片段着色器的改进
从 3.41 版本开始,现在增加了同步图像解码支持,例如在以前,为 shader 创建贴图可能会带来帧延迟,但是现在新增了 decodeImageFromPixelsSync 之后,现在可以生成纹理,并在同一帧中将它们用作采样器。
final Image image = decodeImageFromPixelsSync(pixels, width, height, PixelFormat.rgba8888);
此外还增加了对高码率纹理的支持(最高可达 128 位浮点),解锁了使用高分辨率查找表(LUT)用于 GPU 加速照片滤镜和 SDF 的功能。
void attachTexture(ui.FragmentShader shader) {
ui.PictureRecorder recorder = ui.PictureRecorder();
Canvas canvas = Canvas(recorder);
canvas.drawCircle(const Offset(64, 64), 64, Paint()..color = Colors.red);
ui.Picture picture = recorder.endRecording();
ui.Image image = picture.toImageSync(
128,
128,
targetFormat: ui.TargetPixelFormat.rFloat32,
);
shader.setImageSampler(0, image);
}
Widget Preview
在 Flutter 3.41 开始,Flutter Inspector 在 Widget Preview 环境可以支持使用,目前是实验阶段,也就是在预览下可以方便查看预览控件的状态,暂时还需要配置额外的包目录,比如点击图标打开 Flutter Inspector 设置,添加一个指向你项目的新包目录:

另外,还有支持带有 dart:ffi 依赖的应用场景,在此之前如果包含对 dart:ffi 库具有传递依赖的 Widget 预览会出现编译错误,这是因为 dart:ffi 不支持 Web 平台,而现在 Widget Preview 现在可以处理依赖特定平台库的预览,包括 dart:ffi 和 dart:io。
PS :Widget 预览器还是不支持直接调用这些库中的 API 。
Framework
iOS
从 Flutter 3.41 开始增加了新的 “bounded blur” 风格样式支持,之前使用 BackdropFilter 的半透明 Widget 可能会在边缘出现颜色溢出,而得益于 Impeller 渲染引擎的改进,现在消除了这个伪影问题。

额外提一句:Avalonia 也宣布投资 Impeller , 和 Flutter 团队合作将他们的 GPU 优先渲染器 Impeller 移植到 .NET 平台 。
另外,在 iOS 平台, CupertinoSheet 还支持通过 showDragHandle 添加原生样式拖拽处理的支持:
Navigator.push<void>(
scaffoldKey.currentContext!,
CupertinoSheetRoute<void>(
showDragHandle: true,
builder: (BuildContext context) {
return const CupertinoPageScaffold(child: Text('Page 2'));
},
),
);

Add-to-App
久违的看到了 Add-to-App 更新,从 Flutter 3.41 开始,向现有的 Android 和 iOS 应用添加 Flutter 视图变得更加简单,因为在现有原生应用中嵌入的 Flutter 视图可以根据内容自动调整大小。
在 3.41 之前,Flutter 视图需要由其原生父节点提供的固定大小,所以如果需要将 Flutter 视图潜入到原生可滚动视图,默认情况下会比较麻烦。
当然,要在 Add-to-App 支持这个能力,你的 Root 控件必须支持 unbounded constraints,也就是避免在树顶端使用需要预定义大小的 Widget(如 ListView 或 LayoutBuilder),因为它们会与动态大小逻辑冲突:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
Widget build(BuildContext context)
=> MaterialApp(home: MyPage());
}
class MyPage extends StatelessWidget {
Widget build(BuildContext context) {
return Scaffold(
body: UnconstrainedBox(
// TODO: Edit this line to check if a widget
// can cause problems with content-sized views.
child: Text('This works!'),
// child: Column(children: [Column(children: [Expanded(child: Text('This blows up!'))])]),
// child: ListView(children: [Text('This blows up!')]),
)
);
}
}
如果想开启这个能力:
-
iOS:设置
FlutterViewController.isAutoResizable为true -
Android: Android Manifest 中启用 content sizing,并将 FlutterView 的宽度或高度设置为
content_wrap<meta-data android:name="io.flutter.embedding.android.EnableContentSizing" android:value="true" />
![]() |
![]() |
|---|
导航与滚动
从 3.41 开始,Flutter 引入了 Navigator.popUntilWithResult,可以让开发者在一次调用中弹出多个屏幕并将值传回目的地路由:
Navigator.popUntilWithResult<bool>(
context,
(Route<dynamic> route) => route.isFirst,
true,
);

天啊,2026 了 Flutter 终于想起来内置这个支持。
另外,在 Flutter 3.41 里,官方用从 Android 12 移植过来的基于仿真的方法重新实现了 StretchingOverScrollIndicator,现在可以确保了对高速 flings 的反应更自然:

此外还修复了 NestedScrollView 和 SliverMainAxisGroup 中的 pinned headers 问题,确保头部正确重叠后续的 slivers 显示。
Accessibility
在 Flutter 3.41 里 Accessibility 也做了一些调整,例如
CirCularProgressIndicator和LinearProgressIndicator的原生无障碍支持- Flutter 支持 Web 用户的文字间距覆盖
- 在 flutter_test 引入了新的匹配器,如
isSemantics和accessibilityAnnouncement
Material 和 animation
Flutter 3.41 引入了新的原语和属性,从而扩展了对动画和布局的控制,例如 RepeatingAnimationBuilder 引入了一种声明式方式,可以创建连续动画,比如加载指示器、pulsing 按钮或闪烁的占位符效果:
RepeatingAnimationBuilder<Offset>(
animatable: Tween<Offset>(
begin: const Offset(-1.0, 0.0),
end: const Offset(1.0, 0.0),
),
duration: const Duration(seconds: 1),
repeatMode: RepeatMode.reverse,
curve: Curves.easeInOut,
builder: (BuildContext context, Offset offset, Widget child) {
return FractionalTranslation(
translation: offset,
child: child,
);
},
child: const ColoredBox(
color: Colors.green,
child: SizedBox.square(dimension: 100),
),
),
另外,官方还用 .builder 构建器更新了 CarouselView,从而支持创建带有动态内容的 carousels 变得更容易,其他控件调整还有:
DropdownMenuFormField同样支持自定义 errorBuilderRawAutoComplete现在包含了基于可用屏幕空间智能定位的OptionsViewOpenDirection.mostSpace选项
PC 端和多窗口
基于 Canonical 的长期合作,现在 Flutter Desktop 的发展路线图基本由 Canonical 负责,目前复杂的桌面 UI 需求差距正在被 Canonical 缩小,同时多窗口也开始实验性可用,而 3.41 开始引入了用于创建弹出窗口和提示窗口的实验性 API,并支持 Linux、macOS 和 Windows 上的跨平台对话框窗口支持,例如:
///点击按钮创建一个“普通新窗口”
OutlinedButton(
onPressed: () {
final UniqueKey key = UniqueKey();
windowManager.add(
KeyedWindow(
key: key,
controller: RegularWindowController(
delegate: CallbackRegularWindowControllerDelegate(
onDestroyed: () => windowManager.remove(key),
),
title: 'Regular',
preferredSize: windowSettings.regularSize,
),
),
);
},
child: const Text('Regular'),
)
///创建“模态/非模态 Dialog 窗口”,并在 Dialog 里继续挂子窗口(parent 关系)
ElevatedButton(
onPressed: () {
final UniqueKey key = UniqueKey();
windowManager.add(
KeyedWindow(
key: key,
controller: DialogWindowController(
preferredSize: windowSettings.dialogSize,
delegate: CallbackDialogWindowControllerDelegate(
onDestroyed: () => windowManager.remove(key),
),
parent: window,
title: 'Dialog',
),
),
);
},
child: const Text('Create Modal Dialog'),
)
///Dialog 内容区域:把自己的子窗口也渲染成 ViewCollection
return ViewAnchor(
view: ListenableBuilder(
listenable: windowManager,
builder: (context, _) {
final childViews = <Widget>[];
for (final childWindow in windowManager.getWindows(parent: window)) {
childViews.add(
WindowContent(
controller: childWindow.controller,
windowKey: childWindow.key,
onDestroyed: () => windowManager.remove(childWindow.key),
onError: () => windowManager.remove(childWindow.key),
),
);
}
return ViewCollection(views: childViews);
},
),
child: child,
);
///Tooltip “跟随控件位置”的窗口(锚点矩形 + 每帧更新位置)
final tracker = _ElementPositionTracker(
element: _tooltipButtonKey.currentContext!,
);
_ElementPositionTrackerManager.instance.add(tracker);
final UniqueKey key = UniqueKey();
final controller = TooltipWindowController(
anchorRect: tracker.getGlobalRect()!,
positioner: windowSettings.positioner,
delegate: _TooltipWindowControllerDelegate(
onDestroyed: () {
windowManager.remove(key);
_ElementPositionTrackerManager.instance.remove(tracker);
setState(() {
_tooltipController = null;
_tooltipTracker = null;
});
},
),
parent: widget.parentController,
);
tracker.onGlobalRectChange = (rect) {
controller.updatePosition(anchorRect: rect);
};
windowManager.add(KeyedWindow(key: key, controller: controller));
setState(() {
_tooltipController = controller;
_tooltipTracker = tracker;
});
Demo 可见:https://github.com/flutter/flutter/tree/master/examples/multiple_windows,需要运行时
--enable-windowingflag
另外,Flutter Linux 现在默认支持合并线程,基本上 PC 端也完成和所有线程合并场景支持。
DevTools
3.41 开始,对于 Devtools 在性能和稳定性方面也有一些改进,例如:
- Flutter 的开发工具使用 dart2wasm 编译提升了性能
- 与 Dart Tooling Daemon(DTD)断开连接时,机器在休眠后恢复时会自动重试
Dart 3.11
Flutter 3.41 开始包含 Dart 3.11 ,对于 Dart 3.11 主要有两个值得关心的改进:Glob support 和 Pub cache gc 。
Pub workspaces 现在支持使用 glob 模式声明包,现在可以将目录中的所有包包含在发布工作区:
# Before
name: workspace
environment:
sdk: ^3.10.0
workspace:
- pkg/a
- pkg/b
- pkg/c
# After
name: workspace
environment:
sdk: ^3.11.0
workspace:
- pkg/* # Adds all packages inside pkg.
此外,Pub 一直以来都将软件包存放在一个全局缓存 PUB_CACHE,确保用户不会重复下载同一个软件包,然而由于 Pub 没有追踪哪些项目使用了缓存,因此无法得知哪些软件包已过时,导致软件包版本号随着时间的推移而不断累积。
而从 Dart 3.9 开始,pub get 已将解析项目的路径存储在缓存中,所以在 Dart 3.11 中引入了一个命令,pub cache gc ,这个命令会遍历所有“活跃”项目,标记它们所依赖的所有包版本,并删除其余的包。
> dart pub cache gc
Found 3 active projects:
* /home/yourusername/projects/pub
* /home/yourusername/projects/pub-dev
* /home/yourusername/projects/pana
All other projects will need to run `dart pub get` again to work correctly.
Will recover 2 GB.
Are you sure you want to continue? (y/N)? y
Deleting unused cache entries... (4.5s)
>
天见犹怜,Dart 终于提供官方的包清理工具了。
最后
可以看到,3.41 更多是一个问题修复版本,没有什么重大更新,不过一些细节改进,例如 Platform-specific assets 和 Navigator.popUntilWithResult 等调整还是挺不错的, Add-to-App 的 UI 自缩放支持也算是难得的更新,PC 多窗口距离稳定版也不远了,那么,你准备好更新 3.41 了吗?
最后,提前祝大家,春节快乐~~~
更多推荐





所有评论(0)