0%

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

在 Google I/O 2024 上推出 Flutter 3.22 和 Dart 3.4

過去幾個月,Dart 和 Flutter 的空中交通管制特別繁忙,但我們很高興宣布 Flutter 3.22 和 Dart 3.4 已於今天順利推出,並可供使用,恰逢今年的 Google I/O

我們始終致力於提供強大的語言和框架配對,讓您能夠從單個共用程式碼庫構建精美、豐富且快速的應用程式,以便您可以將應用程式交付給行動、網頁和桌面上的使用者,而無需分散您的產品路線圖。

Flutter 3.22 和 Dart 3.4 提供了效能改進和平台特定的細化,使我們更接近這個願景。我們特別興奮地分享我們在 Wasm 方面的旅程,但您還會發現更多內容,包括改進的 Impeller 渲染引擎、iOS 上更流暢的視覺效果和更低的 CPU 使用率、使用 Android 的預測性返回手勢增強的平台導航、使用 Google Mobile Ads SDK 擴展的變現選項,以及 DevTools 中一個全新的強大深度鏈接驗證器。Dart 開發人員將享受使用 IDE 中的 dart fix 簡化 API 遷移以及用於進階分析的新 DevTools 功能。此外,您現在可以預覽用於 Firebase Dart SDK 的 Vertex AI,將 AI 驅動的功能與強大的安全措施相結合。

今天,我們還將重點介紹頂尖公司如何使用 Flutter 來提高生產力並構建高效能的體驗。我們將重點介紹一些特別令人興奮的功能,這些功能讓我們更接近我們的目標,即在所有平台上提供類似原生的效能,並包括我們對生產力、開發人員體驗和遊戲的投資的最新更新。

如果您想詳細了解版本中包含的所有內容,請查看專門的 FlutterDart 文章。是時候放手一搏了!

Flutter 在行動中

Flutter 開發人員正在忙碌地將大型新應用程式發佈到應用程式商店。讓我們看看其中幾個。

幫助大型企業級應用程式在行動端和網頁端交付

  • 在英國,金融機構 維珍金融 在其行動銀行和信用卡應用程式套件中使用 Flutter,以統一應用程式開發流程,加快變更速度,並提供行業領先的使用者體驗。
  • 美國保險公司 GEICO 最近 分享了 Flutter 如何幫助他們改進 iOS、Android 和網頁上的品牌使用者體驗,減小程式碼庫的大小,並提高開發效率,所有這些都在規模上實現。
  • 環球影城目的地與體驗 發佈了他們好萊塢、大阪和奧蘭多公園的新 Flutter 行動應用程式。觀看下面的影片,了解他們為什麼選擇 Flutter 以及 Flutter 的表現如何。

超越行動端和網頁端

  • Canonical 團隊一直在與 Flutter 合作自 2021 年起 為 Ubuntu 提供 Flutter 生態系統 的支援。在過去的一年中,Canonical 團隊使用 Flutter 從頭開始重建了 Ubuntu 安裝程式。
  • LG 選擇 Flutter 來增強他們的智慧電視作業系統 webOS。Flutter 的效能、生產力和強大的生態系統讓 LG 可以快速開發和部署 webOS 系統應用程式,這些應用程式可以順暢運行。到 2025 年,Flutter 將為全球數千萬台 LG 電視提供系統應用程式。

這些成功案例鼓舞著我們,我們致力於讓 Flutter 變得更好。讓我們深入了解最新的產品更新,展示我們正在做些什麼來讓您能夠構建更加驚豔的應用程式、遊戲和體驗。

WebAssembly:在網頁上追逐原生效能

今天,我們宣布在我們的穩定版本中支援將 Flutter 網頁應用程式 編譯 為 WebAssembly (Wasm)。這是一種用於網頁瀏覽器的令人興奮的新指令格式,它提供了一種可移植的、平台中立的二進制程式碼格式。

我們對 Wasm 的支援是一項深入的、多年來的投資。首先,我們與 Chrome 團隊合作,在 WebAssembly 中為像 Dart 這樣的高級管理語言定義支援,這些語言通常使用垃圾回收。這導致了 WasmGC 提案,該提案現在已成為一個完整的標準,並在 Chrome(Chromium 119 及更高版本)和 Firefox(120 及更高版本)中提供了運行時實施,預計其他瀏覽器供應商將會效仿。接下來,我們添加了一個全新的 Dart 編譯器後端以生成 WasmGC 程式碼,而 Dart 和 Flutter 團隊合作執行編譯後的應用程式程式碼和 Flutter 渲染引擎作為 Wasm 模組,並提供有效的 Wasm 到 Wasm 的互操作性。

那麼最終結果是什麼?我們看到了效能的大幅提高,接近我們在運行機器程式碼的行動和桌面設備上的效能。在我們的內部基準測試中(在 M1 MacBook 上使用 Chrome),Wonderous 的畫面渲染時間在一般情況下提高了 2 倍,在 99% 的最差情況效能下提高了 3 倍。改進的渲染效能對於具有動畫和豐富轉場的需要大量資源的應用程式至關重要,在這些應用程式中,超出畫面預算(分配給渲染下一畫面的時間)會導致非常明顯的卡頓。Wasm 可能會消除這種卡頓,如下圖所示,Wonderous 應用程式使用傳統的 JS 編譯和 Wasm 編譯進行比較。

比較Wonderous 範例應用程式中 Javascript 和 Wasm 的渲染速度。

Flutter 網頁應用程式的 Wasm 編譯今天在穩定版本中可用。若要開始使用,請查看我們的 Dart Wasm 文檔Flutter Wasm 文檔

Dart macros:提高開發抽象級別

我們致力於提供一流的開發人員體驗。這意味著要解決 Dart 開發人員長期存在的痛點,例如序列化 JSON 資料。

這是一種普遍的模式,既簡單又乏味。目前的解決方案意味著要麼手動地完成編碼和解碼樣板,要麼在程式碼生成解決方案(例如 JsonSerializable 套件)的形式中添加額外的工具。

今天,我們宣布了一個用於 JSON 的更好選項的預覽版本:JsonCodable macro。

macros 是創建更多程式碼的程式碼。它們就像程式碼生成,只是 macro 系統 內建於 Dart 中 並在您編輯和運行程式碼時 實時發生。這是一種整合的體驗,沒有延遲,完全支援我們現有的開發工作流程,例如熱重載,如這個螢幕截圖所示:

螢幕截圖展示了使用 macro 的體驗:最初沒有 `toJson` 程式碼完成,但在為類別添加 `@JsonCodable` 之後,`toJson` 程式碼完成立即顯示。

我們很興奮地看到 macros 為我們的開發人員解決各種問題。例如,資料類別,是 票數最高的 Dart 語言功能。除了特定應用之外,我們的最終目標是在 Dart 中擁有一個 macro 系統,允許使用者創建自己的 macros 並提高 Dart 程式設計的抽象級別。

設計和實作這樣一個強大的 macro 系統是一項巨大的任務,因此目前沒有設定穩定版本的時間 - 有關更多詳細資訊,請查看 Dart 3.4 文章。同時,今天就嘗試一下 JsonCodable macro 的預覽版本。有關更多資訊,請查看 macros 文檔

Flutter 遊戲開發的新資源

我們在遊戲方面的早期投資取得了令人鼓舞的成果,包括來自行業領導者(如 EtermaxSupercell)的成功案例,他們都在利用 Flutter 的功能和靈活性來有效地提供愉悅的使用者體驗並擴展其覆蓋範圍。

