Flutter 3.7 正式發布
新的 Flutter 穩定版加入了 Material 3 更新、iOS 平臺優化及其他內容
新年伊始,由 Flutter 3.7 正式版來「打頭陣」!我們與整個 Flutter 社區成員們繼續在 Flutter 3.7 中優化了框架,包括創建自定義菜單欄和層疊式菜單、更好的國際化工具支持、新的調試工具以及其他功能和特性等。

新的穩定版里,我們在持續改進一些特性,例如全局文本選擇、Impeller 渲染速度、DevTools 以及一直以來都在優化的性能。讓我們一起來快速探索 Flutter 3.7 的新特性吧!
增強對 Material 3 的支持
在 Flutter 3.7 中,以下的 widget 已經進行了 Material 3 的適配:
Badge、BottomAppBar、Filled 和 Filled Tonal 按鈕、SegmentedButton、Checkbox、Divider、Menus、DropdownMenu、Drawer 和 NavigationDrawer、ProgressIndicator、Radio 按鈕、Slider、SnackBar、TabBar、TextFields 和 InputDecorator、Banner。
你可以直接在應用中的 ThemeData 里設置 useMaterial3 來啟用 Material 3。只有在完整的顏色方案下才能展現出 Material 3 最完整的細節,你可以使用新的 Material 主題構建器 生成你的主題配置,也可以通過 Flutter ThemeData 構造中的 colorSchemeSeed (顏色種子) 自動生成一整套的主題:
MaterialApp(
theme: ThemeData(
useMaterial3: true,
colorSchemeSeed: Colors.green,
),
// …
);
若想了解 Flutter 在 Material 3 上的支持進度,你可以在 GitHub 上查看 flutter #91605 號議題。
你也可以嘗試 Material 3 示例,其中展示了所有主題的特性。

菜單欄和級聯菜單
Flutter 現在可以創建菜單欄和級聯菜單了。
在 macOS 上,你可以使用 PlatformMenuBar widget 來創建菜單欄,你的菜單欄將由 macOS 系統來渲染,而不是使用 Flutter。
此外,對于所有其他的平臺,你可以定義一個 Material Design 菜單,它提供了級聯菜單欄 (MenuBar),或者使用由 UI 界面元素觸發的 (MenuAnchor) 來創建一個級聯菜單。這些菜單都是完全可自定義的,其中的菜單項可以是自定義的 widget,也可以使用新的菜單項 widget: (MenuItemButton 和 SubmenuButton)。

Impeller 預覽版在穩定版渠道發布
Flutter 團隊很高興能 在穩定版渠道上 為大家帶來 iOS 平臺的 Impeller 渲染引擎 預覽。我們認為 Impeller 的性能已經達到、甚至超越了大部分現有應用上的 Skia 渲染。在圖像保真方面,Impeller 也已覆蓋了大部分除極端條件以外的應用場景。我們希望能夠在之后的穩定版本中 將 Impeller 作為 iOS 平臺的默認渲染引擎,如果你在體驗時有任何問題,請繼續在 GitHub 上提交 Impeller 的相關反饋。
盡管我們對 iOS 上 Impeller 滿足現有應用的渲染需求有足夠的自信,但仍然有部分 API 需要進行補充。你可以在 Flutter wiki 文檔 上看到目前 Impeller 的進度。用戶及開發者在使用時可能會注意到 Impeller 與 Skia 之間的渲染細節區別,這些區別可能是 BUG,當你遇到時請記得在 GitHub 上提出 Issue,幫助我們定位并修復它。
Impeller 的進展飛速離不開社區貢獻者的支持。尤其是 ColdPaleLight、guoguo338、JsouLiang 以及 magicianA,他們在此次發布版本的 Impeller 的 291 次提交中有 31 次 (>12%) 是他們提交的。非常感謝他們的幫助!
我們也在 Impeller 的 Vulkan 支持 (舊設備會回落到 OpenGL) 上有一定的進展,但是 Android Impeller 尚未準備好進行公開預覽。我們會在未來的發布中分享更多正在積極進行的 Impeller 開發進程,包括桌面和 Web 平臺的支持。
若你感興趣,可以關注 GitHub 上的 Impeller 項目看板 來跟進開發進度。
iOS 發布校驗
當你在構建一個發布版本的 iOS 應用時,Flutter 會為你提供 項目設置檢查清單 來確保你的應用已經準備好發布到 App Store。
現在 flutter build ipa 命令會校驗項目的一部分設置,并且在清單中告知你在發布前進行更改。

