【文章翻譯】What’s New in Flutter 2.0

【文章內容使用 Gemini 1.5 Pro 自動產生】

Flutter 2 的新功能

Flutter 網頁和空安全移至穩定版,Flutter 桌面移至 Beta 版,還有更多新功能!

今天,我們很高興宣佈 Flutter 2 的發佈。自 Flutter 1.0 發佈以來已經過去了兩年多,但在這短短的時間裡,我們已經解決了 24,541 個議題,並合併了來自 765 位貢獻者的 17,039 個 PR。僅從 9 月份發佈的 Flutter 1.22 版本至今,我們已經解決了 5807 個議題,並合併了來自 298 位貢獻者的 4091 個 PR。特別感謝我們自願的貢獻者,他們慷慨地貢獻自己的閒暇時間來改進 Flutter 專案。Flutter 2 版本中排名前三的自願貢獻者是 xu-baolin,他提交了 46 個 PR,a14n,他提交了 32 個 PR,專注於將 Flutter 帶入空安全,以及 hamdikahloun,他提交了 20 個 PR,改進了許多 Flutter Plugin。但不僅僅是程式碼作者為 Flutter 專案做出了貢獻;一批優秀的自願 PR 審查者也負責審查了 1525 個 PR,包括 hamdikahloun(再次!)、CareFYazeedAlKhalaf(他只有 16 歲!)。Flutter 確實是一個社群努力的結果,沒有議題提出者、PR 貢獻者和程式碼審查者,我們不可能達到 2.0 版。此版本是獻給你們所有人的。

在 Flutter 2 版本中,發生了很多令人興奮的事情。有關 Flutter 2 和 Dart 2.12 的所有新功能的概述,以及我們的客戶和合作夥伴如何使用 Flutter 2,請參閱 宣佈 Flutter 2。有關 Dart 2.12 的詳細資訊,請參閱 宣佈 Dart 2.12。有關如何充分利用 Flutter 網頁(現在已建議用於生產環境)的資訊,請參閱 Flutter 網頁支援達到穩定里程碑

此外,若要查看 Flutter 2 本身的新功能,請繼續閱讀!

網頁

從今天起,Flutter 的網頁支援已從 Beta 版轉移到穩定頻道。有了這個初始的穩定版本,Flutter 以對網頁平台的支援將程式碼的可重複使用性推向了另一個層級。因此,現在當你在穩定版中建立 Flutter 應用程式時,網頁只是你應用程式的另一個設備目標。