今天,我們很興奮地使用這些 Flutter 遊戲開發人員的新資源來延續這種勢頭:

賦能可持續的遊戲開發

在 2024 年 1 月,在受到他們使用 Flutter 的 故事 的啟發下,我們與全球公民合作,挑戰我們的社群使用 Flutter 設計、構建和發佈可持續性遊戲。這些遊戲旨在激勵和賦能玩家,讓他們為環境採取一些微不足道但有意義的行動。今天,我們宣布 10 位獲獎者

恭喜所有獲獎者!

更多探索

今天我們只有時間重點介紹這些內容,但還有許多其他我們沒有涉及的令人興奮的改進。以下是一些需要注意的其他事項:

  • 您可以 預覽用於 Firebase Dart SDK 的 Vertex AI,在 Dart 或 Flutter 應用程式中使用 Gemini API 來實現 AI 驅動的功能。SDK 與 Firebase 應用程式檢查相結合,保護您的 API 調用,並保護您的後端基礎架構免受嚴重的威脅,例如計費欺詐、釣魚和應用程式偽造。有關詳細資訊,請查看我們的 AI 頁面
  • Impeller,我們的 下一代渲染引擎,現在在 Android 上功能齊全。
  • Android 的預測性返回手勢 現在支援在 Flutter 應用程式中導航時,以及導航到其他應用程式或主畫面時。
  • iOS 上的 平台視圖 已進行效能優化,將 CPU 使用率降低了高達 50%。
  • Google Mobile Ads SDK 已擴展以支援更多廣告合作夥伴和調解選項。
  • DevTools 有一個新的 深度鏈接驗證器,它可以幫助您識別和解決 Android 深度鏈接配置中的錯誤,以便您可以更輕鬆地將網頁體驗與 Flutter 應用程式連接起來。
  • dart fix,我們的 API 遷移工具,現在可以直接從 IDE 中調用。
  • DevTools 現在支援時間線上進階篩選和 CPU 樣本。

前往 Flutter 技術文章Dart 3.4 文章 獲取有關這些內容以及更多內容的更多詳細資訊。

與往常一樣,我們非常感謝您的持續支援、熱情、熱忱和回饋。沒有您,這個專案是不可能實現的,我們迫不及待地想看看您將如何繼續推動 Flutter 向前發展。

Flutter 完畢。我們希望很快再見到您!


在 Google I/O 2024 上推出 Flutter 3.22 和 Dart 3.4 最初發佈在 Flutter 上的 Medium,人們在那裡透過突出顯示和回應這個故事來繼續討論。

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

使用 Flutter 開發跨平台應用程式 - Google Classroom 如何讓教師和學生步調一致

Google Classroom 應用程式最初於 2014 年推出,如今全球有 1.5 億教師和學生使用它來組織作業、成績和課堂通訊。該應用程式可在 Android 和 iOS 上使用,開發工作始於當年早些時候,並經歷了兩個行動平台的巨變時代。事實證明,管理這些分歧的變化帶來了挑戰。

儘管努力同步,但在 2021 年,也就是 7 年後,Classroom 應用程式的 Android 和 iOS 程式碼庫在功能、UI 和實作方面逐漸出現分歧。從最明顯的地方,例如屏幕對相同 UI 採取不同方法,到不太明顯的地方,例如驗證和應用程式啟動邏輯的差異;Classroom 逐漸變成一個難以維護和改進的應用程式,兩個程式碼庫給一個小型開發人員團隊帶來了沉重的負擔。

有許多選項可供選擇,從堅持現狀,到增加更多開發人員,再到使用跨平台框架完全重寫兩個程式碼庫。該團隊致力於改進,這排除了堅持現狀的選項,然後評估穩定兩個現有程式碼庫需要做些什麼,這排除了僅添加更多開發人員的方案。最終,團隊選擇了第三個方案:使用單一來源、跨平台的解決方案重新構想 Classroom,而這個方案最終是 Flutter。

Flutter 如何簡化 Classroom 應用程式

不一致的 UI

Classroom 最明顯的問題 - UI 變異 - 強迫教師熟悉 Android 和 iOS 的 UI。畢竟,很容易想像學生會問關於作業屏幕和說明的問題,而一個平台上的說明在另一個平台上對於學生來說可能毫無意義。

傳統方法是由不同的團隊開發的獨立的客戶端應用程式,這些應用程式會隨著時間推移而出現分歧。只有對每個功能進行一致而艱苦的同步工作才能阻止這種情況。相比之下,Flutter 的本質顛覆了這種預設結果。使用 Flutter,UI 預設情況下是相同的 [1],直到主動工作(通常為了適應性)迫使它們為了使用者利益而出現分歧。

[1] 在 Classroom 的 Flutter 客戶端中,保留了一些細微的故意差異,例如系統欄和底部控制項。Flutter 保留了這些平台特有的細節,同時將屏幕中央 90% 的區域留給單個 UI 實作來填充。

混亂的業務邏輯

Classroom 的 Android 和 iOS 客戶端之間存在著差異,這不僅僅是 UI 的問題。受伺服器端解決方案的影響,該方案將一些複雜的業務邏輯轉移到客戶端,舊版的 Classroom 應用程式還處理核心實作方面的差異。除了造成偶爾的平台特定錯誤(這可能會讓工程師難以重現!)之外,這還給任何評估兩種實作正確性的人都帶來了相當大的認知負擔。

使用 Flutter 重寫 Classroom 解決了一系列錯誤,包括先前報告的和未報告的錯誤,這純粹是 Flutter 如何處理原生平台互動的結果。

在原始程式碼中,多年的持續開發偶爾會模糊 UI、業務和平台特定邏輯之間的界限。這意味著使用者的錯誤報告幾乎總是需要付出巨大的努力才能隔離,因為整個呼叫堆疊都可能存在問題。是否由於檔案系統讀取錯誤、業務邏輯通信錯誤,或者由於 UI 接收了檔案但隨後遺失了檔案而導致請求的檔案無法載入?唯一的解決方法是 調查所有內容

當然,Flutter 開發人員可以像其他人一樣混淆這些界限並混合邏輯,但 Classroom 工程團隊發現,遵循框架最佳實務使這種嘗試變得十分明顯。Flutter 的聲明式 UI 系統強烈建議不要將業務邏輯意外放置在 UI Widget 中,而新的 MVVM 架構甚至有助於在位於 Flutter Widget 背後的龐大程式碼庫中強制執行明確的責任層級。

Flutter 應用程式仍然會定期與底層平台進行通信 - 畢竟,上傳和查看作業的使用者旅程離不開檔案系統 - 但 Flutter 將平台特定邏輯隔離到專用 Plugin 的模式再次阻止了例行磁碟 I/O 偷偷溜進不應該出現的地方。以下範例展示了 Flutter 應用程式在不混淆整個呼叫堆疊的情況下存取檔案系統的一種實際方式。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import "dart:io";
import "package:path/path.dart" as path;
import "package:path_provider/path_provider.dart" as path_provider;

// 載入學生為特定作業儲存的作業。
// 回傳值的 exists() 函式會在學生將作業交給狗狗吃掉的情況下返回 False。
Future<File> getHomework(Assignment assignment) async {
// 使用 `path_provider` 套件將平台特定的檔案系統怪癖抽象化
final Directory homeworkDirectory =
await path_provider.getApplicationSupportDirectory();

// 提取學生上傳的作業
return File(
path.join([homeworkDirectory.absolute.path, assignment.name]),
);
}

