Flutter 3.47 的风头被 Dart 3.13 抢了:原生依赖终于能“瘦身”了

源自7位全网作者

00:14

这周 Flutter 圈基本被 3.47 刷屏了:Impeller 接管桌面端、Material 正式分家、iOS 27 SDK 强制 UIScene。Flutter官方博客相信不少人已经看过不止一篇。但把目光从 Flutter 挪到 Dart 这边,你会发现一个有点反常识的事实:这波更新里真正干活的,可能是 Dart 3.13。

社区里已经有人把话说明白了。知乎上有位长期盯版本更新的作者看完 changelog 直接"应激",直言一开始以为 Dart 3.13 没什么大更新,结果一看,感觉这两个版本 Dart 都比 Flutter 团队靠谱多了。知乎这话说得有点扎心,但对照两边的更新内容,还真不算夸张——3.47 的重头戏本质是一场"搬家"(设计组件解耦、渲染引擎换岗),而 Dart 3.13 动的是几个卡了 Flutter 好几年的老问题。

Flutter 3.47 的风头被 Dart 3.13 抢了:原生依赖终于能“瘦身”了

先把时间线对一下:Dart 3.13.0 稳定版 8 月 5 日就已发布,官方公告博客 8 月 12 日上线,Flutter 3.47 的官宣文章也是同一天。两者是同一波更新的两半。下面从 Dart 3.13 里挑出跟写 App 的人最相关的四件事,按重要程度说。

一、原生依赖终于能"减肥"了:Flutter 被嘲多年的包体积,这次动真格

先说个 Flutter 的老痛点。Dart 这边一直有 tree shaking,用不到的 Dart 代码编译时会被裁掉,但裁剪到 FFI 边界就停了。什么意思?比如你的 Flutter 包通过 FFI 带了一整套 SQLite、加密库、图片解码器或者 Rust 库,Dart AOT 知道你只用了其中几个 wrapper,但底下真正打进 APK、IPA 的 native 库,还是一大坨完整二进制——因为 Dart 编译器知道哪些代码被调用,native linker 却不知道 Dart 那边发生了什么,这条信息链一直是断的。Dart官方博客

3.13 把这条链打通了:新增的 @RecordUse 注解、配套的 record_use 包和 link hook,让 AOT 编译时记录的"到底调用了哪些 FFI binding"能一路传给 native linker。社区作者举的例子很直观:一个 native 库暴露 300 个 API,你的 App 最终只用了 20 个,剩下那 280 个对应的 native 代码理论上也能一起裁掉;如果一个 native 库一个函数都没被用到,整个库都可以不进最终包体。知乎

这事对 Flutter 的意义不止是省几 MB。官方一直在推的 Code Assets(让 Dart 包自然地携带、编译和绑定 C/C++/Rust 代码)一直缺的就是后半环:native 资产怎么参与整包优化。现在 build hook 负责编 native 代码,Dart AOT 负责算可达性,link hook 拿着使用信息去裁剪 native 库——两段流水线终于接上了。往好了说,以后 Flutter 包带 Rust/C++ 依赖的成本会低很多,包作者可以放心暴露一整套 native API,App 只为真正用到的部分付体积钱。

但要泼一盆冷水:这是机制打通,不是自动生效。它需要包作者主动标记、写 link hook 配合,短期内你装的大部分包还享受不到。真正该现在就研究的是写 FFI 插件的包作者;普通 App 开发者先记住这件事,等生态跟进。

二、Primary Constructors 正式转正:数据类不用再写两遍

写 Flutter 的人对这种代码一定眼熟——定义一个普通数据类,同一套字段要在构造函数和实例字段里重复两遍。3.13 起,Primary Constructors 从实验特性转正:`final int x` 直接同时定义构造参数和实例字段,`var` 声明可变字段,只写 `int x` 则只是参数。传统构造函数也简化了,类里面可以用 `new` 代替重复写类名。

官方这次推得很用力,一口气配了多个 lint 和 IDE 重构工具,包括把旧构造函数自动转成 primary constructor 的能力——摆明了就是希望你换过去。Dart官方博客