開發者工具 DevTools 的更新
在本次發布中,開發工具也帶來了新的特性和體驗優化。DevTools 的內存調試工具已經完成了一輪全面的調整。我們帶來了三個新的選項卡:Profile、Trace 和 Diff,它們包含了先前的所有內存調試功能,也添加了更多利于調試的操作。現在你可以按照類或者內存類型對當前的內存分配進行分析,可以在運行時分析哪些代碼調用了哪些部分的內存,也可以對比兩個不同時間點的內存快照之間的差異來了解內存使用的細節。

以上的這些內存特性已經在 文檔 中進行了介紹,若你感興趣可以前往了解更多細節。
性能頁面也有一些值得注意的新功能,該頁面現在在頂部新增了 Frame Analysis (幀分析) 選項卡,它能夠提供在 Flutter 中詳細追蹤大量消耗的某些幀和操作的一些建議。

除了以上的新功能,本次更新還有其他的問題修復和優化改進,包括查看器 (Inspector)、網絡記錄器的 CPU 記錄器的問題修復。你可以通過 Flutter DevTools 的發行注紀頁面查看 2.17.0 - 2.20.0 版本的 發行注記 了解更多細節。
自定義上下文菜單
從新版本開始,你可以在 Flutter 應用的任意位置創建自定義的上下文菜單,也可以自定義內置的上下文菜單。
舉例來說,你可以在用戶選中郵件地址時,為文本框默認的選擇菜單添加「發送郵件」的按鈕 (代碼地址)。contextMenuBuilder 參數也已經添加到現有包含上下文菜單的 widget 中。你可以在 contextMenuBuilder 中返回任何你想返回的 widget,也包括平臺自適應的上下文菜單。

這一新特性也可以用于文本選擇以外的場景。例如,你可以為一個 Image widget 的右鍵和長按操作添加「保存」按鈕 (代碼地址)。你也可以使用 ContextMenuController 在應用內的任意位置展示平臺默認或者自定義的上下文菜單。

若想查看完整的示例,前往 context_menus 示例代碼倉庫 了解更多。
CupertinoListSection 和 CupertinoListTile widget
Cupertino 系列 widget 迎來了兩位新成員: CupertinoListSection 和CupertinoListTile,可用于展示 iOS 風格的滾動列表內容,它們是 Cupertino 版本的 ListView 和 ListTile。


滑動優化
此次版本發布中也包含了眾多 滑動相關的問題 修復,包括觸控板的交互優化以及在滑動組件中文本選擇時的行為。
值得注意的是,macOS 的應用現在可以通過 新物理滑動特性 來體驗與其有更高匹配度的滑動體驗。
新的 AnimatedGrid 和 SliverAnimatedGrid 可以用于為新增和移除的內容展示動畫。

最后,我們 修復了 自 Flutter 遷移至健全的空安全以來的一個問題,該問題影響了所有包含 itemBuilder 參數的滑動 widget (例如 ListView)。在遷移至空安全時,itemBuilder 的類型遷移至了 IndexedWidgetBuilder,即不允許返回 null,而在以前 null 可以用來代表列表已經到了底部等。該參數現已修改為 NullableIndexedWidgetBuilder。感謝 @rrousselGit 發現并修復了這個問題!
國際化工具和文檔
Flutter 對國際化的支持已經煥然一新!我們對 gen-l10n 進行了重寫以支持下述特性:
- 描述性的語法錯誤
- 嵌套或多個復數、選擇和占位的消息內容

更多內容可以了解已經更新的 Flutter 應用里的國際化 文檔。
- Flutter 應用里的國際化文檔: https://flutter.cn/docs/development/accessibility-and-localization/internationalization
全局的選擇優化
SelectionArea 現在已支持鍵盤操作。你可以通過鍵盤快捷鍵 Shift+→ 等快捷鍵進行選擇。
后臺 isolate
現在 平臺通道 可以在 任意 isolate 中進行調用。先前平臺通道只能在主 isolate 中進行調用。優化后會讓插件和混合開發調用 isolate 和宿主平臺代碼更加簡單。更多內容可以閱讀 撰寫平臺代碼 文檔以及 介紹后臺 isolate 通道 文章。
文本放大鏡
在 Android 和 iOS 上進行文本選擇時會出現的放大鏡現在也會在 Flutter 中出現了。它已經添加至了所有的文本選擇,但是你也可以通過 magnifierConfiguration 禁用或者自定義。