這個範例很簡單,Classroom 工程團隊最終開發了他們自己的幾個 Plugin,以包含更複雜的與主機平台的互動。有趣的是,這麼做讓他們的原生程式碼 更容易除錯,比他們最初的原生應用程式更容易。這是怎麼做到的呢?在 Flutter Plugin 中遵循「不要重複自己 (DRY)」原則意味著將儘可能多的業務邏輯提升到 Dart 程式碼中,只為原生互動保留最簡單的進出方法呼叫。這會強制在領域邏輯和平台邏輯之間建立堅如磐石的分隔;這意味著 Classroom 的 Android 或 iOS 程式碼中的任何錯誤都可能出現在隔離的單一責任函式中,這些函式很容易進行推理。

效能消耗

當使用者旅程失敗時,就會提交一個具體的錯誤,所有人都同意需要解決。但對於更微妙的問題,例如應用程式啟動時間隨著時間推移越來越慢,自應用程式推出以來每年都在惡化,該怎麼辦?再加上對保持多個客戶端同步的擔憂,突然之間,對應用程式啟動流程的緩慢進行故障排除感覺就像一項無望的任務。

在這裡,Flutter 通過自身速度足够快,不至於加剧问题,更重要的是,它提供了從頭開始的機會。Classroom 團隊知道他們是在建立新的東西,而不是繞過多年開發積累的骨架,他們通過移除冗餘的 API 呼叫,並行化其他獨立的 API 呼叫,以及在所有內容解析完成時顯示閃爍效果和其他 UI 預覽,使他們的授權和啟動流程更加清晰明了。结果是應用程式启动时间惊人地 *减少了 80%*!

注釋功能

Classroom 的大部分功能可以看作是一個相當例行的應用程式,它將使用者圍繞共享內容(如作業和上傳的作業)聚集在一起。但有一個功能顯得 非常棘手。Classroom 的主要功能之一是檔案共享,教師和學生都可以創建、查看和編輯檔案,包括自由形式的注釋,就像在真紙上用筆或記號筆繪畫一樣。這個注釋共享功能已經存在於 Classroom 的原生 Android 和 iOS 客戶端中,因此將其移植到 Flutter 的任何摩擦都會成為阻礙。

Classroom 團隊能夠將這個注釋功能重新打包到一個 Plugin 中,該 Plugin 將平台特定實作委派給單獨的函式庫。對於檔案注釋,這些函式庫成為了 Google One、Google Keep 和舊版 Classroom 應用程式中已經使用的預先存在的原生函式庫的薄薄包裝。在內部,Android 和 iOS 對檔案共享有不同的實作要求。在 iOS 上,Classroom 應用程式通過原生視圖存取檔案,但在 Android 上,它會直接打開 Google Keep 應用程式。但是,良好的 Plugin 設計原則能夠將這些實作細節隔離,同時仍然為應用程式中的其他部分提供一個乾淨的、單一的 Dart API 來進行導航。最終,Classroom 中「最棘手」的功能之一已成功移植到 Flutter。

以下是 Classroom 在 Android 上的注釋功能的可視化,概述了原生和 Flutter UI 組件的混合。

四個並排的行動裝置屏幕,共同展示了選擇和注釋檔案的使用者流程

更籠統地說,典型的 Flutter Plugin 設計看起來像下面這樣,其中一個單一的、簡化的介面載入平台特定的函式庫,這些函式庫反過來又使用 FFI 或 JNI 與底層平台進行通信。這允許 Flutter 應用程式與所有構建目標的平台特定原生 API 互動,而不會將這些考慮因素洩露到 Dart 程式碼中。

Flutter Plugin 設計圖

回顧

開發速度

Classroom 團隊花費了兩年的時間來使用一個團隊重寫他們的應用程式,這個團隊從 1 名工程師(用於最初的原型設計階段)到開發高峰期的 10 名全職工程師不等。這不是一筆小投入,但團隊基於更快開發和維護的承諾做出了這個決定。Classroom 於 2023 年 6 月在 iOS 上推出了他們的 Flutter 重寫版本,並於 2024 年 1 月在 Android 上推出該專案。此後,用於新功能的平均工程師時間減少了三分之二,這意味著開發速度提高了三倍!在等了兩年之後,利益相關者對期待已久的 ✨更快功能開發✨ 感到非常高興。

Classroom 團隊決定重寫的部分原因是,他們知道他們的專案永遠不會「完成」,新的功能很可能會在很長一段時間內不斷添加。這為一個有說服力的案例提供了支持,即重寫,即使是一項昂貴的重寫,最終也會得到回報。Classroom 團隊計算他們使用 Flutter 重寫應用程式後何時才能實現投資回報的公式是:

估算使用 Flutter 重寫應用程式後,提高的速度何時會超過重寫時間的公式。公式為重寫時間除以使用 Flutter 編寫功能所需時間的減少量,等於達到盈虧平衡點的發佈後功能數量。

在 iOS 推出 9 個月後,Classroom 估計已經通過 Flutter 提供的開發速度提高三倍,從而收回了最初投資的 40%。

開發人員體驗

除了利益相關者之外,唯一比開發速度提高更讓 開發人員自己 高興的是 - 開發人員自己。對於 Classroom 團隊來說,他們 3 倍的速度增長來自於僅需編寫一次每個功能(或者至少 1.5 次,在具有大量原生組件的情況下),消除了協調兩個團隊的成本,而這兩個團隊的時間表通常相差數月,當然還有熱重載。熱重載本身及其大約 99% 的重建時間減少,讓 Classroom 團隊的士氣比他們使用兩個原生客戶端時更高。最終,Classroom 團隊發現,在他們轉向 Flutter 之後,很容易吸引和留住工程師。

此外,Classroom 團隊發現,平均來說,新的功能需要減少至少 50% 的程式碼行數才能實現。實際上,減少量可能要高得多,因為他們在重寫過程中建立的每個功能在兩個原生客戶端中都沒有真正實現!換句話說,50% 的程式碼行數實現了所有舊的功能,還覆蓋了 大量 功能缺口(包括 iOS 上的離線支援)。

總結

在開始重寫大約兩年後,Classroom 團隊將他們的應用程式發佈到 Android 和 iOS,並添加了足夠的額外功能,以償還他們前期投資的 40%。他們的全新應用程式啟動速度是舊版本啟動速度的 五倍,為開發人員和最終使用者節省了時間和挫折。展望未來,新的功能平均開發成本是舊狀況的 三分之一,可以在兩個平台上同時發佈,並且 更容易 除錯和維護。最終,在 Classroom 切換到 Flutter 以重新投資他們的 未來 後,使用者、開發人員和利益相關者的士氣達到了前所未有的高度。


使用 Flutter 開發跨平台應用程式 - Google Classroom 如何讓教師和學生步調一致 最初發佈在 Flutter 上的 Medium,人們在那裡透過突出顯示和回應這個故事來繼續討論。

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

優化 Flutter Web 載入速度的最佳實務

身為一名與 Google Flutter 團隊合作,並在私人時間進行個人專案的 Flutter 開發人員,我遇到並理解了關於 Flutter Web 應用程式載入速度的擔憂。優化載入速度對於提升效能和提供良好的使用者體驗至關重要,尤其是在 Flutter 開發人員擴展到 Web 開發時。本指南提供可執行的策略和最佳實務,以加速 Flutter Web 應用程式的效能。

渲染

CanvasKit 是 Flutter Web 應用程式的預設 渲染器,它透過利用 WebGL 在平台間提供高效能和像素完美的一致性。這種功能對於需要豐富動畫和高保真度的複雜圖形應用程式特別有用。然而,CanvasKit 的內建檔案大小(約 1.5 MB)可能是一個缺點,特別是在初始載入時間至關重要的應用程式中。