有个现实的小尴尬:AI 编程助手目前还不太习惯写新语法,你不强制要求,它还是会写老写法。所以如果你打算在新项目里用,记得在规则或提示里明确说一声。

我的建议:新代码、新项目可以直接上,尤其是数据类密集的仓库,收益立竿见影;老项目没必要全量重写,把 lint 打开,让工具遇到一处改一处就行。

三、Dynamic Modules:官方开始试验"动态代码链接",但别当成 Code Push

先补个背景:Dart AOT 高度依赖"编译时整个程序已确定"的封闭世界假设,代码一旦编进包里就定了型,任何"运行时再加载新代码"的念头都很难落地——这也是 Flutter 社区念叨热更新多年的根源。

3.13 引入的 Dynamic Modules,官方给的说法很克制:这是围绕"动态代码链接"的一组实验,为的是改进开发工作流,比如团队内部快速分享原型。Dart官方博客社区的解读要兴奋得多,有长期盯版本的作者直接点出:这主要是想解决没有 JIT 的移动环境里的开发工作流,也就是 iOS 26 收紧 JIT 之后的问题,并提到官方暂时没有把生产环境的 server-driven UI 列为优先事项。知乎

顺着这条线往回看会更清楚:3.12 上线的 Agentic Hot Reload 已经让 AI 编码代理通过 Dart MCP server 直接连上运行中的应用——你让它修 bug、改组件、查崩溃,它自己改代码、拉运行时诊断、实时热重载。Dart官方博客Dynamic Modules 是同一方向的下一步:官方在持续扩大"开发期能动态做什么"的边界,而不是在发生产端热更新的信号。

Flutter 3.47 的风头被 Dart 3.13 抢了:原生依赖终于能“瘦身”了

所以这里必须把话说死:这离大家心心念念的"Flutter Code Push / 热更新"还很远,别急着往那个方向解读。但它确实值得盯——动态代码链接这条路一旦走顺,Flutter 的开发体验和动态化空间都会是另一个故事。

四、Web 和工具链的两件事,顺带提

做 Flutter Web 的可以关注 dart2wasm 的 deferred loading:3.13 起可以把延迟加载的 Dart 代码真正拆成独立的 Wasm 模块,需要时再加载,直接对着大型 Web 应用的首屏加载痛点去的。不过目前还是早期实验阶段,embedder 还得自己提供加载模块的回调,离无感使用有距离,看看就好,别上生产。

另外两个小提升:dartdoc 支持用 {@example} 直接引用 example 目录里的真实代码,文档示例和真实代码不再各写一份然后慢慢漂移。Dart官方博客dart format 改了方法链的换行逻辑,之前那种把调用链撕得很碎的格式化终于顺眼了。

Flutter 3.47 的风头被 Dart 3.13 抢了:原生依赖终于能“瘦身”了

最后,升级前先看这份分工

  • 准备升 Flutter 3.47 的人:Dart 侧这些能力跟着 SDK 一起来,不需要你额外动手;但 3.47 本身的 Material 迁移、UIScene 适配才是硬仗,老项目按社区共识先观察一两个月再升。

  • 新项目:primary constructor 直接用,同时给 AI 助手立好规矩。

  • 写 FFI / native 插件的包作者:@RecordUse + link hook 现在就该上手,这是接下来"包体积"这个卖点的关键牌。

  • Flutter Web 开发者:deferred loading 保持关注,别上车。

  • 等热更新 / Code Push 的人:Dynamic Modules 值得追进展,但目前只是开发工作流层面的事。

往后值得盯三个信号:11 月秋季稳定版里旧 Material/Cupertino 库正式弃用的动静、Code Assets 生态的跟进速度、Dynamic Modules 的后续更新。Flutter 这波"搬家"看着不热闹,但 Dart 3.13 说明地基确实在换——对还在犹豫要不要继续投入 Flutter 的人来说,这至少是个不算坏的信号。

你升 3.47 了吗?Dart 3.13 这几个更新里,你最想先用上哪个?评论区聊聊。

内容由AI生成
0
扫一下,分享更方便,购买更轻松
0评论

当前文章无评论,是时候发表评论了
提示信息

取消
确认
评论举报

最新文章 热门文章