插件代碼遷移至 Swift
Apple 整將它們的代碼遷移至 Swift,我們也希望能為開發者構建 Swift 插件的示例和指導。quick_actions 已經從 Objective-C 遷移至了 Swift,也可以作為 Swift 插件的最佳實踐。如果你對幫助 Flutter 遷移第一方插件至 Swift 感興趣,請參考 wiki 中的 Swift 遷移部分。
給 iOS 開發者準備的資源
我們新發布了一系列為 iOS 開發者準備的資源,包括:
- 給 SwiftUI 開發者的 Flutter 指南
- 給 Swift 開發者的 Dart 指南
- 給 Swift 開發者的 Flutter 并發開發指南
- 將 Flutter 添加到現有的 SwiftUI 應用中
- 為 Flutter 創建多渠道 (針對 Android 和 iOS)
廢棄 Bitcode
從 Xcode 14 開始,watchOS 和 tvOS 的應用不再需要 bitcode,并且 App Store 也不再接收帶 bitcode 的應用提交。因此,Flutter 也移除了 bitcode 的支持。
Bitcode 在 Flutter 應用中默認是關閉的,所以這也不應該會影響太多開發者的項目。但是,如果你曾經為你的項目手動啟用過 bitcode,請盡快在升級到 Xcode 14 后關閉 bitcode。你可以使用 Xcode 打開 ios/Runner.xcworkspace 找到 Enable Bitcode 設置為 No,混合開發項目需要在宿主項目中禁用。

iOS 平臺視圖應用 BackdropFilter
我們為 iOS 原生視圖添加了可以渲染高斯模糊的特性,現在嵌套在 BackdropFilter 中的 UiKitView 可以正確的渲染高斯模糊了。

你可以查看相應的 設計文檔 了解更多。
內存管理
此次發布的版本對內存管理做了一些改進,這些改進的共同作用是減少由 GC 暫停引起的卡頓、減少由于分配速度和后臺 GC 線程引起的 CPU 占用,并且降低內存占用。
例如,我們擴展了現有手動釋放某些 dart:ui Dart 對象的本地資源的實踐。先前在 Dart VM 垃圾回收 Dart 對象前,本地資源都將被 Flutter 引擎持有。通過對用戶應用程序和我們的 benchmarks 分析,我們認為這種策略很多時候無法避免不合適的 GC 和過度使用內存。因此在此次更新中 Flutter 引擎添加了 API ,用于顯式釋放由 Vertices、Paragraph 和 ImageShader 對象持有的本地資源。

在我們遷移到此 API 的 Flutter 框架的 benchmarks 中,將 90% 的幀構建時間減少了 30% 以上,最終用戶將體驗到更流暢的動畫和更少的卡頓。
此外,Flutter 引擎 不再上報 Dart VM 中的 GPU 圖像的大小。如上所述,當這些圖像資源不再被需要時已由框架手動釋放,如果這時繼續按照 GPU 內存大小的 GC 策略上報至 Dart,會導致不必要的堆內存壓力并進一步觸發無效的 GC。類似的方法同樣應用到了 Flutter 引擎中,用于回收 dart:ui 原生對象的 隱式內存占用。