儘管 flutter.js 載入 API 可並行下載 CanvasKit 和 main.dart.js,但所有 Flutter Widget 都必須等到它們完全載入到瀏覽器中,這可能會在應用程式變得互動之前導致明顯的延遲。為了減輕這些問題並優化載入體驗,開發人員可以選擇 Wasm 渲染模式。

由於 Flutter Web 中的 WebAssembly 支援 被視為實驗性並且可能會發生變化,因此這些步驟適用於願意嘗試尖端功能的開發人員。功能和指令可能會演變,因此請務必參閱最新的 Flutter 文件以瞭解目前的實務。

相容性

當使用 Wasm 進行構建時,dart:html 套件不受支援。此限制意味著您必須仔細考慮您的應用程式相依的 API。或者,web 套件dart2wasmdart2js 支援。

效能

Wasm 不僅與 CanvasKit 相比減少了應用程式大小,而且與 JavaScript 相比,啟動速度也更快。

延遲載入

Dart 的 延遲載入函式庫 允許您分割程式碼,並且只在需要時載入部分程式碼,從而減少初始載入時間。以下部分將討論如何使用延遲載入。

宣告延遲載入

在 Dart 檔案的頂部,宣告您要延遲載入的載入。在載入陳述式中,指定 deferred,後面接著識別符號。當您需要使用函式庫時,請使用延遲載入的 loadLibrary() 方法非同步載入它:

1
2
3
4
5
6
import 'package:myapp/hello.dart' deferred as hello;

Future<void> loadHelloLibrary() async {
await hello.loadLibrary();
hello.sayHi();
}

呼叫載入函數

在您的 Flutter 應用程式中,根據需要呼叫此函數,例如,作為對使用者互動的回應。以下範例在使用者按下 Widget 時載入所需的函式庫:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import 'package:flutter/material.dart';

void main() {
runApp(MaterialApp(home: MyApp()));
}

class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: ElevatedButton(
onPressed: () {
loadHelloLibrary();
},
child: Text('Load Feature'),
),
),
);
}
}

未等待的函數呼叫

為了減少顯示應用程式初始 Widget 所花費的時間,請嘗試在呼叫 runApp 之前不要等待代價高昂的 Future。可以將一些 Future 設為未等待,以便它們在完成後更新 UI。unawaited 函數 允許應用程式程式設計師明確告知「未等待的 Future」提示,這些 Future 不會等待。此改進透過讓應用程式感覺更具回應性,在應用程式啟動和頁面載入期間都增強了使用者體驗。但是,必須小心管理這些函數,以避免與應用程式狀態一致性和資源管理相關的問題。

1
2
3
4
5
6
7
8
9
10
import 'dart:async';
import 'package:flutter/material.dart';

void main() {
unawaited(downloadVideos().then((videos) {
playlist.add(videos);
}));

runApp(const MyApp());
}

媒體檔案

以最佳解析度顯示資產

Flutter 會自動根據設備的像素密度 以適當的解析度載入資產。這可確保在不同螢幕尺寸上顯示最佳視覺效果。雖然優化資產以進行有效傳遞很重要,但請優先考慮在探索替代圖片格式之前提供所需精確解析度的資產,就像我們在下一節中將討論的那樣。

更好的圖片壓縮

PNG 和 JPG 是網站上使用最普遍的圖片格式。這些格式以其廣泛的支援和相容性而聞名。然而,新一代格式(如 WebPAVIF)在減少檔案大小方面取得了重大進展,而不會顯著降低圖片品質。例如,原始大小為 319 KB 的 PNG 圖片可以用 WebP 格式壓縮到僅 38 KB,或者更令人印象深刻的是,可以用 AVIF 格式壓縮到 10 KB。這些檔案大小的縮減是透過肉眼幾乎無法察覺的品質損失來實現的,這證明了這些格式在保持視覺保真度的同時,提升網站載入速度的潛力。

PNG 319 KB / WebP 38 KB / AVIF 10 KB

然而,重要的是要注意,並非所有瀏覽器都支援 WebPAVIF 圖片。在將這些格式整合到您的網站之前,請驗證它們與您的觀眾最常使用的瀏覽器的相容性。這將幫助您確定這些新一代圖片格式是否符合您的網站要求和觀眾需求。

快取

記憶體、磁碟、Service Worker 快取

利用記憶體快取、磁碟快取和 Service Worker 的功能可以顯著減少初始頁面載入後的載入時間。這是因為這些快取機制需要檔案先載入一次,然後才能快取它們。記憶體快取儲存在 RAM 中,提供快速的存取速度,但易失性。另一方面,磁碟快取雖然速度較慢,但提供持久性。Service Worker 作為可程式化的網路代理,可以跨記憶體和磁碟實現複雜的快取策略。

瀏覽器或作業系統通常會自動管理記憶體和磁碟快取,除非有特定的要求需要以程式方式操作它們,否則不需要手動干預。雖然 Flutter 在一定程度上管理 Service Worker,但開發人員可以靈活地在 Flutter 之外實作自訂 Service Worker,以增強對快取和網路互動的控制。

Wasm

瀏覽器會快取 Wasm 檔案(如 CanvasKit,以及很快的 dart2wasm 輸出),以及它們的編譯原生程式碼。這意味著快取的 Wasm 模組載入速度與原生二進制檔案一樣快,與 JavaScript 不同,JavaScript 需要重新解析、重新編譯和重新 JIT(Just-In-Time)處理。

雖然 Flutter 的 Wasm 構建選項尚未完全穩定,但當 dart2wasm 穩定後,採用現代 JS-interop 實務會使您受益。例如,避免使用 dart:htmldart:js 等傳統函式庫,並優先考慮 package:webdart:js_interop。此外,請考慮檢查您正在使用的其他套件是否與 Wasm 相容。

預載入

HTML <head> 標籤、HTTP 響應標頭

預載入資產(如圖片、字體和 JavaScript 檔案)可以顯著提高網頁載入速度。透過在 HTML <head> 標籤中預載入或使用 HTTP 響應標頭,您可以指示瀏覽器在需要用於渲染之前下載這些資源。這樣可以消除延遲,並確保更順暢的使用者體驗。若要預載入資產,請在 <head> 部分添加 <link> 標籤,並將 rel 屬性設定為 preload。僅預載入立即使用的資產,最優化的是應用程式的第一個螢幕,否則瀏覽器會將預載入視為浪費頻寬。

HTML <head> 標籤

1
2
3
4
5
6
7
8
<head>
<link rel="preload" href="assets/logo.webp" as="image" type="image/webp" />
</head>
<body>
<picture>
<source src="assets/logo.webp" type="image/webp" />
</picture>
</body>

Firebase 托管的 HTTP 響應標頭

以下程式碼塊是一個 firebase.json 範例,其中包含一個鍵/值組合,展示如何為資產預載入添加 HTTP 標頭。

1
2
3
4
5
6
"headers": [
{
"key": "Link",
"value": "<assets/logo.webp>; rel=preload; as=image"
}
]

登陸頁面

Flutter 使您能夠使用純粹的 HTML/CSS 為您的應用程式構建完全互動式的登陸頁面。當使用者與您的登陸頁面互動時,flutter.js 會預載入您的 Flutter 應用程式 - 確保使用者導航到 Flutter 應用程式時立即啟動。這對於具有 播放 按鈕的遊戲和需要登入的應用程式特別有用。

載入/啟動畫面