[Moi Mobiili](https://www.moi.fi/),一家現代化虛擬行動網路營運商,努力透過數位化實現運營卓越,選擇使用 Flutter 建立他們的 Mun Moi 帳戶管理應用程式,並最近推出了他們的網頁應用程式。

透過利用網頁平台的許多優勢,Flutter 建立了用於建立豐富互動式網頁應用的基礎。我們主要關注效能和渲染保真度的改進。除了我們的 HTML 渲染器之外,我們還加入了新的 CanvasKit 基礎渲染器。我們還加入了一些特定於網頁的功能,例如 Link Widget,以確保在瀏覽器中運行的應用程式感覺像一個網頁應用程式。

Flutter 的網頁支援部落格文章 中找到有關此穩定版本的更多詳細資訊。

空安全

空安全是 Dart 語言的一個重要新增功能,它透過區分可空類型和不可空類型來進一步強化類型系統。這使開發人員能夠防止空錯誤崩潰,這是應用程式崩潰的常見原因。透過將空檢查整合到類型系統中,這些錯誤可以在開發過程中被捕獲,從而防止在生產環境中出現崩潰。空安全在 Flutter 2(包含 Dart 2.12)中得到完全支援。有關更多詳細資訊,請參閱 Dart 2.12 部落格文章

pub.dev 套件儲存庫中已經發佈了 超過 1,000 個空安全的套件,包括 DartFlutterFirebaseMaterial 團隊的數百個套件。如果您是套件作者,請查看 遷移指南,並考慮今天就進行遷移。

桌面

在此版本中,我們很高興地宣佈 Flutter 的桌面支援在穩定頻道中以早期版本標誌的形式提供。這意味著我們已經準備好讓您嘗試將其作為 Flutter 應用程式的部署目標:您可以將其視為「beta 快照」,預覽今年晚些時候發佈的最終穩定版本。

為了使 Flutter 桌面達到這種程度的品質,從確保文字編輯在每個支援的平台上都能像原生體驗一樣運作開始,包括基礎功能,例如 文字選取中心點 以及能夠在 處理鍵盤事件後停止事件傳播。在滑鼠輸入方面,使用高精度點選裝置進行拖動現在會立即開始,而不是等待處理觸控輸入所需的延遲。此外,為 MaterialCupertino 設計語言的 TextField 和 TextFormField Widget 添加了一個內建的內容選單。最後,為 ReorderableListView Widget 添加了抓取控制柄

ReorderableListView 現在具有抓取控制柄,方便使用滑鼠進行拖放。

ReorderableListView 始終擅長移動項目,作為開發人員,您幾乎不需要付出任何努力,但它需要使用者使用長按來啟動拖動。這在行動設備上是有道理的,但很少有桌面使用者會想到用滑鼠長按一個項目來移動它,因此此版本包含一個適用於滑鼠或觸控輸入的抓取控制柄。另一個針對平台特有功能的改進是 更新的捲軸條,它會在桌面外觀中正確顯示。

此版本包含更新的 Scrollbar Widget,在桌面環境中效果很好。

Scrollbar Widget 已更新,以提供桌面預期的互動式功能,包括拖動滑塊、點擊軌道以向上和向下翻頁以及在滑鼠懸停在捲軸條的任何部分時顯示軌道。此外,由於可以使用 新的 ScrollbarTheme 類別 來設定 Scrollbar 的主題,因此您可以對其進行樣式設定以符合應用程式的樣式和感覺。

為了提供其他特定於桌面的功能,此版本還為 Flutter 應用程式啟用了命令列引數處理,因此可以使用簡單的操作(例如在 Windows 檔案總管中雙擊資料檔案)在應用程式中打開檔案。我們還努力為 WindowsmacOS 都實現更流暢的調整大小操作,並為國際使用者啟用 IME(輸入法編輯器)。

Flutter 桌面現在支援直觀的 IME 輸入。

此外,我們還提供了 有關如何開始為您的桌面應用程式準備部署到適當的作業系統特定商店的更新文件。請試用它們,如果我們遺漏了任何內容,請提供回饋。

在嘗試 Flutter 桌面的 Beta 版時,您可以透過切換到 Beta 版頻道(預期如此)並根據 flutter.dev 上的說明 為您要鎖定的平台設定配置標誌來存取它。此外,我們還在穩定頻道上提供了 Beta 版的快照。如果您使用 flutter config 來啟用其中一個桌面配置設定(例如,enable-macos-desktop),那麼您可以嘗試桌面支援的 Beta 版功能,而無需經歷移動到 Beta 版頻道和下載 Flutter SDK 的最新 Beta 版、建立工具等的冗長過程。這非常適合試用或將桌面支援用作簡單的「Flutter 模擬器」。

但是,如果您選擇停留在穩定頻道以存取桌面 Beta 版,則您獲得新功能或錯誤修復的速度將不如切換到 Beta 版或開發頻道快。因此,如果您積極鎖定 Windows、macOS 或 Linux,我們建議您切換到一個提供更新更快的頻道。

隨著我們第一個完整的生產級品質的 Flutter 桌面版本即將推出,我們知道我們還有更多工作要做,包括支援與原生頂級選單整合、讓文字編輯更像個別平台的體驗、可存取性支援,以及一般的錯誤修復和效能改進。如果您認為在桌面移至生產級品質之前還有其他事情需要做,請務必 提供您的回饋

平台適應性應用程式:Flutter Folio 樣本

現在 Flutter 支援三個生產應用程式平台(Android、iOS 和網頁)以及三個 Beta 版平台(Windows、macOS 和 Linux),一個自然的問題出現了:如何編寫一個能夠很好地適應多種不同外觀尺寸(小、中和大螢幕)、不同輸入模式(觸控、鍵盤和滑鼠)和不同慣例(行動、網頁和桌面)的應用程式?為了回答這個問題,我們為自己和所有地方的 Flutter 開發人員委托了 Flutter Folio 剪貼簿應用程式。

Folio 旨在成為一個簡單的應用程式範例,您希望能夠從單個程式碼庫中在多個平台上良好運行。而「良好」是指,它在小、中和大螢幕上看起來都不錯,它利用了觸控、鍵盤和滑鼠輸入,並且適用於平台的慣例(例如,在網頁上使用連結,在桌面上使用選單)。我們將這種應用程式稱為「平台適應性應用程式」,因為它能夠很好地適應其執行的任何平台。

如果您想了解如何製作自己的平台適應性應用程式,可以查看 Folio 的原始碼。在未來,您會發現更多探討這個主題的文件和 Codelab。在此期間,請查看 Aloïs Deniel 關於這個主題的出色部落格文章和影片

Google 行動廣告移至 Beta 版

除了 Flutter 桌面移至 Beta 版之外,今天我們還很高興地宣佈 Google 行動廣告 SDK for Flutter 的公開 Beta 版。這是一個全新的 Plugin,除了現有的覆蓋格式(覆蓋橫幅、插頁式和獎勵型影片廣告)之外,它還提供了內嵌橫幅和原生廣告。這個 Plugin 統一了對 Ad Manager 和 Admob 的支援,因此無論您是什麽規模的發佈商,這個 Plugin 都可以針對您的場景進行調整。

我們已經與一些早期客戶在一個私人 Beta 程式中試用了這個 Plugin,並且他們中的許多人已成功使用這些新的格式推出了他們的應用程式。例如,Sua Musica(拉丁美洲最大的獨立音樂人音樂平台,擁有超過 15,000 名經過驗證的音樂人和 1,000 萬個 MAU)使用 Google 行動廣告 SDK for Flutter Plugin 推出了他們的全新 Flutter 應用程式。他們在展示次數上看到了 350% 的增長,點擊率增加了 43%,eCPM 增加了 13%。

這個 Plugin 現在已可供您使用。作為 Flutter Engage 的一部分,Andrew Brogdon 和 Zoey Fan 介紹了一個關於「使用 Flutter 變現應用程式」的議程(在 Flutter Engage 上提供),他們在這個議程中討論了使用 Flutter 建立的應用程式的變現策略,以及如何在 Flutter 應用程式中載入廣告。此外,我們在 flutter.dev 上建立了一個新的 廣告 頁面,您可以在其中找到所有有用的資源,例如 Plugin 實作指南內嵌橫幅和原生廣告 Codelab,以及 覆蓋橫幅、插頁式和獎勵型影片廣告 Codelab。請務必查看它們!

新的 iOS 功能

僅僅因為我們正在繼續提高對其他平台的支援品質,並不意味著我們忘記了 iOS。事實上,此版本帶來了 178 個合併的 PR,這些 PR 與 iOS 相關,包括 23495,它為 iOS 帶來了狀態還原,67781,它滿足了長期以來的一個需求,即可以直接從命令列構建 IPA,而無需打開 Xcode,以及 69809,它更新了 CocoaPods 版本以匹配最新的工具。此外,還為 Cupertino 設計語言實作添加了一些 iOS Widget。

新的 CupertinoSearchTextField 提供了 iOS 搜尋欄 UI。

CupertinoFormSectionCupertinoFormRowCupertinoTextFormFieldRow Widget 使得使用 iOS 的分段視覺美學更容易製作經驗證的表單欄位。

除了針對 iOS 的功能工作之外,我們還在繼續 研究針對 iOS 和 Flutter(在著色器和動畫方面)的效能改進。iOS 仍然是 Flutter 的主要平台,我們將繼續努力為其帶來重要的新功能和效能改進。

新的 Widget:Autocomplete 和 ScaffoldMessenger

此版本的 Flutter 附帶了兩個額外的新 Widget,AutocompleteCore 和 ScaffoldMessenger。AutocompleteCore 代表了將自動完成功能加入到 Flutter 應用程式中所需的最低限度功能。

自動完成是 Flutter 中經常被要求的功能,因此此版本開始提供此功能。您現在可以使用它,但如果您對完整功能的設計感到好奇,請查看 自動完成設計文件

同樣地,ScaffoldMessenger 的建立是为了解决許多與 SnackBar 相關的問題,包括能够轻松地在響應 AppBar 動作時创建 SnackBar、创建 SnackBar 以在 Scaffold 轉換之間持久存在,以及能够在异步動作完成時显示 SnackBar,即使使用者已經导航到具有不同 Scaffold 的頁面。

所有這些好東西都可以透過幾行程式碼來實現,從現在開始,您應該使用這些程式碼來顯示 SnackBar:

1
2
final messenger = ScaffoldMessenger.of(context);
messenger.showSnackBar(SnackBar(content: Text('I can fly.')));

正如您可能想像到的,它不仅仅是这些;有关详细信息,请查看Kate Lovett 关于 ScaffoldMessenger 的出色视频

使用 Add-to-App 進行多個 Flutter 實例

我們從與許多 Flutter 開發人員的交談中了解到,許多開發人員没有機會從头开始建立新的应用程序,但他们可以透過將 Flutter 加入到現有的 iOS 和 Android 應用程式中來利用 Flutter。這個功能稱為 Add-to-App,是在保留現有的原生程式碼庫的同時,在兩個行動平台上重複使用 Flutter 程式碼的絕佳方法。但是,對於使用這種方式的開發人員,我們有時會听到,他們不清楚如何超越將第一個螢幕整合到 Flutter 中。交織 Flutter 和原生螢幕會使导航狀態难以维护,而在視圖级别整合多個 Flutter 會占用大量的記憶體。

過去,額外的 Flutter 實例與第一個實例具有相同的記憶體成本。在 Flutter 2 中,我們將建立額外 Flutter 引擎的靜態記憶體成本降低了約 99%,降至每個實例約 180kB。

啟用此功能的新 API 在 Beta 版頻道中提供預覽,並在 flutter.dev 上有文件,以及 一組演示這種新模式的範例專案。有了這個變化,我們現在不再猶豫推薦在您的原生應用程式中建立多個 Flutter 引擎實例。

Flutter Fix

每當任何框架成熟並吸引越來越多的使用者,隨著時間推移,他們的程式碼庫也越來越大,人們往往會避免對框架 API 進行任何更改,以免破壞越來越多的程式碼行。隨著全球超過 500,000 名 Flutter 開發人員在越來越多平台上使用 Flutter,Flutter 2 正在迅速邁入這個行列。但是,為了使我們能夠隨著時間的推移繼續改進 Flutter,我們希望能夠對 API 進行重大更改。問題是,如何在不破壞開發人員的情況下繼續改進 Flutter API?

我們的答案是 Flutter Fix

Flutter Fix 是多種事物的組合。首先,dart CLI 工具中有一個新的命令列選項,稱為 dart fix,它知道在哪裡尋找已棄用 API 列表以及如何使用這些 API 更新程式碼。其次,它是可用修復本身的列表,從版本 2 開始與 Flutter SDK 捆綁在一起。最後,它是一組更新的 Flutter 擴展,用於 VS Code、IntelliJ 和 Android Studio IDE,這些擴展知道如何將相同的可用修復列表作為快速修復顯示,並帶有小的燈泡,有助於您用滑鼠點擊來更改程式碼。

舉例來說,假設您的應用程式中有以下程式碼行:

使用已棄用參數建立 Flutter Widget

因為此建構函數的參數已棄用,因此應該替換為以下內容:

使用已棄用參數被替換的 Flutter Widget 建立

即使您熟悉 Flutter 中的許多已棄用 API,但要更改的程式碼越多,您要應用所有修復程式就越困难,犯错的可能性也越大;人类不擅长这种重复性任务。但電腦很擅长;透過執行以下命令,您可以查看我們知道如何在整個專案中進行的所有修復:

1
$ dart fix --dry-run

如果您想批量應用它們,您可以輕鬆地做到:

1
$ dart fix --apply

或者,如果您想在您喜歡的 IDE 中互動式地應用這些修復程式,您也可以做到。

雖然我們已經將舊的 API 標記為已棄用多年,但現在我們 制定了關於何時真正移除已棄用 API 的政策,Flutter 2 是我們第一次這樣做。即使我們还没有將所有已弃用的API作為數據捕获以供 Flutter Fix 使用,我們也將繼續從之前已弃用的 API 中添加更多 API,並在未來的重大更改中繼續这样做。我們的目標是尽力使 Flutter 的 API 达到最佳状态,同时在进行更改时也保持您的代码最新。

Flutter DevTools

為了明确 DevTools 应该是一个用于调试 Flutter 应用程序的工具,我们将其重命名为在调试 Flutter 应用程序时称为 Flutter DevTools。此外,我们做了很多工作,使其达到足以与 Flutter 2 相匹配的生产级品质。

一项新的功能可以帮助您在启动 DevTools 之前找到问题,即 Android Studio、IntelliJ 或 Visual Studio Code 可以注意到常见的异常,并建议将其在 DevTools 中打开以帮助您调试它。例如,以下显示您的应用程序中出现了溢出异常,这将在 Visual Studio Code 中提供一个选项,用于在 DevTools 中调试该问题。

Flutter IDE 扩展会注意到您的应用程序何时抛出布局溢出异常

按下那个按钮会直接带您到 DevTools 中的 Flutter Inspector,指向导致问题的 Widget,这样您就可以对其进行修复。我们今天只针对布局溢出异常这样做,但我们的计划是将这种处理方式扩展到所有常见的异常,而 DevTools 可以作为解决这些异常的方案。

在 DevTools 运行后,选项卡上的新错误徽章可以帮助您在应用程序中找出具体问题。

DevTools 中的红点可以帮助您关注应用程序中出现错误的部分

DevTools 中的另一个新功能是能够轻松地查看比显示尺寸更高的分辨率的图像,这有助于跟踪应用程序的大小和内存使用情况。若要启用此功能,请在 Flutter Inspector 中启用「反转超尺寸图像」。

启用「反转超尺寸图像」选项以突出显示比实际需要更大的图像

现在,当您显示的分辨率明显大于其显示尺寸的图像时,它将上下颠倒显示,以便您在应用程序中轻松找到它。

「反转超尺寸图像」选项在行动中

此外,应广大用户的要求,除了在 Flutter Inspector 的布局资源管理器中显示有关灵活布局的详细信息外,我们还添加了显示固定布局的功能,使您能够调试各种类型的布局。

新的布局资源管理器显示了固定布局和灵活布局的布局详细信息

而且这还不是全部。以下只是 Flutter DevTools 2 中一些新功能的摘要:

  • 在 Flutter 畫面圖表中添加了平均 FPS 資訊和可用性改進
  • 在網路分析工具中使用紅色錯誤標籤來突出顯示失敗的網路請求
  • 新的記憶體檢視圖表更快、更小、更容易使用,包括一個新的懸停卡來描述特定時間的活動
  • 在記錄選項卡中添加了搜尋和過濾
  • 追蹤 DevTools 啟動之前的記錄,以便您在啟動 DevTools 時查看完整的記錄歷史記錄
  • 將「效能」檢視重新命名為「CPU 分析工具」,使功能更明確
  • 在 CPU 分析工具火焰圖表中添加了時間網格
  • 將「時間軸」檢視重新命名為「效能」,使功能更明確

而且這 仍然 不是全部。為了獲得完整的功能变更集,我推荐以下公告:

Android Studio/IntelliJ 擴展

針對 IntelliJ IDE 系列的 Flutter Plugin 也為 Flutter 2 添加了一些新功能。首先,有一個新的專案嚮導,它與 IntelliJ 中的新嚮導樣式相匹配。

此外,如果您在 Linux 上使用 IntelliJ 或 Android Studio 對 從 Snap 商店安裝的 Flutter SDK 進行編程,則 Flutter snap 路徑已添加到已知 SDK 路徑列表中。這使得 Snap 的 Flutter 使用者可以更輕鬆地在設定中配置 Flutter SDK。感謝 MarcusTomlinson@ 的貢獻!

Linux 上的 Android Studio 更易於使用透過 Snap 安裝的 Flutter SDK

您可以在最近更新的公告中閱讀更多關於這些好東西的內容:

  • IntelliJ Plugin M51
  • IntelliJ Plugin M52
  • IntelliJ Plugin M53
  • IntelliJ Plugin M54

Visual Studio Code 擴展

Visual Studio Code 的 Flutter 擴展也針對 Flutter 2 進行了改進,從許多測試增強功能開始,包括僅重新執行失敗測試的功能。

經過兩年的開發,Dart 的 LSP(語言伺服器協定)支援現在正在推出,作為獲得 Dart 分析器以整合到 Visual Studio Code 的 Flutter 擴展中的預設方式。LSP 支援為 Flutter 開發帶來了許多改進,包括能夠在當前的 Dart 檔案中應用特定類型的所有修復程式,以及讓程式碼完成生成完整的函數調用,包括括號和必需參數。

而且 LSP 支援不僅僅適用於 Dart;它也支援在 pubspec.yamlanalysis_options.yaml 檔案中的程式碼完成。

這些只是 Visual Studio Code 的 Flutter 擴展最近獲得的一些更新。您可以在這些公告中閱讀完整的列表:

  • Visual Studio Code Plugin v3.16
  • Visual Studio Code Plugin v3.17
  • Visual Studio Code Plugin v3.18
  • Visual Studio Code Plugin v3.19
  • Visual Studio Code Plugin v3.20

DartPad 更新為支援 Flutter 2

這個工具更新列表沒有提及 DartPad 就不完整,DartPad 已更新為支援 Flutter 2。

DartPad 已更新為支援 Flutter 2

現在

http://creativecommons.org/licenses/by/4.0/

【文章翻譯】Announcing Dart 2.12

【文章內容使用 Gemini 1.5 Pro 自動翻譯產生】

宣佈 Dart 2.12

今天,我們宣佈推出 Dart 2.12,其中包含 完善的空安全Dart FFI 的穩定版本。空安全是我們最新的主要生產力功能,旨在幫助您避免空錯誤,這是一類通常難以發現的錯誤,如此影片介紹 中所述。FFI 是一種互操作性機制,可讓您調用以 C 語言編寫的現有程式碼,例如調用 Windows Win32 API。Dart 2.12 現已推出。

Dart 平台的獨特功能

在詳細探討完善的空安全和 FFI 之前,讓我們先討論一下它們如何符合我們對 Dart 平台的目標。程式語言往往具有許多共同的功能。例如,許多語言都支援物件導向程式設計或在網路上執行。真正讓語言與眾不同的是它們獨特的功能組合。

Dart 的獨特功能涵蓋三個維度:

  • 可攜性:高效的編譯器為設備生成 x86 和 ARM 機器碼,並為網路生成優化的 JavaScript。支援廣泛的目標平台 - 行動設備、桌上型電腦、應用程式後端等等。大量的函式庫和套件提供了可在所有平台上運作的一致 API,進一步降低了建立真正的跨平台應用程式的成本。
  • 生產力:Dart 平台支援熱重載,可為原生設備和網路實現快速、迭代的開發。Dart 還提供豐富的結構,例如 isolates 和 async/await,用於處理常見的並行和事件驅動的應用程式模式。
  • 穩健性:Dart 完善的空安全類型系統可在開發過程中捕獲錯誤。整個平台具有高度的可擴展性和可靠性,大型應用程式(包括 Google Ads 和 Google Assistant 等業務關鍵型應用程式)已在生產環境中使用超過十年。

完善的空安全使類型系統更加穩健,並提升效能。Dart FFI 可讓您使用現有的 C 函式庫以獲得更好的可攜性,並讓您可以選擇使用高度調整的 C 程式碼來執行效能關鍵型任務。

完善的空安全

完善的空安全是自 Dart 2.0 中引入完善的類型系統以來,對 Dart 語言的最大補充。空安全進一步增強了類型系統,使您能夠捕獲空錯誤,這是應用程式崩潰的常見原因。透過選擇使用空安全,您可以在開發過程中捕獲空錯誤,從而防止生產環境中的崩潰。

完善的空安全是圍繞幾個核心原則設計的。讓我們重新審視這些原則如何影響您作為開發人員。

預設不可为空:類型系統的根本性變化

在空安全之前,核心挑戰是您無法區分預期傳遞空值的程式碼和不適用於空值的程式碼。幾個月前,我們在 Flutter master channel 中發現了一個錯誤,其中各種 flutter tool 指令會在某些機器配置上因空錯誤而崩潰:在 null 上調用了方法 ‘>=’。根本原因是如下程式碼:

1
2
3
4
5
6
final int major = version?.major;
final int minor = version?.minor;
if (globals.platform.isMacOS) {
// Android Studio 的 plugin 路徑在 4.1 版後發生了變化。
if (major >= 4 && minor >= 1) {
...

您能發現錯誤嗎?因為 version 可以為 null,所以 major 和 minor 也都可能為 null。這個錯誤在這裡單獨看來似乎很容易發現,但在實踐中,這樣的程式碼經常會被忽略,即使是像 Flutter 儲存庫中使用的嚴格程式碼審查流程也是如此。有了空安全,靜態分析可以立即捕獲此問題。(在 DartPad 中即時試用。)

IDE 中分析輸出的螢幕截圖

這是一個非常簡單的錯誤。在 Google 內部早期使用空安全的程式碼中,我們發現了更多複雜的錯誤。其中一些錯誤已經存在多年了,但如果沒有空安全的額外靜態檢查,團隊就無法找到原因。以下是一些例子:

  • 一個內部團隊發現,他們經常檢查永遠不可能為 null 的表達式的空值。這個問題最常見於使用 protobuf 的程式碼中,其中可選欄位在未設定時返回預設值,而不是 null。因此,程式碼會因為混淆預設值和空值而錯誤地檢查預設條件。
  • Google Pay 團隊在他們的 Flutter 程式碼中發現了錯誤,當他們嘗試在 Widget 上下文之外存取 Flutter State 物件時,這些程式碼會失敗。在空安全之前,這些物件會返回 null 並掩蓋錯誤;有了空安全,完善的分析確定這些屬性永遠不可能為 null,並拋出分析錯誤。
  • Flutter 團隊發現了一個錯誤,如果將 null 傳遞給 Window.render() 中的 scene 參數,Flutter 引擎可能會崩潰。在空安全遷移過程中,他們加入了一個提示,將 Scene 標記為不可为空,然後就能夠輕鬆防止 null 可能觸發的潛在應用程式崩潰。

使用預設不可为空

啟用空安全後,變數宣告的基礎知識會發生變化,因為預設類型是不可为空的:

1
2
3
4
// 在空安全 Dart 中,這些都不可能為 null。
var i = 42; // 推斷為 int。
String name = getFileName();
final b = Foo();

如果要建立一個可以包含值或 null 的變數,則需要透過在類型後面加上 ? 後綴,在變數宣告中明確指出:

1
2
// aNullableInt 可以包含整數或 null。
int? aNullableInt = null;

空安全的實作非常穩健,具有豐富的靜態流程分析,使使用可为空類型更加容易。例如,在檢查 null 後,Dart 將局部變數的類型從可为空提升為不可为空:

1
2
3
4
5
6
7
int definitelyInt(int? aNullableInt) {
if (aNullableInt == null) {
return 0;
}
// aNullableInt 現在已提升為不可为空的 int。
return aNullableInt;
}

我們還加入了一個新的關鍵字 required。當命名參數標記為 required(這在 Flutter Widget API 中經常發生)並且調用者忘記提供參數時,就會發生分析錯誤:

逐步遷移至空安全

由於空安全是對我們類型系統的根本性變更,如果我們堅持強制採用,將會造成極大的破壞。因此, 可以決定何時是合適的時機,空安全是一項可選功能:您可以使用 Dart 2.12 而無需強制啟用空安全。您甚至可以依賴已啟用空安全的套件,無論您的應用程式或套件是否已啟用空安全。

為了幫助您將現有程式碼遷移至空安全,我們提供了一個遷移工具和一個遷移指南。該工具首先分析您所有的現有程式碼。然後,您可以互動式地審查該工具推斷出的可空性屬性。如果您不同意該工具的任何結論,您可以加入可空性提示來更改推斷。加入一些遷移提示可以對遷移品質產生巨大影響。

目前,使用 dart createflutter create 建立的新套件和應用程式不會啟用完善的空安全。我們預計在未來的穩定版本中更改這一點,屆時我們會看到大多數生態系統都已遷移。您可以使用 dart migrate 輕鬆地在新建的套件或應用程式中啟用空安全

Dart 生態系統空安全遷移狀態

在過去的一年中,我們提供了幾個完善的空安全的預覽版和測試版,目的是在生態系統中播種支援空安全的套件。這項準備工作很重要,因為我們建議按順序遷移至完善的空安全 - 在所有依賴項都已遷移之前,您不應遷移套件或應用程式。

我們已經發佈了由 DartFlutterFirebaseMaterial 團隊提供的數百個套件的空安全版本。我們也看到了來自 Dart 和 Flutter 生態系統的大力支援,因此 pub.dev 現在有超過一千個套件支援空安全。重要的是,最受歡迎的套件率先遷移,因此在前 100 個最受歡迎的套件中,有 98% 支援空安全,前 250 個中有 78%,前 500 個中有 57% 在今天的發佈之前已經支援空安全。我們期待在未來幾周內看到更多具有空安全的套件出現在 pub.dev 上。我們的分析顯示,pub.dev 上的絕大多數套件已經沒有阻礙,可以開始遷移

完善的空安全的好處

一旦您完全遷移,Dart 的空安全就是完善的。這意味著 Dart 可以 100% 確定具有不可为空類型的表達式不可能為 null。當 Dart 分析您的程式碼並確定變數為不可为空時,該變數始終 為不可为空。Dart 與 Swift 共享完善的空安全,但其他程式語言並不多。

Dart 空安全的完善性還有另一個值得歡迎的含義:它意味著您的程式可以更小、更快。因為 Dart 確定不可为空變數永遠不會為 null,所以 Dart 可以優化。例如,Dart ahead-of-time (AOT) 編譯器可以生成更小、更快的原生程式碼,因為它在知道變數不為 null 時不需要加入 null 檢查。

Dart FFI,用於整合 Dart 與 C 函式庫

Dart FFI 可讓您利用 C 函式庫中的現有程式碼,以提高可攜性,並與高度調整的 C 程式碼整合,以執行效能關鍵型任務。從 Dart 2.12 開始,Dart FFI 已脫離 測試 階段,現在被認為是穩定的,可供生產使用。我們還加入了一些新功能,包括巢狀結構體和按值傳遞結構體。

按值傳遞結構體

在 C 程式碼中,結構體可以透過引用和按值傳遞。FFI 以前只支援透過引用傳遞,但從 Dart 2.12 開始,您可以按值傳遞結構體。以下是一個透過引用和按值傳遞的兩個 C 函數的小例子:

1
2
3
4
struct Link {
double value;
Link* next;
};
1
2
3
void MoveByReference(Link* link) {
link->value = link->value + 10.0;
}
1
2
3
4
Coord MoveByValue(Link link) {
link.value = link.value + 10.0;
return link;
}

巢狀結構體

C API 經常使用巢狀結構體 - 本身包含結構體的結構體,例如:

1
2
3
4
5
6
7
8
9
struct Wheel {
int spokes;
};

struct Bike {
struct Wheel front;
struct Wheel rear;
int buildYear;
};

從 Dart 2.12 開始,FFI 支援巢狀結構體。

API 變更

作為宣佈 FFI 穩定的部分,以及為了支援上述功能,我們進行了一些較小的 API 變更。

現在不允許建立空結構體(重大變更 #44622),並會產生棄用警告。您可以使用新的類型 Opaque 來表示空結構體。dart:ffi 函數 sizeOfelementAtref 現在需要編譯時類型參數(重大變更 #44621)。由於 package:ffi 中加入了新的便捷函數,因此在常見情況下不需要額外的樣板程式碼來分配和釋放記憶體:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 分配一個指向 Utf8 陣列的指標,從 Dart 字串填充它,
// 將其傳遞給 C 函數,轉換結果,並釋放參數。
//
// API 變更前:
final pointer = allocate<Int8>(count: 10);
free(pointer);
final arg = Utf8.toUtf8('Michael');
var result = helloWorldInC(arg);
print(Utf8.fromUtf8(result);
free(arg);

// API 變更後:
final pointer = calloc<Int8>(10);
calloc.free(pointer);
final arg = 'Michael'.toNativeUtf8();
var result = helloWorldInC(arg);
print(result.toDartString);
calloc.free(arg);

自動生成 FFI 繫結

對於大型 API 表面,編寫與 C 程式碼整合的 Dart 繫結可能會非常耗時。為了減少這種負擔,我們建置了一個繫結產生器,用於從 C 標頭檔自動建立 FFI 包裝器。我們邀請您試用:package:ffigen

FFI 路線圖

隨著核心 FFI 平台的完成,我們將把重點轉向透過在核心平台之上分層的功能來擴展 FFI 功能集。我們正在研究的一些功能包括:

FFI 的應用範例

我們已經看到許多創造性地使用 Dart FFI 與各種基於 C 的 API 整合的例子。以下是一些例子:

  • open_file 是一個用於在多個平台上打開檔案的單一 API。它使用 FFI 在 Windows、macOS 和 Linux 上調用原生作業系統 API。
  • win32 包裝了最常見的 Win32 API,可以直接從 Dart 調用各種 Windows API。
  • objectbox 是一個由基於 C 的實作支援的快速資料庫。
  • tflite_flutter 使用 FFI 包裝 TensorFlow Lite API。

Dart 語言的下一步是什麼?

完善的空安全是我們多年來對 Dart 語言所做的最大變更。接下來,我們將在牢固的基礎上,對語言和平台進行更多漸進式變更。以下是我們在語言設計漏斗中正在試驗的一些內容的快速概覽:

類型別名#65):建立非函數類型類型別名的能力。例如,您可以建立一個類型定義並將其用作變數類型:

1
2
typedef IntList = List<int>;
IntList il = [1,2,3];

三移位運算子#120):加入一個新的、完全可覆蓋的 >>> 運算子,用於對整數執行無符號位移。

泛型中繼資料註釋#1297):擴展中繼資料註釋以支援包含類型參數的註釋。

靜態元程式設計#1482):支援靜態元程式設計 - 在編譯期間產生新的 Dart 原始程式碼的 Dart 程式,類似於 Rust 巨集 和 Swift 函數建置器。此功能仍處於早期探索階段,但我們認為它可以實現當前依賴程式碼生成的使用案例。

Dart 2.12 現已推出

具有完善空安全和穩定 FFI 的 Dart 2.12 現已在 Dart 2.12Flutter 2.0 SDK 中提供。請花點時間查看Dart 的已知空安全問題Flutter 的已知空安全問題。如果您發現任何其他問題,請在 Dart 問題追蹤器 中回報。

如果您開發了在 pub.dev 上發佈的套件,請立即查看遷移指南,並了解如何遷移至完善的空安全。遷移您的套件可能有助於解除其他依賴它的套件和應用程式的阻礙。我們也要感謝那些已經遷移的人!

我們很樂意聽到您對完善的空安全和 FFI 的體驗。請在下方留言或在 Twitter 上 dart_lang 中提及我們。


宣佈 Dart 2.12 最初發佈於 Medium 上的 Dart,人們在那裡透過突出顯示和回應這個故事來繼續討論。

【文章翻譯】Preparing the Dart and Flutter ecosystem for null safety

【文章內容使用 Gemini 1.5 Pro 自動翻譯產生】

空安全現在已進入 API 穩定階段。立即發佈您的穩定套件!

今天,我們宣布 Dart 的一個新的 Beta 版本。此 Beta 版本代表了新的 健全空安全類型系統的新級別的穩定性和信心,我們已經為此努力了一年多。更新的 Dart Beta 版本 (2.12.0–259.9.beta) 可以在 dart.dev 上獲得,也包含在 Flutter 的 Beta 頻道 中。我們預計從現在到此功能的穩定版本之間不會再有任何重大變更。

如果您是套件開發人員,我們邀請您開始發佈套件的穩定、空安全版本,以便在我們發佈帶有空安全的 Dart 穩定版本時,為使用者提供最佳體驗。我們自己已經開始了這個過程,發佈了空安全套件的穩定版本,例如 argsyamlgrpc。如果您的所有相依項都是空安全的,並且以穩定版本發佈(例如 1.0.0 而不是 1.0.0-nullsafety.123),那麼現在是您也這樣做的時候了!

我們還為 pub.dev 加入了新功能,當套件版本的相依 Dart SDK 還沒有發佈到穩定版本時,將其標記為 預覽版本。一旦新的穩定版 Dart SDK 發佈,預覽版本將自動升級為常規穩定版。

pub.dev 顯示 args 套件,其中包含 1.6.0 穩定版本和 2.0.0 預覽版本

空安全遷移指南 提供了關於如何遷移套件的最新資訊。請密切注意 pubspec 中的 Dart SDK 約束和相依項的版本,以及您在持續整合 (CI) 測試中使用的 SDK 版本。

帶有空安全的 Dart 穩定版本即將推出!感謝您幫助我們實現這一目標。


為空安全準備 Dart 和 Flutter 生態系統 最初發佈在 Medium 的 Dart 上,人們在那裡透過突出顯示和回應這個故事來繼續討論。

http://creativecommons.org/licenses/by/4.0/

【文章翻譯】Flutter Performance Updates in the first half of 2020

【文章內容使用 Gemini 1.5 Pro 自動產生】

Flutter 在 2020 年上半年的效能更新

作者:Yuqian LiShams Zakhour

速度是 Flutter 的關鍵支柱。本文重點介紹 Flutter 社群成員在 2020 年上半年實施的效能改進。

如果您在 2020 年 6 月之後幫助過效能改進,我們將在未來的文章中涵蓋這些內容。我們希望與您分享這些內容,希望 Flutter 社群受到鼓舞,一起參與改進 Flutter 效能的努力!

量化改善

貢獻者: alexmarkovsstricklmkustermannaskeksa-googlermacnak-googlemralephcrelier

[應用程式大小] 透過字體子集處理,Gallery 應用程式縮減了 100KB 的大小

貢獻者: dnfieldjonahwilliamszandersojmagmanblasten

  • PR 1482849737498425022451808
  • Flutter Gallery 應用程式縮减了 100KB 的大小 (大小縮減)
  • 修復了「搖樹 Material 圖示 16311」,「將 hb-subset 作為引擎組建的一部分進行組建並上傳到雲端儲存 43642」,「在 flutter_tools 中使用 font-subset 並搖樹圖示字體 43644」,「為所有平台連接字體子集處理 49730“)。

[速度、記憶體] dart2js 工具的運行速度提升了 9 倍,記憶體減少了 99% 以上

貢獻者: rmacnak-googlea-siva

[速度] 從 OpenGL 切換到 Metal,iOS 平均渲染速度提升了 50%

貢獻者: chinmaygardednfieldjason-simmonscbrackenamirhliyuqian

[速度] 由於著色器編譯,最差畫面渲染時間提升了 2 到 5 倍

貢獻者: liyuqianjonahwilliamschinmaygardeiskakaushikzandersosfshaza2filiphacoutts

  • PR 173005385917601178615874356638443012142
  • Android 的 flutter_gallery__transition_perf 最差畫面渲染時間 worst_frame_rasterizer_time_millis 提升了 2.25 倍 (從 90ms 到 40ms)
  • iOS 的 flutter_gallery_ios32__transition_perf 最差畫面渲染時間 worst_frame_rasterizer_time_millis 提升了 5 倍 (從 300ms 到 60ms)
  • 一些實際應用程式的速度提升了 3.75 倍 (從 229ms 到 61ms)
  • 修復了「基於 SkSL 的著色器預熱 53607」、「三次貝茲曲線回歸 35142」和「儲存」一些客戶。

[速度] 滑鼠點擊測試速度提升了 15.8 倍

貢獻者: dkwingsmtyjbanovgoderbauergspencergoog

  • PR 59803 59883
  • bench_mouse_region_grid_scroll 的畫面持續時間 (網頁) 提升了 15.8 倍 (從 79ms 到 5ms)。
  • 修復了「訂閱 MouseRegion 事件時效能低下 41194

[速度] 平台訊息回應處理速度提升了 13.9 倍

貢獻者: zljj0818jason-simmonsliyuqian

  • PR 1883818945,兩者都受 18808 啟發
  • 修復了「載入大型圖片時,Image.asset 會阻塞 UI 線程 58572
  • PlatformMessageResponseDartComplete 速度提升了 13.9 倍 (從 9164us 到 660us)

[速度] 使用不透明路由時,畫面構建時間提升了 20% 到 37%

貢獻者: goderbauerdnfield

  • PR 48900
  • flutter_gallery_ios32__transition_perf 的平均畫面構建時間 average_frame_build_time_millis 提升了 20% (從 7.38ms 到 6.13ms)
  • flutter_gallery_ios32__transition_perf 的第 99 個百分位數畫面構建時間 99th_percentile_frame_build_time_millis 提升了 37% (從 50.45ms 到 36.63ms)
  • 修復了「在推入覆蓋/導航器不透明內容時,優化不必要的重建 45797

[速度] 使用 ImageFiltered 而不是 BackdropFilter,模糊效果速度提升了 4.8 倍

貢獻者: flarhixieyjbanovliyuqian

[速度] 使用 Flutter 網頁捲軸大型靜態內容時,速度提升了 14 倍

貢獻者: yjbanovferhatb

  • PR 17621
  • text_canvas_cached_layout.html.layout.average 速度提升了 14.01 倍 (從 463.74ms 到 33.10ms)
  • 修復了「使用 Flutter Web 捲軸大型靜態內容時卡頓 42987」和「在 Web 上繪製畫布邊界外的文字很昂貴 48516

[速度] Flutter 引擎 Shell 初始化速度提升了 6.8 倍

貢獻者: scutlightjason-simmonsgaaclarkeliyuqian

[速度] 限制條件相同時,跳過調用構建器,速度提升了 5 倍

貢獻者: yjbanovhixie

  • PR 55414
  • 使用 Flokk 客戶端應用程式捲軸聯絡人列表時,速度提升了 5 倍(從大約 10FPS 到大約 50FPS)。
  • 修復了「LayoutBuilder 應該快取限制條件,如果沒有改變就不應該重新建立 6469

[速度] 網頁上的陰影和動畫速度提升了 2 倍

貢獻者: ferhatbmdebbaryjbanov

貢獻者: ferhatbclocksmithrami-a

[速度] 在 Fuchsia 中啟用柵格快取後,平均畫面渲染時間提升了 2.8 倍

貢獻者: drevemanliyuqianchinmaygardearbreng

  • PR 17753
  • frame_rasterizer_times_avg 速度提升了 2.8 倍(從大約 10ms 到大約 3.5ms)
  • 修復了「由於柵格快取被停用,Fuchsia 上的效能低下 54950

[速度] 透過排除無效的動畫圖片,第 90 個百分位數畫面構建時間提升了 1.85 倍

貢獻者: dnfieldliyuqiantvolkertdigiter

  • PR 5085150842
  • animated_placeholder_perf 的第 90 個百分位數畫面構建時間提升了 1.85 倍 (從 3.148ms 到 1.699ms)
  • 修復了「當長列表中的卡片內部使用列表構建器時,flutter 的畫面速率很低 (平均 20 到 35fps) 35592

[速度] Google 智能顯示器 P10 的 FPS 提升了 2 倍

貢獻者: chinmaygardednicoaracbrackenjason-simmonsasakhartrdaum

  • PR 15980
  • 透過讓嵌入器可以調整線程優先順序,速度提升了 2 倍(從 30fps 到 60fps)。
  • 修復了問題 49551

[速度] 透過增強子元素快取,ImageFilterLayer 的速度提升了 2.45 倍

貢獻者: flarliyuqian

  • PR 171755490358277
  • ImageFiltered Transform 的平均畫面渲染時間 average_frame_rasterizer_time_millis 提升了 2.45 倍 (從 18.41ms 到 7.53ms)
  • 還修復了「由於 OpacityLayer 柵格快取未命中,轉場效能略有下降 52864

[速度] 大型 dart2js 編譯速度提升了 15%

貢獻者: rmacnak-googlea-siva

[速度] 大型應用程式的 AOT 編譯時間提升了 1.8 倍

貢獻者: alexmarkovmralephsigurdmcskau-g

[速度] Dart RegExp 在 AOT 模式下的匹配速度提升了 5 到 13 倍

貢獻者: mralephrmacnak-google

[速度] Dart UTF8 解碼速度提升了 5 倍

貢獻者: askeksa-googlemkustermannrakudrama

  • 提交 cf6f89e35ca378df4afa2fd4
  • X64JIT TwoByteString 基準測試速度提升了 5.02 倍。
  • 修復了「快速路徑 Uint8List 到 _OneByteString 轉換 41703」、「直接將 UTF-8 結果寫入字串 41704

[速度] async/sync* 函數的速度提升了 35% 到 65%

貢獻者: cskau-gmkustermannmraleph

  • 提交 e29407fdca1f7ed169ca94ad
  • 在 {dart,dart-aot}-{ia32,x64,armv7hf,armv8} 上,Calls.IterableManualIterablePolymorphicManyYields 的速度提升了 35% 到 65%。
  • 修復了「改進 VM 上 sync* 程式碼的效能 37753」、「在 VM 中生成 sync-yield 函數時,評估使用 IndirectGoto 37754

[速度] 使用未裝箱的參數和欄位,時間最多減少了 31.82%

貢獻者: mkustermannmkustermann

  • 提交 9eb531b95149e076e79eb531
  • matrix_utils_transform_rect_affine 迭代時間最多減少了 31.82%。
  • 修復了「Dart VM 中的真實未裝箱欄位 40004

[速度] Dart Pointer<Int8,Int64,etc> 在 AOT 中的載入/儲存速度提升了 20% 到 25%

貢獻者: dcharkesmkustermann

  • 提交 408123
  • 在 x64 上,AOT 中的 Pointer&lt;Int8,Int64,etc&gt; 載入/儲存速度提升了 20% 到 25%。
  • 幫助「儲存和載入應該支援未裝箱的索引 (在 AOT 中) 39432

其他改進

[應用程式大小、能源、記憶體、速度] 將 A/B 測試模式加入到本機 Devicelab 執行器

貢獻者: yjbanovflarferhatbchristopherfujinoliyuqian

[應用程式大小] 修復了「常見問題解答中 iOS 應用程式大小不正確」

貢獻者: [jmagman](https://github.com/

【文章翻譯】Are you happy with Flutter? — Q4 2020 user survey results

【文章內容使用 Gemini 1.5 Pro 自動產生】

您對 Flutter 感到滿意嗎? - 2020 年第 4 季使用者調查結果

Google 的 Flutter 團隊自 2018 年以來便持續進行每季一次的調查,以收集您的意見回饋 自 2018 年以來。上一季度的調查於 2020 年 11 月 23 日發布,並持續進行了 8 天。團隊收集了 8,285 份回饋,我們想與您分享這些結果!儘管這次調查的長度只有我們平常調查的一半,但我們還是像往常一樣從您的答案中學到了很多。我們非常感謝您撥冗提供寶貴的意見回饋。

使用者滿意度

總體而言,92% 的受訪者對 Flutter 有些滿意非常滿意。我們很高興能夠持續維持高滿意度。

92% 的使用者對 Flutter 感到滿意,其中 51% 非常滿意。

從圖表中可以看出,我們也學到了以下資訊:

  • 91% 的受訪者表示 Flutter 很適合他們的專案。
  • 90% 的受訪者承诺并希望在下一个项目中使用 Flutter。
  • 58% 的受访者表示 Flutter 对其公司的成功至关重要。

這些結果表明 Flutter 繼續蓬勃發展,並成為開發者工具箱的重要組成部分。

90% 的使用者希望在下個專案中使用 Flutter。

但是,我們注意到整體滿意度自上一季調查以來略有下降,從 94% 降至 92%。為了了解為什麼您對 Flutter 的各個方面並未完全滿意,團隊仔細審閱了開放式意見回饋。感謝您的回饋,團隊意識到了一些主要問題,並將投資於高優先順序項目。例如,我們計劃 改進程式碼完成,因為我們發現這是 IDE 相關問題中最常見的挫折來源。

難點

這次,我們採用了不同的方法來了解 Flutter 的難點。我們想了解什麼阻礙了您更多地使用 Flutter。當我們詢問「如果不是因為以下原因,我會更多地使用 Flutter」,26% 的受訪者選擇了 缺乏關鍵函式庫 作為原因。作為回應,我們正與 BaseflowInvertaseCodemagic 合作,以提高我們第一方套件和外掛的品質。雖然團隊正在努力改進先前研究中識別出的關鍵函式庫,但我們也在使用標籤 would be a good package 監控問題追蹤器中的特定需求,以便任何人都可以找出生態系統中缺少什麼,並為其做出貢獻。

由於 Flutter 相容套件的數量超過 15,000 個,並且 Flutter 團隊無法擴展規模來處理可能被認為是關鍵的數十甚至數百個套件,因此我們為社群提供了一系列機制來 評分套件。我們提供這些機制,以便搜尋結果能產生高品質的結果,包括讚好、靜態分析和 Flutter Favorite 認證,該認證由一群 Flutter 社群志願者頒發。這樣做不僅鼓勵您貢獻更多套件來涵蓋關鍵方面,而且套件的品質也會隨著時間推移而提升,因為套件作者會因其工作而獲得更好的分數和認可。我們將繼續投資於這個領域,以便生態系統能夠自給自足,並持續自然地提高品質。

26% 的使用者需要更多函式庫。此結果不包括 19% 表示我目前使用 Flutter 足夠的使用者。

為了讓那些從事 Flutter 之外專案的人(19%)更容易,我們將繼續投資於 add-to-app,這有助於您將 Flutter 模組整合到現有的 Android 或 iOS 應用程式中。您可以在 GitHub 議題 72009 上追蹤相關功能的進度。

核心框架中缺少的功能 被 18% 的受訪者選中。在我們仔細查看開放式意見回饋後,發現回饋集中在 Flutter 框架中包含的功能與套件提供的功能之間的界線上。雖然有些人希望框架包含更多超出使用者介面 API 的功能是可以理解的,但我們的重點是我們最擅長的 - 提供出色的 UI 框架。但是,我們想為您提供所需的功能,因此我們與社群貢獻者合作,透過套件和外掛提供特定領域和特定平台的功能。如前所述,我們投資了工具和計畫來認可高品質的套件,並幫助您在生態系統中發現它們。我們歡迎您提供回饋意見和想法,以進一步增強我們的套件生態系統。

線上社群

在這次調查中,團隊想知道您在哪裡與其他 Flutter 開發人員交流資訊或想法。雖然 21% 的受訪者表示他們沒有參與任何線上社群,但我們發現 Stack Overflow 是 Flutter 開發人員相互聯繫的最受歡迎的社群。38% 的受訪者選擇 Stack Overflow 作為他們最活躍的線上社群。

Stack Overflow 是 38% 的受訪者的主要線上社群。此圖表省略了 21% 沒有參與任何線上社群的使用者。

受訪者最活躍的地方不同,他們對社群有用性的評分也不同。例如,我們詢問「您在多大程度上同意或不同意以下關於您在上一個問題中選擇的線上社群的陳述?」對於回應 *”當我在社群中向其他 Flutter 使用者提問時,我能夠得到答案”*,在 Stack Overflow 上活躍的 75% 受訪者同意他們在 Stack Overflow 上提問時能夠得到答案。此外,61% 主要活躍在即時通訊服務上的受訪者表示他們也得到了答案。

受訪者被要求評估他們對 *"當我問…” 的問題時,我能夠得到答案"* 這個陳述的同意程度,結果因他們活躍的社群而異。

這是我們第一次評估使用者在線上的分佈情況以及他們對各種線上社群的看法。建立一個有用的和蓬勃發展的社群對 Flutter 的成功至關重要。我們與您分享這些結果,希望幫助提供者和尋求者都能更好地利用這些線上溝通管道。Flutter 團隊將監控這些資料,以指導我們的支援和教育工作,並確保您能夠尋求幫助並保持聯繫。

Flutter 活動

每年都会由当地社区小组和 Flutter 贡献者组织许多面向 Flutter 社区的线下和线上活动,约 90% 参加活动的受访者表示他们在活动中了解了 Flutter 的新知识,并认为这些信息很有帮助。虽然这些活动是有效的学习机会,但通过我们的研究,我们现在知道大多数受访者 (61%) 在 2020 年并不知道这些活动。即使我们没有像 2019 年那样举办 Flutter Interact 这样的大型活动来宣传这些活动,但这个百分比仍然高于我们的预期。因此,在计划 2021 年 3 月 3 日的 Flutter Engage 活动 时,我们将与区域 Google 团队合作,帮助宣传这些活动。我们也正在与当地 Flutter 小组密切合作,以确保我们的活动内容能够传达给更多 Flutter 社区成员。每个人都欢迎参加这个免费的线上活动。

61% 的在 2020 年没有参加任何活动 (线上和线下) 的使用者不知道有这些活動。
85% 或以上的使用者從各種 Flutter 活動中學到了新東西。

接下來會發生什麼事?

下一項調查將於 2 月底左右在 flutter.devFlutteDev (和 Flutter IDE Plugin 中宣布。您也可以透過 註冊 來參與其他研究,以參與即將到來的 UX 研究。

請繼續分享您的想法,因為團隊正在尋找重要問題的答案。

再次感謝所有參與本次調查並提供宝貴意見回饋的人。感謝您的時間和努力!

Flutter Engage 期待與您相見!


您對 Flutter 感到滿意嗎? - 2020 年第 4 季使用者調查結果 最初發佈在 Flutter 上的 Medium,人們在那裡透過突出顯示和回應這個故事來繼續討論。

【文章翻譯】Join us for

【文章內容使用 Gemini 1.5 Pro 自動產生】

加入我們,一起參與 #30DaysOfFlutter

30 天 Flutter 活動的標語

新年快樂各位!現在正是學習新事物的好時機!您是否在假期裡想過要開發一個應用程式?如果是的話,我們有一個絕佳的機會等著您!從 2 月 1 日開始,在我們於 3 月 3 日舉行的盛大 活動 之前,加入我們參與 #30DaysOfFlutter,開啟您的學習旅程,並結識社群中的 Flutter 專家。無論您是正在開發您的第一個 Flutter 應用程式,還是在尋找提升 Flutter 技能的方法,我們都準備了精心策劃的內容、程式碼實驗室和示範!

Flutter 是 Google 的開源 UI 工具包,用於從單一程式碼庫建立精美的原生編譯應用程式,適用於行動、網頁和桌面。它是成長最快速、需求量最大的跨平台框架之一,被全球的自由接案開發員和大型組織使用。Flutter 使用 Dart 語言,因此對於熟悉面向物件語言的許多人來說,它會感覺很自然。

跳進來吧,水很溫和!

除了精心策劃的內容,我們還將舉辦四場現場 問我任何問題 (#AMA) 討論會,您可以在其中與 Google 的 Flutter 團隊和社群成員見面。您也可以加入我們在 FlutterDev Discord 頻道 上,在那裡您可以結識社群中的其他成員,提出和回答問題,甚至還可以交到新的 Flutter 朋友!

聽起來很令人興奮嗎?請訪問 30 天 Flutter 網站 了解更多資訊,並註冊加入。註冊截止日期為 2021 年 1 月 31 日太平洋時間晚上 11:30。

#30DaysOfFlutter 議程

您在本月的 Flutter 學習旅程將如下所示:

第 1 週

收到精心策劃的內容到您的收件匣。在 Discord 上結識其他 Flutter 開發人員。參加 2 月 1 日的啟動網路研討會。

第 2 週

收到更多內容。開始開發您的第一個 Flutter 應用程式。加入網路研討會並提出您的問題。

第 3 週

繼續開發您的應用程式,並參加第 3 場網路研討會,提出您的問題。

第 4 週

完成您的專案,學習如何與 Flutter 社群分享您的作品。

您是否準備好學習世界上最熱門的開發者技能之一?

註冊 加入這個旅程,並務必在 Twitter 上關注 FlutterDev (@FlutterDev),以獲得有關 #30DaysOfFlutter 的最新更新。


加入我們,一起參與 #30DaysOfFlutter 最初發佈在 Flutter 上的 Medium,人們在那裡透過突出顯示和回應這個故事來繼續討論。

http://creativecommons.org/licenses/by/4.0/

【文章翻譯】Dart and the performance benefits of sound types

【文章內容使用 Gemini 1.5 Pro 自動翻譯產生】

Dart 與可靠類型帶來的效能優勢

3 screenshots of machine code: much code → less code → 3 lines of code.
從 Dart 1.24、2.0 和 2.12(從左到右)中的同一個 Dart 方法生成的程式碼變得更小。要了解原因(並查看實際生成的程式碼),請继续阅读。

在過去的幾年中,我們強化了 Dart 的類型系統。最初的 Dart 語言(Dart 1)有一個不可靠的、可選的類型系統(類似於類型的 JavaScript 方言,例如微軟的 TypeScript 或 Facebook 的 Flow)。Dart 2 引入了一個更嚴格的、可靠的類型系統。在過去的兩年中,我們一直在努力透過 可靠的空安全 進一步擴展類型系統。

雖然可靠的類型系統為開發人員提供了更大的信心,但它也使我們的編譯器能夠安全地使用類型來優化生成的程式碼。有了可靠性,我們的工具透過結合靜態和(必要時)運行時檢查來保證類型的正確性。沒有可靠性,類型檢查只能進行到一定程度,並且靜態類型在運行時可能不正確。

在實踐中,可靠性允許我們的編譯器生成更小、更快的程式碼,尤其是在提前 (AOT) 設定中,我們將預編譯的原生程式碼傳送給客戶端。

範例

以下範例方法演示了可靠類型如何對相對簡單的程式碼產生巨大影響:

1
2
3
int getAge(Animal a) {
return a.age;
}

在我們最後一個穩定的 Dart 1 版本 (1.24.3) 中,這個方法映射到 26 個原生 x64 指令——這還是在檢測和設定檔引導的優化之後,這會減慢初始運行時啟動速度。在 Dart 2.12 中使用可靠的空安全,此程式碼僅映射到 3 個指令,而無需任何設定檔引導的優化。

Dart 編譯為 ARM32/64 和 x86/x64 架構。在以下範例中,我們使用 x64,但在其他目標上的結果類似。

範例方法的完整 Dart 程式碼和上下文顯示在本文末尾,但以下是重點:

  • Animal 類包含一個類型為 int 的欄位 age
  • Animal 有幾個子類別(CatDogSnakeHamster)。
  • 上述方法在運行時在許多這些類型上被調用。

Dart 物件佈局

當編譯為原生 (x64) 程式碼時,Dart 類 Animal 有一個簡單的佈局:

8 bytes of object header, followed by 8 bytes of `age` field, followed by additional subclass fields.

前 8 個位元組是一個標題,提供具體化的類型資訊(即物件的運行時類型)。第二個 8 個位元組包含 age 欄位。所有子類別都保留(並可能添加到)此結構:任何額外的欄位都佈局在後面,保留基本類型的結構。給定 Animal(或任何子類別)的實例,getAge 方法應從 8 位元組偏移量載入欄位並返回它。

Dart 1:不可靠的類型

然而,在 Dart 1 中,靜態類型並不可靠,並且在編譯期間實際上被忽略。在運行時,我們不能假設靜態類型是正確的(因此,佈局也是預期的)。對 age 的存取可能是對不同偏移量處的欄位、對觸發更多可執行程式碼的 getter 或對不存在的欄位(觸發可捕獲的運行時錯誤)的存取。

Dart 1 被設計為依賴於客戶端設備上的即時編譯器和虛擬機器,該編譯器使用運行時類型資訊來優化程式碼。在這種方案中,我們實際上編譯了每個方法兩次:第一次是為了收集資訊,第二次(對於熱點方法)是根據觀察到的運行時行為生成更優化的程式碼。

Dart 1:第一次編譯

getAge 的第一次編譯在 x64 上產生了以下 47 個指令:

2 columns full of assembly code.

請注意,此程式碼已檢測以確定運行時會發生什麼。它對傳遞的物件沒有任何假設,並且有效地執行等效於雜湊表查找以正確找到欄位、執行 getter 或拋出錯誤。

Dart 1:第二次編譯

在這種情況下,程式碼會被重複調用,並觸發第二次優化編譯,生成以下 26 個指令:

2 columns of assembly code (but less than before). Most of the code is blue (prologue/epilogue) or red (various checks).

這個優化的程式碼仍然很大。它基於設定檔資訊,發現該方法僅在 CatHamsterDog 的實例上被調用,並根據未來也將如此的假設進行了優化。

藍色 程式碼是方法的序言和結尾(用於設置和恢復堆疊框架)。紅色 程式碼檢查預期的情況——實例非空且屬於先前看到的類型之一——並為其他情況調用慢路徑。粗體 程式碼是載入欄位的實際工作。

如果未來的行為與過去不同,優化的程式碼實際上可能會更慢:如果在新的實例(例如 Snake)上調用 getAge,程式碼將執行額外的檢查,但仍然會進入慢路徑。

Dart 1 生成的程式碼的問題

上面的生成的程式碼在結構上與 Chrome 中的 JavaScript 引擎 V8 在給定或多或少等效的 JavaScript/TypeScript/Flow 程序時生成的程式碼非常相似。雖然這種方法(和相應的生成的程式碼)可以在許多情況下提供良好的效能,但當我們開始(尤其是使用 Flutter)面向更廣泛的客戶端平台(包括對大小和記憶體佔用更敏感的行動設備)時,它就不再適合了:

  • 首先,客戶端編譯的成本增加了 Dart 應用程式的整體佔用空間。
  • 其次,兩階段推測編譯的成本對應用程式啟動不利。
  • 第三,iOS 上不允許即時編譯:我們至少需要針對某些目標的替代策略。

我們轉而採用提前編譯方法,但使用 Dart 1 會導致程式碼品質差很多。即使使用複雜的、全程序分析,我們也無法始終在編譯時確定類型資訊,尤其是在應用程式變得更大時。此外,當整個應用程式都被預編譯時,推測的成本(上面的紅色程式碼)變得過高。

Dart 2:可靠的類型

在 Dart 2 中,我們引入了可靠性,這使我們能夠安全地根據類型資訊編譯程式碼,並減少了對設定檔以獲得效能的依賴。使用 Dart 2,在單個提前編譯上,我們在 x64 上生成 10 個指令:

Much less code, but still there’s some blue code (prologue/epilogue) and red code (null checks).

此程式碼仍然執行空檢查(紅色),如果發現空則調用輔助方法。

Dart 2.12:可靠的空安全

有了可靠的空安全,類型系統更加豐富,我們的編譯器可以利用這一點。編譯器可以安全地依賴於(現在的)非空類型,並消除上面的紅色程式碼。在 Dart 2.12 beta 中,我們減少生成了 3 個指令:

Some blue code (prologue/epilogue) but no red code! No null checks needed!

事實上,隨著程式碼變得更簡單,我們也能够簡化序言和結尾。在我們即將發布的穩定版本中,我們將只為範例方法生成 3 個指令:

Even less blue code (prologue/epilogue) than before.

有了可靠的空安全,我們可以將此方法的生成的程式碼減少到其本質:欄位載入。在實踐中,對此方法的調用將始終被內聯,因為編譯器現在可以輕鬆地看到內聯是效能和程式碼大小的雙贏。不再需要運行時檢查和補償程式碼:更多的繁重工作在編譯時完成。我們不再需要客戶端編譯的啟動和記憶體開銷。因此,我們的用戶可以獲得更小、更快的程式碼。

試試看!

我們鼓勵您嘗試 空安全。它在 Dart 2.12 中可用,現在在我們的 beta 頻道中。一旦您的上游相依項被遷移,您就可以遷移您自己的套件和應用程式。正如這裡的範例所示,您可能不需要做太多更改。

請記住,要獲得空安全的效能優勢,您需要一個完全遷移的應用程式。一旦您的應用程式完全遷移,我們的編譯器將自動利用空安全來生成更好、更小的程式碼。

附註:程式碼

這是完整的 Dart 程式碼,我編譯它生成了本文中的所有程式碼。雖然這裡的範例是人為設計的,但模式(類別層次結構中的欄位)相當常見。


Dart 與可靠類型帶來的效能優勢 最初發佈在 Dart 上的 Medium,人們在那裡透過突出顯示和回應這個故事來繼續討論。

http://creativecommons.org/licenses/by/4.0/

【文章翻譯】Providing operating system compatibility on a large scale

【文章內容使用 Gemini 1.5 Pro 自動產生】

大規模提供作業系統相容性

使用 Flutter 編寫的應用程式可以在 Android、iOS、網頁和桌面作業系統上運行。由於我們在支援多個平台方面的投入,Flutter 應用程式可以在任何具有應用程式編寫時所用作業系統版本(或更高版本)的設備上運行,而無需進行任何修改,這擴展了 Flutter 的跨平台吸引力。

在本文中,Flutter 的核心開發團隊(我們)想要分享我們為何投資於支援多個平台,我們如何才能繼續支援多個平台,以及在需要新增對新平台的支援或停止支援舊平台時,我們如何做出決定。

展望未來:Android 和 iOS 的版本

Flutter 致力於為 Android 和 iOS 的最新功能提供完全支援。我們始終監控著 Apple 和 Google 發布的有關其平台 API、工具使用和授權條款變更的定期指南。對新作業系統版本的支援是我們定期產品規劃的一部分,我們會盡量將我們的版本與 Google 和 Apple 的最新指南保持一致,以確保我們的穩定版本始終與兩者的最新指南相容。

我們承諾對您提供多個平台和 Android 和 iOS 的軟體版本(例如 Android 11 或 iOS 14)以及其小版本更新的支援。對於目標平台的主要修訂,我們會在了解到所需內容後立即開始開發必要的功能和更改。這通常發生在春季後期,Google 公佈了其即將發佈的 Android 版本的計劃,而 Apple 在其全球開發者大會 (WWDC) 上發布了最新公告。在發布公告之後,我們會評估 Flutter 程式碼庫中必要的更改,例如由於可能已棄用的 API 導致的引擎更改,工具更改如何影響 flutter 工具和開發人員體驗,以及兩者的設計語言更改。我們還會評估工作範圍,預期這兩個平台都将在秋季初提供給客戶。

我們會針對 Android 和 iOS 的測試版進行這項工作,並會透過我們的 master、dev 和 beta 頻道定期提供這些更改。master 頻道的版本是持續性的。我們計劃每週發佈兩到三個 dev 頻道版本(針對 Google 內部應用程式和測試套件進行測試的 master 頻道版本)。beta 頻道通常在每月的第一週發佈。我們會使用 GitHub 問題追蹤我們的進度。若要查看問題清單,您可以根據 platform-iosplatform-android 搜尋。

將我們的穩定版本發佈時間表與 iOS 保持一致尤其具有挑戰性,因為從新聞發佈到我們獲得有關作業系統更改的指南之間的時間通常非常短。我們會透過在秋季規劃我們的其中一個版本,並準備好針對 iOS 或甚至 Android 上出現的任何阻礙性錯誤對我們目前的穩定版本進行熱修復來減輕這一挑戰。(這發生在 Flutter 1.20 和 iOS 14 上,我們在 iOS 14 發佈的同一天發布了 熱修復)。

無論支援新平台版本需要做多少工作,我們的目標都是支援目標平台的新版本,而不棄用舊版本。

向後相容性和 Flutter 的價值主張

Flutter 是 Google 的可移植 UI 工具包,用於從單一程式碼庫建立針對行動、網頁和桌面的精美的原生編譯應用程式。為此,我們希望支援我們可以支援的最廣泛的設備集合,而不仅仅是特定類型的平台。我們還希望支援最多數量的平台版本。

以 Android 為例:根據 statcounter,截至 2020 年 6 月,市面上的 Android 版本如下所示:

從數字來看,Android KitKat (Android 4.x) 的市場佔有率不到 2%。絕大多數 Android 設備 (54%) 正在運行 Android Pie (Android 9.0) 或 Android 10。支援每個版本的 Android 都需要投資。您知道我們為何要投資於像 KitKat 這樣市場佔有率低於 2% 的平台嗎?

答案很簡單:淨數字。由於超過 10 億台 Android 設備沒有運行 Android Pi 或更高版本,我們希望確保 Flutter 尽可能广泛地得到使用。我們還希望支援多元的全球使用者群。而且,由於 Android 和 iOS 的舊版本經常被開發中國家的使用者使用,我們希望在尽可能長的時間內避免停止支援舊版本。

透過 Flutter 的核心引擎、框架和 Plugin 中的工作,Flutter 為作業系統平台和作業系統版本的各種問題提供了抽象。例如,Material 應用程式可以在舊版本的 iOS 或 Android 上運行,而无需進行任何修改。事實上,開發人員已發佈在與第一個版本同時推出的硬體上運行的商業 Material 應用程式,而使用這些設備附帶的 Widget 集,則無法在這些設備上執行 。Plugin 也有類似的案例。Plugin 會抽象化平台和版本差異,讓您可以專注於重要的部分:您的應用程式。

Flutter 如何支援如此多的目標

Flutter 為多目標支援帶來了兩大優勢。首先,Flutter 對底層作業系統的依賴性很小。Flutter 的引擎直接與圖形 API 互動,Plugin 為其他功能提供了大部分的設備特定實作。

我們的持續整合 (CI) 系統會為 macOS、Linux 和 Windows 建立 Flutter 及其工具,並部署到一系列 Android 和 iOS 設備(實體設備和模擬設備)。部分 CI 是使用 Google 辦公室中的實驗室進行的;其他 CI 測試是在 Firebase 測試實驗室 上進行的,這是 Google 為 Google 和第三方開發人員運營的雲端託管測試解決方案。

以下是一張我們測試實驗室中其中一個機架的照片:

我們在設備實驗室中運行相對低端的行動設備,因為我們會在那裡進行 效能測試。在測試時,我們希望從代表大多數使用者擁有的設備中獲取效能指標。這樣做可以讓我們獲得最糟糕的情況、真實世界的效能。這種理念也適用於核心工程團隊使用的設備。核心工程團隊的大部分成員並沒有在最新的 Google Pixel 或 Apple iPhone 上進行 Flutter 除錯。

由於我們想要測試許多類型的行動設備,因此我們會保留一個設備庫,核心工程團隊的成員可以在其中檢出特定設備以進行測試和除錯。(在新冠肺炎疫情期間,我們充分利用了美國郵政服務!)

由於實驗室只能測試少數幾種設備類型和版本,我們如何確保我們正在提供我們聲稱提供的支援?請繼續閱讀以瞭解。

對平台版本支援做出一般性斷言

首先也是最重要的是,我們會針對每個程式碼提交在各種平台上進行測試。

在我們目前的實驗室中,我們正在以下 Android 平台上進行測試:

  • Android API 24 (Android N)
  • Android API 28 (Android P)
  • Android API 29 (Android 10)

這涵蓋了已部署 Android 版本市場的 57%;稍後,我們會說明如何透過使用 Firebase 測試實驗室來涵蓋剩餘的設備。

我們的實驗室還會針對每個提交在運行以下作業系統的設備上測試 iOS:

  • iOS 9.3.6
  • iOS 12.4
  • iOS 12.4.1
  • iOS 13.1.3
  • iOS 13.2

最後,對於桌面和網頁,我們會針對每個提交在以下設備上進行測試:

  • Chrome 84
  • Firefox 72.0
  • Catalina 上的 Safari
  • Edge 1.2.0.0
  • Windows 10
  • macOS El Capitan
  • Debian 10

很明顯,Android 方面需要進行更多測試。我們依賴於 Firebase 測試實驗室 完成這項工作,測試以下額外的 Android 和 iOS 組態:

  • Android API 19 (Android K)
  • Android API 21 和 22 (Android L)
  • Android API 23 (Android M)
  • Android API 26 和 27 (Android O)
  • Android API 30 (Android 11)
  • iOS 11
  • iOS 13.0
  • iOS 13.1
  • iOS 13.3–13.7
  • iOS 14

總體而言,我們對 Android 和 iOS 平台的測試涵蓋了目前發佈版本中的 95% 以上。

對於其他作業系統版本,我們透過 您的 支援,也就是 Flutter 開發社群,提供向後相容性。這對特定的設備/作業系統組合尤其適用。你們中許多人使用我們無法使用到的設備:可能是因為你們的作業系統版本我們沒有,或是因為這些設備在美國無法取得。在某些情況下,我們可以減輕這種情況。例如,我們可以在一些 Google Pixel 硬體上刷入較舊的 Android 版本,購買較舊的翻新 iOS 設備,或在模擬器中運行 Android 版本。在許多情況下,你們中的一個人提交的報告會觸發我們對特定平台問題的調查。

這對許多 Android 設備的原始設備製造商 (OEM) 尤其適用。OEM 通常會對 Android 的某些方面進行自訂,例如鍵盤支援。過去,由於你們的幫助,我們能夠修復許多僅在某些市場的某些設備上發生的文字輸入問題。

我們感謝您的幫助,因為我們不可能自己找到所有問題,但我們會努力降低注入問題的風險。在進行程式碼更改時,我們會謹慎行事,並注意作業系統的最早版本支援哪些功能。在需要支援不連貫的組態時,我們會提供選項。這就是為什麼您可以使用 OpenGL 或 Metal 建立 iOS 應用程式,Flutter 會在運行時自動選擇其中之一。

由於這些原因,儘管我們會盡力支援作業系統版本上的測試,但我們支援的一些設備是基於「盡力而為」的基礎支援的。我們會嘗試撰寫支援我們聲稱支援的平台的程式碼,我們會依賴團隊對設備多樣性的隨機使用承諾,然後會尋求社群的回饋,以了解我們在實際使用中表現如何。

我們需要您幫助測試屬於「盡力而為」類別的設備。此類別中有數萬(甚至更多!)個 SKU。我們會盡可能地進行測試,有時候我們會從拍賣網站取得較舊的設備,以方便我們測試和修復在無法複製問題時通報的設備問題。如果您發現特定設備的問題,請在 GitHub 上提交問題。

最後,一些平台,例如 iOS 7,已被棄用。也許它們可以正常工作,但我們不會在已被棄用的平台上進行測試,也不提供任何保證。但是,如果我們可以在修補程式生效後測試時充分支援這些平台,我們會根據具體情況考慮針對已被棄用的平台的修補程式。

Flutter 會維護一個 網頁,列出我們會在其中進行測試的設備以及我們會尋求社群幫助的設備。

決定停止支援

儘管我們致力於在尽可能長的時間內支援每個平台版本,但支援舊平台(或平台組態,例如 Apple A7 上的 OpenGL)需要付出代價,並且會遵循我們上游合作夥伴(包括 Skia)的指南。Flutter 的核心工程團隊規模相對較小,我們會不斷做出權衡,以確保我們所做的事情對使用者來說最有利。在某些時候,工程方面、CI 實驗室中測試的頻寬以及隨機測試的頻寬,以及技術限制(例如作業系統供應商停止支援平台版本中的工具)的成本可能會讓繼續支援目標平台變得困難或不可能。

在我們決定停止支援之前,我們會考慮以下一些問題:

  • 這將會減少我們開發人員的多少終端使用者?
  • 這對 Flutter 開發人員有何影響?是否有主要合作夥伴的業務運營會受到重大影響?
  • 我們可能會節省多少工程成本?例如,透過支援多個作業系統版本,使用 Flutter 建立的應用程式數量是否會增加?(例如,在 iOS 版本中支援 OpenGL 和 Metal 就是這樣的案例。)
  • 這個決定是否符合我們廣泛採用和包容性的目標?
  • 停止支援是否是由外部原因引起的,例如平台供應商在其建置工具中停止支援平台版本?如果是,是否有可能減輕這種停止支援的影響?

在評估是否停止支援時,我們會先透過在 GitHub 中開啟一個議題來詢問您的意見,並發布一份相關的 Flutter 設計文件,該文件會提出停止支援的建議,說明我們為何考慮停止支援,以及可能可用的緩解措施。這是一個向社群徵求意見的請求 (RFC);公共設計文件會透過我們的討論清單 ([email protected]) 和我們的 Discord 推廣。

若要開始停止支援,我們會在發佈穩定版本時,作為穩定版本公告的一部分,啟動 RFC 流程。然後,我們會留出時間供公眾發表意見,然後在後續平台版本中減少對平台或功能的支援。RFC 是您提供回饋的機會。根據我們收到的回饋,我們將繼續停止支援,或對提議進行修改,將平台版本的支援時間延長。我們會認真对待這些前瞻性決定的回饋意见,因為我們認識到我們對您和您的產品使用者負有責任。

徵求意見:停止支援 iOS 8

我們正在考慮停止支援 iOS 8。所有 iOS 8 設備都可以升級到 iOS 9。根據 Google 和第三方分析,運行 iOS 8 的設備數量非常少(一些報告顯示「0.0%」),而 Apple 正在逐步停止支援其工具中的 iOS 8。

我們已發布了 有關停止支援 iOS 8 的徵求意見請求,我們請求您審閱並參與討論。我們的目的是使 Flutter 1.22(我們最新的穩定版本)成為最後一個支援 iOS 8 的穩定版本。RFC 包含理由以及如果您受到影響,該如何操作。

徵求意見:停止支援 Android Jelly Bean

我們正在考慮停止支援 Android Jelly Bean,因為我們不再在實驗室中測試運行該版本的 Android 設備,而為實驗室取得可靠的設備也越來越困難。目前運行 Android Jelly Bean 的設備約佔 Android 使用者群體的 0.46%。

我們已發布了 有關停止支援 Android Jelly Bean 的徵求意見請求,我們請求您審閱並參與討論。我們的目的是使 Flutter 1.22(我們最新的穩定版本)成為最後一個支援 Android Jelly Bean 的穩定版本。RFC 包含理由以及如果您受到影響,該如何操作。

您可以如何幫助

最簡單的幫助方式是參與!我們感謝您提交有關我們尚未遇到的各種設備的邊緣案例的問題。在許多情況下,這些問題出現在我們從未擁有的硬體上,即使我們將硬體測試的支出增加一倍或四倍。報告這些問題,並提供可重現的情況和有關軟體版本和硬體型號的詳細資訊,對我們追蹤問題的根源至關重要。

此外,我們希望您在需要減少對特定平台的支援時,參與決策過程。當我們考慮 Flutter 的未來時,您的見解非常寶貴。請在您看到 RFC 時參與我們公開的 RFC。您是您特定市場的專家,也是離您的客戶最近的人。

我們非常感謝您對我們使用者和讓我們成為您產品一部分的信任。我們仍然致力於幫助您將您的願景呈現在尽可能多的螢幕上。


大規模提供作業系統相容性 最初發佈在 Flutter 上的 Medium,人們在那裡透過突出顯示和回應這個故事來繼續討論。

\n

【文章翻譯】Updates on Flutter Testing

【文章內容使用 Gemini 1.5 Pro 自動產生】

更新整合測試,支援行動端的 Firebase Test Lab;同時也支援網頁和桌面端的獨立支援!

Flutter 的目標是提供一個開放的框架,用於在多個平台上快速構建精美的原生應用程式。實現這個目標的很大一部分是能夠輕鬆地測試您的 Flutter 應用程式,以確保它們按您的意願工作,並在您所針對的平台上以您想要的方式呈現。一些測試可以透過使用 內建於 Dart 的單元測試框架 編寫的單元測試來處理。Dart 單元測試對於非 UI 測試非常有效;它在您的開發機器上執行,並且不依賴於 Flutter 應用程式的 GUI。

整合測試(也稱為端到端測試或 GUI 測試)比單元測試更進一步,因為整合測試嘗試透過按下按鈕、選擇項目和在鍵盤上輸入等方式模擬使用者與您的應用程式互動。這種測試是自動的,以避免讓人類做這種重複性的工作,因為坦白說,我們不擅長這種事情。我們最初避免人類互動的解決方案是一種編寫 Flutter 測試的特殊方式。這些測試從主機執行,就像 Dart 單元測試一樣,並驅動在真實或虛擬設備上運行的應用程式,就像一個人一樣。這些測試稱為 Flutter 驅動測試,因為您使用 flutter_driver 套件和 flutter drive 命令列來驅動應用程式的 GUI。

不幸的是,Flutter 驅動測試存在一些問題。一個問題是測試從開發機器執行並與設備上的應用程式通訊,這意味著測試不適合在像 Firebase Test Lab 這樣的設備池上執行。另一個問題是,為您的測試單獨使用一個程序會讓您很難檢查應用程式的狀態。您可以檢查輸出,但是您如何知道,例如,應用程式的內部狀態。最後,flutter_driver API 比它需要的要複雜,特別是在編寫程式碼以找到螢幕上適當的 Widget 來進行測試時。

因此,為了解決這些問題並繼續改進 Flutter 測試體驗,使其涵蓋越來越多目標,我們很高興宣布 integration_test Plugin 的 1.0 版,這是一種更簡單的方式來測試您的 Flutter 應用程式,並且也支援 Firebase Test Lab。

開始使用 integration_test

使用 integration_test Plugin 需要兩個步驟。首先,將 Plugin 添加到您的 pubspec.yaml 檔案中,作為開發相依,並使用 flutter pub get 將 plugin 拉到您的專案中:

1
2
3
4
5
6
7
# pubspec.yaml

dev_dependencies:
flutter_test:
sdk: flutter
integration_test: ^1.0.0

然後,在測試程式碼中使用 integration_test 套件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import 'package:my_app/main.dart' as app;

void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();

group('end-to-end', () {
testWidgets('Counter increments smoke test', (WidgetTester tester) async {
// Build our app and trigger a frame.
app.main();
await tester.pumpAndSettle();

// Verify that our counter starts at 0.
expect(find.text('0'), findsOneWidget);

// Tap the '+' icon and trigger a frame.
await tester.tap(find.byIcon(Icons.add));
await tester.pumpAndSettle();

// Verify the counter increments by 1.
expect(find.text('1'), findsOneWidget);
});
});
}

請注意 integration_test 套件的匯入和對 IntegrationTestWidgetsFlutterBinding.ensureInitialized() 的呼叫,這將確保套件正確初始化。還要注意標準 WidgetTester 測試程式碼。這是在 flutter create 期間由預設的 Counter 應用程式範本生成的相同測試程式碼。

雖然 integration_test 使您的測試能夠以獨立的方式捆绑到您的應用程式中(這是像 Firebase Test Lab 這樣的設備池的要求),但它需要一些我們將在下面介紹的構建技巧。但是,在測試開發過程中,能夠透過命令列互動式執行您的測試非常方便,为此,您需要一個新的入口點:

1
2
3
4
5
6
import 'package:integration_test/integration_test.dart';

void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
integrationDriver();
}

integrationDriver 的呼叫是 integrationDriver Plugin 的便捷包裝函數,使您能夠使用 flutter drive 命令執行新的測試:

1
2
3
$ flutter drive 
--driver=test_driver/integration_test.dart
--target=test/widget_integration_test.dart

此命令會將您的應用程式部署到模擬器,執行您的測試,並向您顯示結果。

Flutter integration_test in action

此特定測試在 iOS 上執行,但 integration_test Plugin 也適用於 Android,只需更改 --device-id 選項,就像適用於其他平台一樣。此外,您也可以針對網頁和桌面目標執行整合測試,但此功能仍處於預發佈階段。

在 Firebase Test Lab 上執行

當您知道測試可以使用虛擬或實體硬體在本地執行後,就可以將應用程式在 Firebase Test Lab 提供的大量設備上執行。

Firebase Test Lab console

Firebase Test Lab 是一個基於雲端的應用程式測試基礎設施。透過一項操作,您可以在各種設備和設備配置上測試您的 Android 或 iOS 應用程式,並在 Firebase 主控台中查看結果 - 包括日誌、影片和螢幕截圖。integration_test Plugin 的一大進步是能夠在 Firebase Test Lab 上執行針對 Android 和 iOS 的 Flutter 應用程式,讓您能夠在發佈應用程式之前,在數百台設備上同時測試,以查找平台、外觀因素或設備特定的問題。

若要在 Firebase Test Lab 上執行測試,您需要進行一些配置,並使用 Gradle 命令為 Android 和 iOS 構建測試工具,這取決於您選擇的平台。有關這些詳細資訊,請查看 flutter.dev 上最新的整合測試文件

從 Flutter 驅動測試遷移

對於使用現有的 flutter_driver 測試的使用者,遷移到新的 API 並不困難。除了前面提到的適當初始化之外,您還需要遷移到新的 WidgetTester API。

flutter_driver API (left) vs. WidgetTesting API (right)

flutter_driver API(左邊顯示)和 WidgetTester API(右邊顯示)在概念上非常相似,但您可以看到許多細節是不同的。例如,您不是在 flutter_driver 上呼叫 waitFor 方法,而是在 WidgetTester 上呼叫 pumpAndSettle 方法。前者等待特定 Widget 出現,後者等待應用程式 UI 渲染階段穩定。獲得特定 Widget 後,您可以使用兩個 API 類似地對其進行操作,但您使用的是不同的物件。WidgetTest API 更符合您在 Dart 單元測試中看到的內容。如您所見,expect 方法用於確保 Widget 的內容符合您的預期。

有關如何將測試从 flutter_driver 遷移到 integration_test 和 WidgetTester 的詳細資訊,請查看 flutter.dev 上的遷移文件

原生 UI 測試

如果您有一個現有的 Android 或 iOS 應用程式,您使用 Add-to-App 為其添加 Flutter,那麼您可能已經為這些原生應用程式有了現有的整合測試,您想要利用這些測試。在這種情況下,將 Flutter 螢幕的測試添加到這些現有的測試中。對於 Android,如果您使用 Espresso 框架編寫測試,可以使用 espresso Plugin,它為 Espresso 對 Flutter Android 應用程式的測試提供了綁定。我們很快就會有類似的 Plugin 來支援使用 Earl Grey 建立的原生 iOS 測試。

總結

本公告介紹了使用適用於 Flutter 的新 integration_test Plugin 的整合測試的新基礎。不僅 API 更簡單,而且更一致,使用 integration_test 編寫的測試可以使用 Firebase Test Lab 在數百台不同的設備上執行。Flutter 團隊計劃透過將 flutter create 範本來使用 integration_test 作為預設值,更新測試輸出以支援使用 JUnit 格式的現有測試工具,添加在測試期間為黃金測試比較截取螢幕截圖的功能等等,來進一步發展這個新基礎。有關針對 Flutter 應用程式和 Plugin 的整合測試新建議的完整詳細資訊,請查看 flutter.dev 上的測試文件


Flutter 測試更新 最初發佈在 Flutter 上的 Medium,人們在那裡透過突出顯示和回應這個故事來繼續討論。

【文章翻譯】Why nullable types?

【文章內容使用 Gemini 1.5 Pro 自動翻譯產生】

為什麼要使用可空類型?

幾週前,我們宣布了 Dart 空安全測試版,這是一項主要的生產力功能,旨在幫助您避免空錯誤。說到空值,在 /r/dart_lang subreddit 中,一位使用者最近問道

但是為什麼我們仍然擁有/想要空值?為什麼不完全擺脫它呢?我目前也在玩 Rust,它根本沒有空值。所以似乎沒有它也能活下去。

我喜歡這個問題。為什麼完全擺脫空值?本文是我在該討論串中回答內容的擴展版本。

簡短的答案是,是的,完全有可能在沒有空值的情況下生存,像 Rust 這樣的語言就是這樣做的。但是程式設計師確實會使用空值,所以在我們可以將其移除之前,我們需要了解為什麼要使用它。當我們在確實擁有它的語言中使用它時,空值通常什麼?

事實證明,空值通常用於表示值的缺失,這非常有用。有些人沒有中間名。有些郵寄地址沒有公寓號碼。有些怪物在你殺死它們時不會掉落任何寶藏。

在這種情況下,我們想要一種表達方式:「這個變數可以具有 X 類型的值,或者它可能根本沒有值。」那麼問題是如何建模呢?

一種選擇是說一個變數可以包含預期類型的值,或者它可以包含魔術值 null。如果我們在值為 null 時嘗試使用它,就會出現執行時錯誤。這就是 Dart 在空安全之前所做的,SQL 所做的,Java 對非基本類型所做的,以及 C# 對類類型所做的。

但是執行時失敗很糟糕。這意味著我們的使用者會遇到這個錯誤。我們程式設計師寧願在他們遇到之前就發現這些錯誤。事實上,如果我們能夠在我們執行程式之前就發現錯誤,我們會很高興。那麼我們如何以類型系統理解的方式對值的缺失進行建模呢?換句話說,我們如何給「可能缺失」的值和「肯定存在」的值不同的靜態類型?

主要有兩種解決方案:

  1. 使用選項或 maybe 類型
  2. 使用可空類型

解決方案 1:選項類型

這就是 ML 和大多數源自 ML 的函數式語言(包括 Rust、Scala 和 Swift)所做的。當我們知道我們肯定會有一個值時,我們只使用底層類型。如果我們寫 int,則表示「這裡肯定有一個整數」。

為了表示一個可能缺失的值,我們將底層類型包裝在一個 選項類型 中。所以 Option<int> 表示一個值,它可能是一個整數,也可能什麼都不是。它就像一個可以包含零個或一個項目的集合類型。

從類型系統的角度來看,intOption<int> 之間沒有直接關係。將它們視為不同的類型意味著我們不能意外地將可能缺失的 Option<int> 傳遞給預期接收真實 int 的東西。我們也不能意外地嘗試使用 Option<int> 好像它是一個整數一樣,因為它不支援任何這些操作。我們不能對 Option<int> 執行算術運算,就像我們不能對 List<int> 執行算術運算一樣。

要從底層類型的現有值(例如 3)建立選項類型的值,您可以像 Some(3) 一樣構造選項。要在值缺失時建立選項類型,您可以寫類似 None() 的內容。

為了使用儲存在 Option<int> 中的可能缺失的整數,我們必須首先檢查並查看值是否存在。如果存在,我們可以從選項中提取整數並使用它,就像從集合中讀取值一樣。具有選項類型的語言通常也具有良好的 模式匹配 語法,這為我們提供了一種優雅的方式來檢查值是否存在,如果存在則使用它。

解決方案 2:可空類型

另一種選擇 (heh) 是 Kotlin、TypeScript 和現在的 Dart 所做的。可空類型聯集類型 的一種特殊情況。

(題外話:這裡的命名非常令人困惑。選項類型——ML 和它的朋友們上面所做的——是 代數資料類型 的一種特殊情況。代數資料類型的另一個名稱是「區分聯集」。但是,儘管名稱中有「聯集」,但「區分聯集」與「聯集類型」卻大不相同。正如 Phil Karlton 所說,電腦科學中只有兩個難題:快取失效和命名。)

與選項類型方法類似,我們使用底層類型來表示一個肯定存在的值。所以 int 仍然表示我們絕對有一個整數。如果我們想要一個可能缺失的整數,我們可以使用 int? 可空類型。這個小小的問號是 int | Null 之類的聯集類型的語法糖。

就像選項類型一樣,可空類型不支援與底層類型相同的操作。類型系統不允許我們嘗試對可空 int 執行算術運算,因為這是不安全的。同樣,我們不能將可空整數傳遞給需要實際整數的東西。

然而,類型系統比選項類型更靈活一些。類型系統理解聯集類型是其分支的超類型。換句話說,intint? 的子類型。這意味著我們可以將肯定存在的整數傳遞給預期接收可能存在的整數的東西,因為這樣做是安全的。這是一個向上轉換,就像我們可以將 String 傳遞給接收 Object 的函數一樣。Dart 只禁止我們反過來——從可空到不可空——因為那將是一個向下轉換,而這些可能會失敗。

當我們有一個可空類型的值,並且我們想要查看是否存在實際值或 null 時,我們會像在 C 或 Java 中自然地那樣以命令式方式檢查該值:

1
2
3
4
5
foo(int? i) {
if (i != null) {
print(i + 1);
}
}

然後,語言使用 流程分析 來確定程式的哪些部分受到這些檢查的保護。分析確定只有在變數不為 null 時才能到達程式碼,因此在這些區域內,類型系統會將變數的類型收緊為不可空。因此,在這裡,它將 i 視為在 if 語句內具有 int 類型。

語言應該採取哪種解決方案?

因此,當我們 Dart 團隊決定讓語言以更安全的方式處理 null 時,我們應該如何選擇解決方案 1 或 2?我們可以從觀察我們的使用者開始。他們想要如何編寫檢查缺失值的程式碼?在函數式語言中,模式匹配是主要的控制流程結構之一,那裡的使用者對它非常熟悉。使用選項類型和模式匹配在這種風格中是很自然的。

在源自 C 的命令式語言中,像我之前的範例這樣的程式碼是檢查 null 的慣用方法。使用流程分析和可空類型使熟悉的程式碼能夠正確安全地工作。事實上,在 Dart 中,我們發現大多數現有程式碼在新類型系統下已經是靜態空安全的,因為新的流程分析可以正確地分析已經編寫的程式碼。

(這在某種程度上並不令人驚訝。大多數程式碼在處理 null 方面已經是動態正確的。如果沒有,它會一直崩潰。大部分工作只是使類型系統足夠聰明,以便看到該程式碼已經正確,從而使用者的注意力集中在少數不正確的部分。)

因此,如果我們的目標是最大限度地提高熟悉度和使用者舒適度(這語言設計中的重要標準),我們應該遵循我們語言的控制流程結構為我們設定的路徑。

表示缺失和存在

有一種更深層次的方法來處理這個問題,基於選項類型和可空類型的表示方式之間的差異。這種表示方式的差異迫使我們做出一些關鍵的取捨,而這些取捨可能會使我們傾向於某個方向。

在第一種方法中,選項類型的值具有與底層值不同的執行時表示。假設我們在 Dart 中選擇了選項類型,您建立了一個選項類型,然後將其向上轉換為 Object

1
2
3
var optionalInt = Some(3);
Object obj = optionalInt;
print(obj is int); // false

請注意最後一行。Option<int> 值,即使存在,也不像底層類型的值。Some(3)3 是不同的、可區分的