實用性 Max,新 Flutter & Dart Agent Skills 深度解析

雖然之前在剛發布那會,我們就在 《Flutter 發布官方 Skills 》 聊過 Flutter 的 Skills,不過經過幾輪測試之後,官方發現之前單純文檔型的 Skills 作用並不明顯,所以後續開始調整策略,增加了「任務導向型」的 Skills,這個調整讓 Skills 的實用性大大提高。

在深入聊這次更新之前,其實 Flutter 官方這套 Skills 本身的生成邏輯就很有意思,它是基於文件驅動,透過文件定時更新 Skills,這樣可以做到在生成文件的時候,Skills 也能保持最新。

Skills 流水線

官方的這些 Skills 基本都不是手寫的,它們有一條自動化生成流水線,核心是 tool/generator

其中對應的設定檔長這樣:

yaml 体验AI代码助手 代码解读复制代码- name: flutter-layout
  description: "..."
  resources:
    - https://docs.flutter.dev/ui/widgets/layout
    - https://docs.flutter.dev/ui/layout
    - ../packages/flutter/lib/src/widgets/layout.md

而 Generator 工具會爬取 resources 裡列出的 URL,然後把文件內容餵給 AI,讓 AI 按照 Skill 規範生成 SKILL.md,然後有三個子命令:

  • generate-skill:首次生成
  • update-skill:基於現有內容 + 新文件更新
  • validate-skill:重新生成並與現有版本對比,用來測試 prompt 穩定性

最後還有一個 dart_skills_lint,會在 presubmit 階段校驗每個 Skill 的格式合規性,校驗項包括:

  • name 欄位必須與目錄名完全一致(最多 64 字元,純小寫字母 + 連字號)
  • description 不超過 1024 字元
  • Markdown 內嵌連結不能使用絕對路徑(保證可攜性)
  • 不能有多層巢狀目錄
  • 支援自訂 Rule 擴充

所以其實在我們日常的 harness 工程裡,本身就可以配置這樣一套 CI 工具,透過我們的需求文件、spec 或者程式碼,自動迭代出每個提交和修改的記錄以及 skills 給專案。

Flutter Skills

這裡主要介紹這次更新的一些有趣的 skills,這次增加的幾個都是很垂直領域的實用性支援。

flutter-fix-layout-issues

主要用來做佈局錯誤自動修復,核心是解決 Flutter 最高頻的佈局報錯,比如 RenderFlex overflowedVertical viewport was given unbounded heightAn InputDecorator cannot have an unbounded width 等。

這個 Skill 的核心思路是「錯誤碼到診斷到對應修復方案的確定性映射」,因為 Flutter 的佈局系統主要是基於 "Constraints go down, Sizes go up, Parent sets position" 這個基礎,所有佈局錯誤都是基於這條規則被違反的表現,所以 Skill 把每種違反場景都寫成明確的 if-else 處理分支:

因為這些錯誤的錯誤訊息是固定的字串,AI 可以直接匹配,所以能夠針對性做到:

「當看到黃黑條紋溢出報錯時,它知道精確的修復步驟,包括熱重載驗證的回饋迴圈」。

flutter-add-widget-test

新增 Widget 測試,用 WidgetTester 寫元件級 UI 測試,驗證渲染、tap、scroll、文字輸入等互動行為。

這個 Skill 其實並不複雜,但是它把測試流程細化成了明確步驟的決策流程,並且對每種互動場景都給了明確的 API 選擇指引:

甚至還幫你區分了用 pump() 還是 pumpAndSettle(),Skill 把這些決策顯式化了,也就是 AI 寫出的測試程式碼,可以基於明確依據,同時 SKILL.md 裡附帶了一個完整的 TodoList 增刪測試範例,展示了像遇到 Dismissible 滑動刪除這種複雜互動該怎麼測試。

這在 AI 場景下,做回歸測試還是很實用的。

flutter-add-integration-test

這個技能主要做整合測試,特別是配置 Flutter Driver,並把 MCP 工具的互動 action 轉化為持久化的整合測試程式碼。

這個技能最有趣的是先探索,後固化,流程大概是:

  • 探索階段(透過 MCP 互動):
    • launch_app 啟動應用,取得 DTD URI
    • get_widget_tree 掃描 widget 樹,找出可用的 Key、Text、Type
    • tapenter_textscroll 模擬使用者操作,驗證互動路徑可行
  • 固化階段(生成靜態測試):
    • 把探索過程中驗證通過的操作序列翻譯成 integration_test/ 裡的 testWidgets 程式碼

所以它主要解決了 AI 對你的專案每次都是從 0 探索的問題,把能固化的東西固化成程式碼,這樣後續測試流程裡可以更加穩定,也節省 token。