雖然我們一直關注應用程式載入速度的技術優化,但感知載入速度更為關鍵。您的目標應該是讓您的應用程式 感覺很快

載入/啟動畫面在增強這種感知方面非常有效。透過提供視覺活動,它們向使用者保證應用程式正在迅速啟動。相反,空白螢幕會引起不確定性,可能會導致沮喪和頁面重新整理。

為了實現最快的回應能力,請使用純粹的 CSS/HTML 在您的 index.html 檔案中直接實作啟動畫面。這可以最大限度地減少任何潛在的延遲。

例如,請查看 Flutter Gallery 實作

結語

在本文件中,我們探討了加速 Flutter Web 應用程式初始載入和渲染效能的方法。您可以採用多種策略,但請記住,每個解決方案都涉及權衡取捨。選擇最適合您的特定需求和使用者需求的優化。透過結合這些方法، 您可以為您的 Flutter Web 應用程式創造更流暢、更具回應性的使用者體驗。


優化 Flutter Web 載入速度的最佳實務 最初發佈在 Flutter 上的 Medium,人們在那裡透過突出顯示和回應這個故事來繼續討論。

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

Flutter 和 Dart 在 Google Cloud Next 上

如果您錯過了,Flutter 團隊上週首次參加了 Google Cloud Next,這證明了 Flutter 在開發社群中的影響力日益增長。

我們與 Google Cloud、Firebase、Very Good VenturesServerpod 的團隊合作,提供重點關注簡化工作流程的閃電演講、議程和演示攤位。

如果您錯過了,以下回顧了我們分享的內容。

使用 Firestore、Cloud Run 和 Flutter 快速開發

我們實時開發了一個最小可行 Flutter 應用程式,透過 Google Cloud Run 支援的 API 支援 Firestore 資料庫。您可以從這些 資源 了解更多有關如何自己執行此操作的資訊。

利用 Flutter、Firebase 和 Gemini 開發智慧型應用程式

我們使用 Flutter、Firebase 和 Gemini 從頭開始建立了一個動態的真實世界應用程式,現場展示了 Firebase 的 Firestore 和儲存功能如何簡化資料管理和媒體處理。觀看 演講的錄製

如何使用 Serverpod 開發全堆疊 Dart

我們展示了開發人員如何在伺服器上使用 Dart 共用代碼並使用 Serverpod 補充他們的 Flutter 應用程式,Serverpod 是一個全堆疊 Dart 解決方案,它使用代碼生成來建立匹配的客戶端-伺服器代碼以及基於您的架構的豐富功能的 Postgres ORM。查看 這個 Observable Flutter 集 以了解更多資訊。

使用 Firestore 對 Flutter 應用程式進行現場編碼

我們展示了 Google 的 Project IDX 如何讓為 Flutter 設定開發環境變得更加容易!查看 Project IDX 開始使用。

使用 Flutter、Dart Frog 和 Gemini 開發全堆疊應用程式和遊戲

Very Good Ventures (VGV) 展示了如何使用 Gemini 和 Flutter 以「選擇你的冒險」風格建立一個 AI 支援的遊戲。現在就觀看 演講

如何使用 Dart Frog 和 Google Cloud 共用代碼

VGV 展示了如何使用 Dart Frog 在您的前端和後端之間快速建立和運行 代碼共用,啟動一個全堆疊專案,並在幾分鐘內讓它在設備上和 Cloud Run 中運行。

您可能錯過了

查看 Cloud Next 中的這些公告,我們認為這些公告有可能幫助 Flutter 和 Dart 開發人員更輕鬆地在您的應用程式中構建 AI 功能。

Firestore 向量搜尋支援 + 擴展發佈

Firestore 中的向量搜尋嵌入,以及 Firestore 向量搜尋擴展,讓 Flutter 和 Dart 開發人員能夠將 Firestore 資料轉換為豐富的、可搜尋的知識圖,為高度創新的生成式 AI 功能提供支持。當您使用 Firestore 時,這為將 AI 支援的產品推薦、智慧型聊天機器人和其他複雜的體驗直接整合到您的 Flutter 應用程式中打開了大門。

Vertex Gemini Dart SDK 私人預覽

Vertex Gemini SDK 是一組用於 Firebase 的客戶端 SDK,支援 Dart、Kotlin、Swift 和 JavaScript。它們旨在透過輕鬆存取 Vertex AI 服務來加速開發。Flutter 和 Dart 開發人員可以透過此 Google 表單 請求存取私人預覽。

向我們展示您正在構建的內容

對於想要構建由 Google Cloud 支援的高品質跨平台體驗的開發人員來說,未來一片光明,我們想看看您正在構建什麼。如果您將 Flutter 與 Firebase 或任何 Google Cloud 產品或服務結合使用,請在 TwitterLinkedIn 上告訴我們!

如果您只是想開始使用 Flutter 和 Google Cloud,請查看以下資源。

直到下次 😉 - 我們迫不及待想看看您會建立什麼!


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

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

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

Flutter 如何讓畫布渲染的應用程式對輔助技術使用者更友善

Flutter 框架支援的目標平台之一是 Web。Flutter 應用程式透過將所有 UI 渲染到畫布元素上,來保證像素精準度和平台一致性。但是,預設情況下,畫布元素不可存取。本案例研究說明了此類畫布渲染的 Flutter 應用程式如何支援存取性。

Dash, the Flutter mascot, with a tablet and a drink.

Flutter 擁有大量的預設 Widget,這些 Widget 會 自動產生存取性樹。存取性樹是一個存取性物件的樹,輔助技術可以查詢其屬性和特性,並在其上執行操作。對於自訂 Widget,Flutter 的 Semantics 類別允許開發人員描述 Widget 的含義,幫助輔助技術理解 Widget 的內容。

出於效能考量,在撰寫本文時,Flutter 的存取性預設情況下是選擇性啟用的。Flutter 團隊希望最終在 Flutter Web 中預設啟用語義。然而,在目前的狀況下,這會在許多情況下導致顯著的效能成本,並且需要一些優化才能更改預設值。希望始終啟用 Flutter 存取性模式的開發人員可以使用以下程式碼片段:

1
2
3
4
5
6
7
8
import 'package:flutter/semantics.dart';

void main() {
runApp(const MyApp());
if (kIsWeb) {
SemanticsBinding.instance.ensureSemantics();
}
}

注意:如果您的應用程式絕對需要知道使用者是否正在使用螢幕閱讀器等輔助設備,請允許使用者選擇性啟用。

啟用 Flutter 的存取性支援後,HTML 會自動更改,如本頁面的其餘部分所示。

注意: 螢幕閱讀器只是利用所述方法獲益的輔助技術的一個例子。為了提高可讀性,螢幕閱讀器被用作此類技術和其他輔助技術的代表。

Flutter 的存取性選擇性啟用

Flutter 的選擇性啟用機制是一個隱藏的按鈕。它在 HTML 中放置一個按鈕,準確地說,是一個 flt-semantics-placeholder 元素,其 role 等於 “button” - 對有視力的人來說是不可見且不可達的。它是一個自訂元素,已應用樣式,因此它不會顯示,除非您使用螢幕閱讀器,否則不可選取。

1
2
3
4
5
6
7
8
9
10
11
12
<flt-semantics-placeholder
role="button"
aria-live="polite"
aria-label="Enable accessibility"
tabindex="0"
style="
position: absolute;
left: -1px;
top: -1px;
width: 1px;
height: 1px;"
>&lt;/flt-semantics-placeholder&gt;
1
2
3
4
/* `<flt-semantics-placeholder>` inherits from `<flutter-view>`. */
flutter-view {
user-select: none;
}