在我們的測試中,此更改省去了 widget 創建 GPU 常駐圖像構建幀時的同步 GC 工作。
本次版本發布中,Flutter 引擎在動態更新應用狀態至 Dart VM 方面有所進步。具體來說,Flutter 現在會使用 Dart VM 中 RAIL 風格 的 API,讓 路由轉場時渲染延遲更低,即讓堆內存在轉場時保持增長而不是進行 GC,避免造成動畫的卡頓。目前這項改動不會帶來太大的性能優化,但未來我們會將這項改進拓展到其他方法上,消除由 GC 帶來的卡頓影響。此外,我們還修復了向 Dart VM 報告 Flutter 引擎已經閑置的 一處邏輯錯誤,也減少了 GC 帶來的卡頓。最后,在 Flutter 視圖不再展示時,也會 通知 Dart VM 進行處理,進一步優化了 Flutter 視圖未顯示時的內存占用。
放棄對 macOS 10.11 到 10.13 版本的支持
我們在 Flutter 3.3 發布的文章 中提到過,Flutter 將不再支持 macOS 的 10.11 和 10.12 版本,自上個版本發布以來,通過進一步的 分析發現,放棄對 macOS 10.13 的支持也不會造成太大影響,帶來的收效卻是可以幫助大幅簡化代碼庫。這意味著,使用 Flutter 3.7 以及后續版本構建的桌面端應用程序將不能再在 macOS 10.11、10.12、10.13 版本中運行,Flutter 對 macOS 的最低10點要求版本提升至 macOS Mojave 10.14。
至此,Flutter 構建的 iOS 和 macOS 應用都已經包含了 Metal 的支持,OpenGL 后端渲染引擎已經從 iOS 和 macOS 嵌入器層被移除,移除后,壓縮后的 Flutter 引擎體積降低了大約 100KB。
將 toImageSync 新增至 dart:ui 中
本次版本發布,將 Picture.toImageSync 和 Scene.toImageSync 方法直接加入到了 dart:ui,類似于 Picture.toImage 以及 Scene.toImage. 這樣的異步方法,Picture.toImageSync 會直接返回一個 Picture 轉 Image 的一個句柄,并在后臺異步對 Image 進行光柵化。
當 GPU context 可用時,圖像會在 GPU 中常駐,這意味著與 toImage 生成的圖像相比它的繪制速度會更快。(toImage 生成的圖像也可以實現 GPU 常駐,但目前還未實現)。
新的 toImageSync API 支持的例子:
- 快速捕捉一張昂貴的柵格化圖片,以便跨多幀重復使用。
- 應用在圖片的多路過濾器上
- 應用在自定義著色器上
一個例子是,Flutter 框架現已使用這個 API 以優化 Android 上的頁面切換動畫的性能,幾乎減少了幀光柵化一半的時間,減少掉幀,在支持這些刷新率的機器上動畫可以達到 90/120fps。
自定義著色器支持的改進
本次發行版包含了許多關于 Flutter 對自定義著色器片段的優化支持。Flutter SDK 現已內置了一個著色器編譯器,能夠將 pubspec.yaml 文件中列出的 GSGL 著色器編譯為目標平臺的正確的平臺特定對應的格式。此外,自定義著色器能夠在開發階段方便的執行 hot reload。自定義著色器目前已經在 iOS 上對 Skia 以及 Impeller 都支持了。
我們為社區中分享的樣例感到印象深刻,期待能夠未來能有更多關于 Flutter 中的自定義著色器的創意。
請參閱 文檔網站上的文檔 以及 pub.dev 上的
flutter_shaders package 了解更多。
字體資源支持熱重載
在過去,將新的字體資源加入到 pubspec.yaml 文件的時候會需要重新構建應用后才能查看,不像其他資源可以直接熱重載生效,現如今,字體清單文件的修改 (包括添加新字體) 后,也可以直接熱重載到應用中立刻可見了。
減少 iOS 設備上動畫效果的卡頓
有兩項重要的來自社區成員 luckysmg 的貢獻,幫助減少了 iOS 設備上動畫效果的卡頓。特別是在 iOS 手勢交互期間在主線程上添加一個虛擬的 CADisplayLink 以強制設定最大刷新率。此外,鍵盤動畫也通過 CADisplayLink 設定了與 Flutter 引擎里 animator 相同的刷新率。由于新加入了這些變化,用戶可以在 120Hz 的 iOS 設備上感受到更一致和流暢的動畫效果。
結語
還是那句話,如果沒有 Flutter 社區中優秀、熱情貢獻者們,Flutter 不會像現在這樣優秀,在我們未來持續進行的這段旅程中,我們希望你可以知道,沒有你們,我們無法做出這樣的優秀成績。感恩每一位貢獻者!
我們的發展勢頭依舊,請期待未來的更新!
致謝
感謝來自 CFUG 社區的 Alex、Luke、迷鹿、鑫磊 對本文的翻譯和審校。
浙公網安備 33010602011771號