這個 Skill 還有一些非常細節的處理:

  • 懶載入 widget 找不到的問題: 明確指出如果 get_widget_tree 找不到目標 widget,可能是因為它在 SliverList/ListView 裡還沒被掛載,應該先 scroll/scrollIntoView
  • PumpAndSettleTimedOutException 回饋迴圈裡明確標註,遇到這個錯誤要檢查是否有無限動畫

其實這才是 AI 輔助測試的正確姿勢,不是讓 AI 盲猜 UI 結構,而是先用 MCP 工具「看」到真實的 app,再把所見轉化為測試程式碼。

flutter-build-responsive-layout

這個也很實用,核心是用 LayoutBuilderMediaQueryExpanded/Flexible 組合構建適配不同螢幕尺寸的佈局。

這個 Skill 最核心的作用是修正了 Flutter 響應式開發中最常見的幾個反模式,透過明確「不要做什麼」規則來減少效能損失,比如:

  • 不要用 MediaQuery.orientationOfOrientationBuilder 來切換佈局,因為裝置方向不等於可用空間(摺疊螢幕、分割畫面、畫中畫)
  • 不要檢測硬體類型(手機 vs 平板),Flutter 執行在可調整大小的視窗裡
  • 不要鎖定螢幕方向,因為在摺疊裝置上會導致 letterboxing(黑邊)

同時給出正向教學:

  • LayoutBuilder + constraints.maxWidth 做斷點判斷
  • 大螢幕上用 ConstrainedBox(constraints: BoxConstraints(maxWidth: 800)) 防止內容過度拉伸
  • 清單用 GridView.builder + SliverGridDelegateWithMaxCrossAxisExtent 自動根據寬度調整欄數

實際上這些規則很難透過 Flutter 基礎文件直接讓 AI 理解,而這個技能就可以很好讓 AI 在適配時避開這些問題。

flutter-setup-localization

這是國際化多語言設定,用來配置 flutter_localizations + intl,實現 .arb 多語言支援。

因為 Flutter 的 i18n 涉及多個協同步驟,而 Skill 把這個步驟做成了嚴格有序的檢查清單:

  • flutter pub add flutter_localizations --sdk=flutter + flutter pub add intl:any
  • pubspec.yaml 裡加 flutter: generate: true
  • 根目錄建立 l10n.yaml 設定檔
  • MaterialApp 注入 localizationsDelegatessupportedLocales

進階部分還涵蓋了容易出錯的高級 ARB 語法:

  • Placeholders(參數插值): "hello": "Hello {userName}"
  • Plurals(複數形式): {count, plural, =0{...} =1{...} other{...}}
  • Selects(條件選擇,如性別): {gender, select, male{he} female{she} other{they}}

這些語法在 AI 生成時很容易寫錯,例如漏掉 other 分支會導致執行期崩潰,所以這個技能可以很好支援多語言生成的穩定性。


flutter-implement-json-serialization

JSON 序列化這個不用多說了,這一直是大家吐槽的點,這個技能用 dart:convert 手動實現 fromJson/toJson,不依賴程式碼生成。

在這裡官方設定了一些型別安全原則:

  • jsonDecode() 回傳 dynamic,必須立即 cast 為 Map<String, dynamic>
  • 使用 Dart 3 的 pattern matching 來做 fromJson,型別不匹配時直接丟出 FormatException,而不是回傳 null
dart 体验AI代码助手 代码解读复制代码factory User.fromJson(Map<String, dynamic> json) {
  return switch (json) {
    {'id': int id, 'name': String name, 'email': String email} =>
      User(id: id, name: name, email: email),
    _ => throw const FormatException('Failed to load User.'),
  };
}

另外還有大 payload 的背景解析

  • 如果解析時間 > 16ms,用 compute() 把解析函式轉移到背景 isolate
  • 傳給 compute() 的函式必須是頂層函式或靜態方法,不能是閉包或實例方法(跨 isolate 限制)

這些也是 AI 生成 JSON 程式碼時的常見漏誤。

flutter-add-widget-preview

這是一個使用 Flutter 3.38+ 的 Widget Previewer,實現給 UI 元件添加即時預覽的技能。