啟用後的變更

當一個使用螢幕閱讀器的使用者點擊這個按鈕時會發生什麼?考慮一個不太複雜的例子,例如 Flutter Gallery 中的 卡片,如以下螢幕截圖所示。

A classic card component with an image, a heading, and some text.

為了更好地理解使用者點擊按鈕時發生了什麼變化,請比較啟用和未啟用 Chrome DevTools 的螢幕截圖,當您 檢查存取性樹 時。第二張螢幕截圖顯示的語義資訊比第一張多很多。

未啟用:

Chrome DevTools showing an “Enable accessibility” button.

已啟用:

Chrome DevTools showing a rich accessibility tree with headings, buttons, groups, etc.

實作細節

Flutter 的核心思路是建立一個可存取的 DOM 結構,反映目前在畫布上顯示的內容。這包括一個 flt-semantics-host 父自訂元素,它具有 flt-semanticsflt-semantics-container 子元素,而這些子元素又可以巢狀。考慮一個按鈕 Widget,例如 TextButton。此 Widget 在 DOM 中由 flt-semantics 元素表示。flt-semantics 元素上的 ARIA 標註(例如,rolearia-label)和其他 DOM 屬性(tabindex,事件監聽器)允許螢幕閱讀器向使用者宣佈這個元素為按鈕,並支援點擊和點選它,即使它不是一個字面上的

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

全球遊戲挑戰賽:公布 20 強!

在過去 9 週裡,看到數千位開發人員齊心協力,使用 Flutter 和 Dart 為地球開發史詩般的遊戲,令人振奮不已。參賽作品包括 RPG、平台遊戲、AI 驅動遊戲等等。您的創意橫跨大陸、類型、格式、平台,甚至銀河系!

您的創意總是讓我們驚嘆不已,因此我們的 Flutter 評審團在評估來自全球各地的才華橫溢的開發人員、設計師、藝術家和倡導者的數百款遊戲時,面臨著艱難的抉擇。話不多說,以下是 20 強!

重大揭曉!

請敲響鼓聲!以下是晉級決賽的 20 個專案:

接下來呢?

從這裡開始會更加令人興奮!由全球公民、聯合國為計畫聯盟遊戲、Google Play、YouTube 和 Flutter 社群代表組成的最終評審團將選出我們的 10 強決賽。10 強將於 2024 年 5 月宣布。

在此同時,從 4 月 22 日開始,您就可以為您最喜歡的遊戲投票!前往 globalgamers.devpost.com 投票,幫助我們選出社群選擇的冠軍!

感謝您,繼續建設!

我們衷心感謝所有參與者的參與,再次熱烈祝賀我們的 20 強!來自 Google 和全球公民的所有人向您致敬 - 繼續懷抱更大的夢想,繼續編碼,並繼續為我們的地球努力奮鬥,一次一場精彩的遊戲!


全球遊戲挑戰賽:公布 20 強! 最初發佈在 Flutter 上的 Medium,人們在那裡透過突出顯示和回應這個故事來繼續討論。

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

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

Dart 中 JS 互通性的歷史

由於 Dart 3.3 中實現了一個令人興奮的 JavaScript 互通性里程碑,目前 Flutter beta 版已支援 Wasm。為了慶祝,我們將回顧 Dart 和 JS 互通性十年來的旅程。

AI Image generated by Gemini

從 Dart 誕生之初,互通性就一直是核心重點。Dart 於 2011 年首次發佈時,其設計目標是可嵌入跨平台。它可以在獨立虛擬機器上運行、嵌入瀏覽器中,並編譯成 JavaScript。2015 年 Flutter 出現時,我們也準備將其嵌入其中。現在,我們也很高興能以 WasmGC 執行階段為目標

起初,我們迅速地公開了 Dart 嵌入的每個平台的功能。這就是我們的 SDK 平台特定函式庫的起源:dart:io 公開了 VM 上的檔案系統,dart:html 公開了 Web 上的瀏覽器 API,等等。這些函式庫的外觀和感覺就像普通的 Dart 函式庫,但在幕後隱藏了一些複雜的低階原生基元,以使其運作。這是我們發明的第一種互通性形式。它具有表現力,但僅限於 SDK 函式庫。

在 Web 上,開發人員需要的東西不僅僅是瀏覽器 API。因此,我們開始尋找方法來開放互通性以涵蓋更多目標。作為起點,我們在 2013 年引入了 dart:js,以便能夠存取 JavaScript 函式庫。

1
2
3
4
5
6
7
// 簡短的 JavaScript 程式碼範例,用於說明 Dart/JS 互通性
window.myTopLevel = {
field1: 0,
method2() {
return this.field1;
}
}
1
2
3
4
5
6
7
8
9
10
11
// 透過 `dart:js` 存取 (2013)
import 'dart:js' as js;

void main() {
// 這行程式碼有錯字!糟糕 :(
var object = js.context['myTopLevl'];
object['field1'] = 1;
// 這個呼叫失敗,並顯示 noSuchMethod,因為 method2
// 返回一個 int,糟糕
object.callMethod('method2', []).substr(1);
}

那時我們就知道 dart:js 不是我們想要的程式設計模型。您必須使用字串來存取 JavaScript 中的名稱——別想在編譯時發現問題,更別想程式碼完成了!實作的成本也很高。它嚴重依賴於大多數操作的 boxes 和深層副本。因此,我們在 2014 年和 2015 年繼續起草想法,直到 package:js v0.6 發佈。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 透過 `package:js` 存取 (2015)
import 'package:js/js.dart';

// 魔術註釋允許我們宣告 API 簽名:
@JS()
class MyObject {
external int get field1;
external void set field1(int value);
external String method2();
}

@JS()
external MyObject get myTopLevel;

void main() {
// 存取程式碼不易出錯:分析器可以檢查這些符號是否與宣告相符,而且我們還可以進行程式碼完成!
var object = myTopLevel;
object.field1 = 1;
// 但是類型未經檢查,這會在 int 上不正確地調用 substring
object.method2().substring(1);
}

有了 package:js,我們終於有了一個高效且使用者友好的開放 API。您可以在抽象類別上添加一些註釋,然後,您就可以存取 JavaScript API 了。一切都像魔法一樣運作,直到它失效為止。有很多事情您無法使用 package:js 完成:直接存取瀏覽器 API、重新命名成員、轉換、附加 Dart 邏輯等等更多。為了彌補,我們還發佈了 dart:js_util——一個類似於 dart:js 的輕量級且高效的低階 API,作為備份。package:js 中的所有限制都讓我們很困擾,但我們束手無策。我們需要 Dart 語言提供更多功能才能做得更好。

大約在那個時候,我們已經在著手進行我們對該語言做過最大的變更——我們正在讓 Dart 變得可靠。諷刺的是,當我們在 2018 年與 Dart 2.0 一起發佈新的類型系統時,互通性變得更糟了!除了早期的限制之外,package:js 的特殊之處的魔法也有其黑暗面——它無法檢查類型的有效性。這意味著我們的互通性在我們原本可靠的語言中是不穩定的來源。

然後,我們的旅程轉變為專注於協同改進 Dart 和 JS 互通性。憑藉明確的原則(慣用、表達、組合、精確、易於理解、務實、非魔幻且完整),我們朝著一個基於類型和靜態分派的設計方向發展,並挑戰了 Dart 語言。接下來是並行演變。

  • 2019 年,Dart 2.7 加入了靜態擴充方法。您可以將自訂 Dart 邏輯附加到 JS 互通類別,並轉換值,例如將 JS Promise 轉換為 Dart Future,而無需使用包裝器。
  • 2021 年,我們與 package:js v0.6.4 一起發佈了 @staticInterop。終於,JS 互通性具有足夠的表現力——您可以公開以前由 SDK 函式庫(如 dart:html)獨家管理的瀏覽器 API。
  • 2023 年,當我們在 Dart 3.0 中放棄了不穩定的空安全時,我們終於可以看到我們取得的進展,我們的設計和 @staticInterop 的工作清楚地表明我們準備好解決我們長期以來存在的可靠性差距。

那一年,我們引入了編譯到 WasmGC,並利用 JS 互通性在其上運行豐富的框架,例如 Flutter Web。這激發了對 JS 類型 的研究,以在程式設計模型中明確定義 Dart 和 JS 的邊界,並找到一種在 Wasm 和 JS 編譯目標中使用 JS 的一致方法。我們還開始了 擴充類型 語言實驗——Dart 3.3 中推出的一項功能,彌合了 Dart 語言和 JS 互通性之間的差距。多年來,JS 互通性具有一些行為,例如類型擦除,這些行為與 Dart 中的其他任何東西都不匹配。有了擴充類型,JS 互通性終於可以變得慣用,並在 Dart 開發工具中獲得應有的支援。

儘管一路走來經歷了許多變化和轉折,但有一件事在整個十年中始終如一:Dart 社群的積極參與。社群成員率先測試和貢獻 dart:js,後來又影響了 package:js 的設計。他們編寫工具來解決功能差距 (package:js_wrapping),並嘗試透過自動生成 Dart API (package:js_facade_genpackage:js_bindingspackage:typings) 來提高生產力。每一項貢獻都使 Dart 的互通性設計變得更好。感謝你們每一個人,讓這成為一次如此激動人心的冒險!

最後,我們來到了 2024 年。我們在 Dart 3.3 中與 package:web 一起發佈了 dart:js_interop,這是 Dart 中最新的 JS 互通性解決方案,使 將 Flutter 編譯為 Wasm 成為可能。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// 透過 `dart:js_interop` 存取 (2024)
import 'dart:js_interop';

// 宣告使用擴充類型,這與 package:js
// 宣告非常相似。主要區別:它們是靜態分派的。
extension type MyObject._(JSObject _) implements JSObject {
external int get field1;
external void set field1(int value);
external String method2();
}

@JS()
external MyObject get myTopLevel;

void main() {
var object = myTopLevel;
object.field1 = 1;
// 最後,存取是可靠的 - 從 method2 返回時,這行程式碼會因類型錯誤而失敗。
object.method2().substring(1);
}
  • dart:js_interop 是一種基於擴充類型的靜態、可靠、慣用、表達且一致的互通性形式,能夠公開任何 JavaScript 或瀏覽器 API。
  • package:web 使用 dart:js_interop 來完成 13 年前 dart:html 所做的事情,但以 JavaScript 和 WasmGC 都支援的方式進行。

今天,我們很高興慶祝 Dart/JS 互通性的一種新形式及其所帶來的未來。了解我們的過去,我們確信這不是旅程的終點,而是我們歷史上一個激動人心的時刻。

我們迫不及待地想看到您用它構建出什麼!


Dart 中 JS 互通性的歷史 最初發佈在 Dart 上的 Medium,人們在那裡透過突出顯示和回應這個故事來繼續討論。

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

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

Flutter 登上 GDC 舞台

去年,Flutter 的休閒遊戲工具包迎來了 重大更新。本週,Flutter 在舊金山舉行的 遊戲開發者大會 (GDC) 上首次亮相,這是遊戲產業最頂尖的專業活動,致力於支持遊戲開發人員及其技能的發展。請继续阅读,了解開發者們在 Flutter 上構建遊戲的進展,以及 Flutter 遊戲開發的未来展望。

Flutter for Games hero image

Flutter 休閒遊戲工具包 發佈以來,Flutter 在遊戲開發領域取得了顯著進展。在過去的 12 個月裡,使用 Flutter 開發了超過 15,000 款新的行動遊戲。

Flutter 已證明是各種規模遊戲應用的吸引人選項,它為首次接觸遊戲開發的新手開發者(例如 Tatsuya,他利用 Flutter 在閒暇時間創造了 Tinies Merge,並在 Google Play 的獨立遊戲節 上入圍前 20 名)以及 Trivia Crack 等熱門遊戲背後的團隊(在全球擁有數億次下載量!)提供了支持。

為什麼選擇 Flutter 開發遊戲?

對於 2D 休閒遊戲,特別是介面驅動型或回合制遊戲,Flutter 提供了令人信服的优势。它是開源軟體,這意味著它消除了授權費,提供了對遊戲機制的深度控制,以及對豐富的插件生態系統的存取。Flutter 的「熱重載」功能加快了開發速度,而其優化的引擎確保了跨設備(包括瀏覽器)的順暢效能。Flutter 能夠一次構建,跨平台部署,包括 iOS、Android、網頁、桌面和 Google Play 遊戲 for PC,簡化了遊戲的覆蓋範圍。因此,如果您是遊戲開發者,不要忽視 Flutter 的潛力——嘗試用 Flutter 開發您的下一款遊戲,並幫助我們傳播這個消息!

2024 年及以後:共同打造 Flutter 遊戲開發生態系統

在 2024 年,我們致力於賦能您使用 Flutter 創造出色的休閒遊戲體驗。我們的重點將放在:

  • 簡化開發: 預計將擴展遊戲開發資源,例如範本、插件整合和深入指南,以加快您的工作流程,並釋放 Flutter 的遊戲開發潛力。
  • 擴展覆蓋範圍: 我們正在努力使 Flutter 遊戲在網頁和其他平台上的部署更加順暢,為您的作品打開新的受眾群體。
  • 為未來奠定基礎: 雖然 2D 行動遊戲支援是我們的首要重點,但我們熱衷於將 3D 功能作為 Flutter GPU 努力的一部分進行探索。您可以查看我們的一些 早期實驗,了解我們的進展。

特別感謝社群

我們對社群的堅定支持和重大貢獻表示衷心的感謝,這些貢獻推動了 Flutter 在遊戲開發領域的非凡發展。

我們對您的工作感到敬畏,並對許多傑出的貢獻表示衷心的感謝,包括:

這個列表只是社群中人才的冰山一角。對於我們無法個別提名的所有人:我們對您的貢獻深表感謝,您使 Flutter 成為一個充滿活力的遊戲開發場所!

同時,我們也向使用 Flutter 發佈遊戲的開發者們表示最衷心的感謝。您的創意和激情激勵著我們不斷突破可能的界限,使 Flutter 成為全球開發者更強大的工具。

Flutter 作為遊戲開發平台的旅程才剛剛開始。我們致力於與社群共同成長,聆聽您的回饋,并構建您所需的工具。

我們迫不及待想看看您會建立什麼!


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

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

Dart 參與 2024 Google 暑期程式碼計畫

Google 暑期程式碼計畫 (GSoC) 的重點是將來自世界各地的學生開發人員帶入開源軟體開發領域。Google 贊助學生在夏季與一個指導開源組織合作進行一個為期 12 週(或更長時間)的程式設計專案。在過去的 19 年裡,已有超過 20,000 名貢獻者參與了 Google 暑期程式碼計畫。

我們很高興地宣布,Dart 專案將在 2024 年 Google 暑期程式碼計畫中指導貢獻者(第五次!)。

您有興趣嗎?