這個技能主要添加核心限制:

  • Previewer 執行在 Web 環境,不能用 dart:iodart:ffi 或原生外掛
  • 資源路徑必須用 package-based 路徑(packages/my_pkg/assets/img.png
  • 預覽註解的 callback 參數必須是 public const

比如 @Preview 註解的使用方式:

dart 体验AI代码助手 代码解读复制代码@Preview(name: 'My Sample Text', group: 'Typography')
Widget mySampleText() => const Text('Hello, World!');

進階:MultiPreview:一個註解自動生成多個預覽實例(比如同時生成亮色/暗色主題預覽):

dart 体验AI代码助手 代码解读复制代码final class MultiBrightnessPreview extends MultiPreview {
  @override
  List<Preview> get previews => [
    Preview(brightness: Brightness.light),
    Preview(brightness: Brightness.dark),
  ];
}

這個 Skill 的意義主要是可以讓 AI 在幫你寫 UI 元件時,同步給元件掛上預覽註解,也是一個實用的支援場景。

Dart Skills

而這次 Dart 本身也更新了一批實用 Skill,比如純文件解釋也實用了不少。

dart-fix-runtime-errors

比如 dart-fix-runtime-errors,實際上是靜態分析錯誤的系統修復工作流,涵蓋型別系統、Null Safety、錯誤處理三個維度:

問題錯誤做法正確做法子類參數型別縮窄參數型別(Mouse 替代 Animal)用 covariant 關鍵字動態列表賦值final list = [](推導為 List<dynamic>final list = <int>[]非空欄位初始化欄位不初始化直接宣告加 late 關鍵字延遲初始化捕獲錯誤catch (Error e)永遠不要 catch Error,那是程式設計 bug然後依賴回饋迴圈來修正 Dart 的一些錯誤:

dart-use-pattern-matching

這是一個讓 Dart 程式直接實用 Dart 3 新特性的技能說明,在適當場景使用 switch 表達式和模式匹配替代傳統 if-else 鏈,這也是 Dart Skills 裡目前技術含量最高的一個,在 Pattern 選擇策略裡有:

場景推薦 Pattern驗證並解構 JSONMap + List pattern處理多返回值Record pattern代數資料型別(sealed class)Object pattern數值範圍匹配Relational + Logical-and pattern多 case 共享邏輯Logical-or pattern忽略特定值Wildcard _Switch 表達式 vs Switch 語句的選擇:

  • 產出一個值:用 switch expressionswitch (v) { pattern => expr }
  • 執行副作用:用 switch statementswitch (v) { case p: stmts; }

例如實用 sealed class 窮舉性檢查:

Dart 体验AI代码助手 代码解读复制代码sealed class Shape {}
class Square implements Shape { final double length; ... }
class Circle implements Shape { final double radius; ... }

// 編譯器保證窮舉——漏掉任何子類都是編譯錯誤
double calculateArea(Shape shape) => switch (shape) {
  Square(length: var l) => l * l,
  Circle(:var radius)   => math.pi * radius * radius,
};

dart-migrate-to-checks-package

這個技能也算是實用性技能,主要把 package:matcherexpect() 斷言遷移到 package:checkscheck() 風格。

為什麼要遷移?因為 package:checks 提供了更貼近自然語言的鏈式 API,並且錯誤訊息更豐富:

dart 体验AI代码助手 代码解读复制代码// 舊風格(matcher)
expect(someList.length, 1);
expect(someString, startsWith('a'));

// 新風格(checks)
check(someList).length.equals(1);
check(someString).startsWith('a');

比如非同步斷言的語法差異:

dart 体验AI代码助手 代码解读复制代码// Future
await check(Future.value(10)).completes((it) => it.equals(10));

// Stream(需要 StreamQueue)
await check(stdout).emitsThrough((it) => it.equals('Ready'));

另外這個 Skill 還明確了讓 AI 優先使用 MCP 工具(run_testsanalyze_files)而不是 shell 命令。

最後

可以看到這次更新的 Skills 實用性提高了不少,每個 Skill 都不是在描述一個功能或者說明一個文件,而是在提供決策邏輯,讓 AI 不需要多想,而是透過明確指令來解決問題

另外回饋迴圈(Feedback Loop)也很重要,很多 Skill 的工作流末尾都有顯式的回饋迴圈:

也就是每個技能的結果都需要做檢驗,而不是執行完了之後讓使用者自己判斷,比起單純的文件,這次 Skills 的方向明顯更加實用,這也是之前我們聊過 《compose_skill 和 android skills》 的對比:

相較於官方 android skills 的泛化性支援,第三方使用者提供的這個 compose_skill 實用性強了不少,因為它帶了大量明確的實踐判斷和針對性產出,在提高專案效能和專案合理性上更有幫助。

所以 Skills 現在更多不應該只是「告訴 AI 這個 API 怎麼用、用什麼」,而是更需要告訴 AI「在什麼情況下用哪種方式,遇到什麼問題怎麼修,如何驗證結果」。

所以,現在你可以把這兩個 Skills 用起來,因為它們現在確實能提供不錯的生產力。

連結

github.com/flutter/ski…

github.com/dart-lang/s…


原文出處:https://juejin.cn/post/7637046499474538559


精選技術文章翻譯,幫助開發者持續吸收新知。

共有 0 則留言


精選技術文章翻譯,幫助開發者持續吸收新知。
🏆 本月排行榜
🥇
站長阿川
📝12   💬4   ❤️1
464
🥈
alicec
📝1   ❤️2
87
#4
我愛JS
💬1  
3
評分標準:發文×10 + 留言×3 + 獲讚×5 + 點讚×1 + 瀏覽數÷10
本數據每小時更新一次
📢 贊助商廣告 · 我要刊登