若要立即開始,請閱讀 專案構想列表,以找到與您的技能和興趣相符的專案。正式申請必須在 4 月 2 日之前提交。我們鼓勵潛在的申請者提前提交草稿並徵求回饋。

Dart 團隊預計會有足夠的導師來接受少數申請,因此也請查看 其他指導組織

如果您有關於 Dart 和 GSoC 的具體問題,請在 我們的專用郵件列表 中提問。

若要進一步了解 Google 暑期程式碼計畫,請觀看以下影片或閱讀 Google 暑期程式碼計畫的貢獻者指南

我們期待您的回音!


Dart 參與 2024 Google 暑期程式碼計畫 最初發佈於 Medium 上的 Dart,人們在那裡透過醒目顯示和回應這個故事來繼續討論。

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

Flutter 如何促進 L+R 設計師和開發人員的合作

您可能熟悉 Global Citizen (GC),這是一個致力於消除世界貧困和幫助地球的組織。當 GC 想要重新編寫一個行動應用程式來幫助完成這項工作時,他們聯繫了我們的工作室 L+R,共同設計、開發和同步推出 Android 和 iOS 版本的應用程式。

Flutter 的靈活性、預建 Widget 清單和強大的動畫功能讓 L+R 團隊能夠實施以設計為導向的開發流程。使用 Flutter 時,我們的開發人員擁有一個空白畫布,可以將自訂設計變為現實。對於 L+R 來說,這意味著我們的設計團隊可以釋放他們的創造力,打造以使用者為中心的應用程式,這些應用程式看起來很棒,體驗也很棒。

以下是 Global Citizen 應用程式中的一些螢幕截圖:

設計流程

在開始新的客戶專案時,設計師首先在 Figma 中建立一個設計系統。這包括品牌指南 - 例如調色盤和文字排版 - 以及小的可重複使用元件。

在開始重寫 Global Citizen 應用程式時,設計團隊擴展了現有指南,以提供具有更高對比度元素的新面貌。這不僅有助於引導使用者的注意力,還改善了可訪問性。

UI 元素在 Figma 中被建立為 元件。每個元件可能具有不同的 變體,具體取決於元件類型或狀態。例如,下圖顯示了幾個按鈕變體:

在開發新的元件時,設計團隊參考了 Figma 中的 Material 和 iOS 設計套件以獲取靈感。這有助於將設計轉換為程式碼,因為這些 Figma 元件與 Material 和 Cupertino 函式庫中提供的 Widget 密切相關。

在整個設計過程中,團隊將小的可重複使用元件組合成更大的功能特定元件,然後將這些元件組合成完整的頁面。這使 Global Citizen 的產品團隊能够擴展應用程式,添加新的功能,同時保持與最初愿景的一致性。

專案範本

在 L+R,我們團隊從第一個公開發佈版本開始就一直在使用 Flutter。為了讓我們的團隊快速簡便地構建 Flutter 應用程式,我們建立了一個 開源儲存庫,它作為專案範本,為我們構建的所有 Flutter 應用程式提供了基石。

這個簡潔的專案包含一組可以自訂並用於客戶應用程式的 Widget。例如,Figma 設計檔案中所呈現的按鈕(如上所示)可以使用專案範本中的 _BaseButton 類別構建。此類別接受不同的顏色、文字樣式和內嵌,以最佳匹配為該專案設定的設計系統。

為了讓根據品牌指南輕鬆地為這些元件設定樣式,我們使用 ThemeData 類別。開發人員從 Figma 中取得顏色方案和文字樣式,並將它們對應到相應的主題屬性。

我們的團隊盡可能地利用 ThemeData 中現有的屬性,然後使用 ThemeExtension 功能完成剩餘的設定。

Flutter 的 Widget 函式庫

如上所述,專案範本包含一組可重複使用的 Widget。在開發這些 Widget 時,我們盡可能地使用 Material 和 Cupertino 函式庫中的預先存在的 Widget。在 Global Citizen 應用程式中,大約一半的元件來自 Material 或 Cupertino Widget。

例如,Material 中的 TextFieldTextFormField Widget 包含與設計相符的所有必要的自訂和功能。Material 中的 TextButton 也用於實作 _BaseButton Widget。在這種情況下,我們利用了 TextButton 現有的突出顯示功能,但我們將其包裝到一個具有擴展功能的新 Widget 中,以更好地滿足我們的需求。

擁有這些開箱即用的 UI 元件,可以輕鬆地為其設定樣式,這使得構建和維護我們的 Widget 變得更加容易。但是,有時我們的設計師會創建無法使用 Flutter 的 Material 或 Cupertino Widget 重新建立的自訂元件。在這些情況下,開發團隊會使用低階 Flutter Widget 創建我們自己的自訂 Widget。

Global Citizen 應用程式中的一個範例是進度指示器。對於這個應用程式,我們的設計師創建了一個自訂進度指示器,如以下 GIF 中所示。現有的 Material 和 Cupertino 進度指示器不適用於此設計。但是,我們的開發人員可以輕鬆地使用容器、行和列以及內在動畫創建一個全新的 Widget。

社群函式庫對於更複雜和靈活的元件也非常有用。例如,我們使用社群構建的 flushbarGlobal Citizen 應用程式中顯示警報通知。

熱重載

在將 Figma 設計轉換為 Flutter 程式碼時,設計師和開發人員的合作非常重要。設計師通常會提供回饋,導致樣式、佈局或動畫的微調。熱重載使這種合作變得更加高效。

使用熱重載,開發人員可以在與設計團隊進行螢幕共享時調整程式碼(無論是在 UX 階段、UI 概念階段、前端實施階段,甚至是在設計 QA 階段)。在螢幕共享時,設計師可以立即看到更改的結果。這使得除錯和迭代變得更快。

流暢的動畫

有助於應用程式感覺精緻的一件事是添加周到的動畫。Flutter 的動畫框架靈活而強大,但設計師可能難以理解。對我們團隊有所幫助的一件事是參考開源應用程式中的精美動畫。具體來說,我們查看了 Wonderous 應用程式 的程式碼庫。從那時起,我們利用了為 Wonderous 提供動力的開源函式庫 flutter_animate,為關鍵功能添加了簡單但豐富的動畫。

以下鏈接中的影片突出了「採取行動」流程的一部分,使用者在其中瀏覽一系列信息螢幕以了解有關問題的更多信息。

查看 action_learn_animations 影片。

使用 flutter_animate,我們能夠執行以下操作:

  • 在使用者向前移動時為步驟指示器製作動畫
  • 在頁面之間添加輕微的淡入淡出轉場
  • 在觀看影片後將「播放影片」按鈕轉換為成功勾號

總的來說,Flutter 允許設計和開發使用靈活的方法。Flutter 的預建 Widget 使創建可重複使用、可以設定樣式以匹配客戶品牌形象的 UI 元件變得更加容易。Flutter 社群在技術發展過程中發揮著重要作用,提供高品質的函式庫並擴展可用資源。Flutter 的關鍵功能(如熱重載)支持設計師和開發人員之間更好的協作。所有這些加在一起就會產生一個既美觀又實用的應用程式!

有關應用程式的更多信息,請查看 新 Global Citizen 應用程式:每日行動主義和可衡量的影響力,盡在您的口袋。您也可以 將 Global Citizen 應用程式下載 到您的行動裝置上。

L+R 是一個國際策略、設計和行動技術工作室。我們提供許多服務,例如 UX 設計、行動開發和策略咨詢。


Flutter如何促進L+R設計師和開發人員的合作 最初發佈在 Flutter 上的 Medium,人們在那裡透過突出顯示和回應這個故事來繼續討論。