Google 的 Flutter 團隊目前為 Android Studio(基於 IntelliJ-IDEA)和 Visual Studio Code(VS Code)建立和維護支援。我們在這些 IDE 的插件中整合了 Flutter 應用程式開發功能,例如程式碼完成、語法高亮、Widget 編輯輔助、運行和除錯支援等等。自 Flutter 最初推出以來,Flutter 開發人員一直使用這兩種 IDE,Android Studio 傳統上比 VS Code 更受歡迎。如以下圖所示,VS Code 的普及速度比 Android Studio 快,最近在 Flutter 開發中也超越了 Android Studio 的普及程度。
除了 Flutter 開發人員在 2022 年初在 Android Studio 和 VS Code 之間的比例為 50:50 之外,我們還根據之前的調查對開發人員的選擇有了更多了解。
Flutter 開發人員傾向於使用他們熟悉的 IDE
在 2019 年第三季,我們詢問 Flutter 開發人員為什麼他們最喜歡他們使用的 IDE。最常見的選擇是 IDE 對他們來說「更熟悉」。
圖 2. 根據 2019 年第三季的調查結果,80% 的 Android Studio 使用者和 61% 的 VS Code 使用者表示,他們選擇 IDE 是因為熟悉度。
VS Code 使用者重視他們在 IDE 中體驗的速度
上述圖表(圖 2)的另一個值得注意的地方是,68% 的 VS Code 使用者選擇 IDE 是因為它比其他 IDE 快,而只有 12% 的 Android Studio 使用者這麼認為。在一個開放式問題中,VS Code 使用者表示他們喜歡 IDE,因為它輕量級但有很多擴展。
VS Code 使用者對 Flutter 的 IDE 支援感到更滿意
我們還詢問了對 Flutter 的 IDE 支援的滿意度,VS Code 使用者往往更滿意。(當開發人員從 IDE 中打開調查時,我們會記錄他們使用的 IDE。當開發人員點擊調查連結時,我們會通知他們有關此記錄。)
圖 3. 93.3% 的 VS Code 使用者對 Flutter 的 IDE 支援感到滿意,而只有 85.9% 的 Android Studio 使用者感到滿意。
當然,Android Studio 是專門為 Android 開發而設計的完全整合 IDE,因此它在這個目的上具備更豐富的功能集。開發人員表示,在 Android Studio 中處理原生 Android 程式碼和使用重構等便利功能很容易。在下一節中,我們將更深入地探討偏好,以及為什麼開發人員對這些優勢感到不滿意,而沒有在 Android Studio 中使用 Flutter。
我們從 2022 年第二季調查中學到了什麼
上述結果讓我們想知道,為什麼 Flutter 開發人員對 VS Code 的支援比對 Android Studio 的支援更滿意。我們想要了解 Flutter 開發人員真正喜歡 VS Code 的地方。
為了了解這一點,我們向開發人員詢問了一組問題,這些開發人員將他們的首要 IDE 從一個 IDE 切換到另一個 IDE,無論方向如何。我們相信這些開發人員能夠從他們的角度告訴我們每個 IDE 中的獨特價值。
首先,將主 IDE 從 Android Studio 切換到 VS Code 的 Flutter 開發人員更多。
圖 4. 將主 IDE 從 Android Studio(藍色)切換到 VS Code(青綠色)的 Flutter 開發人員比反過來多。
如以下圖表所示,那些切換到 VS Code 的開發人員喜歡它的效能(82%)和可用性(63%)。另一方面,那些切換到 Android Studio 的開發人員喜歡它的功能(51%)、與 Flutter 工具的整合(39%)和原生平台(27%)。
圖 5. 切換到新 IDE 的原因。
儘管如此,約有 23% 的 Flutter 開發人員同時使用 VS Code 和 Android Studio。當我們詢問他們為什麼使用不止一個 IDE 時,出現的最突出的主題是 VS Code 使用者需要使用 Android Studio 和 Xcode 才能實現特定於原生的功能,例如模擬器設定、構建配置、發佈要求(例如金鑰生成和簽署),以及在開發混合 Flutter+原生應用程式時。
該應用程式匯入了 Foundation.h,其中包含 Apple Foundation 函式庫的 API 標頭檔。接下來,在 main 方法內,它從 NSTimeZone 類別調用 systemTimeZone 方法。此方法返回一個 NSTimeZone 實例,其中包含設備上選定的時區。最後,應用程式向控制台輸出兩行,其中包含時區的名稱和以小時為單位的 UTC 偏移量。
final systemTimeZonePointer = dylib.lookupFunction<SystemTimeZoneC, SystemTimeZoneDart>('NSTimeZone_systemTimeZone'); final timezone = systemTimeZonePointer();
final secondsFromGMTPointer = dylib.lookupFunction<SecondsFromGMTC, SecondsFromGMTDart>('NSTimeZone_secondsFromGMT'); final secondsFromGMT = secondsFromGMTPointer(timezone); final hoursFromGMT = secondsFromGMT / 3600;
final getNamePointer = dylib.lookupFunction<GetNameC, GetNameDart>('NSTimeZone_name'); final name = getNamePointer(timezone).toDartString();
final url = Uri.parse('https://example.com/whatsit/create'); final response = await client.get(url); print('Response status: ${response.statusCode}'); print('Response body: ${response.body}');
當您無法使用通用用戶端介面時,您可以使用 cupertino_http 函式庫直接調用 Apple 的網路 API:
1 2 3 4 5 6 7 8
final session = cupertino.cupertinoHttp.NSURLSession.sharedSession();
// Now you can use session to perform network requests such as // dataTaskWithRequest, dataTaskWithURL, etc // For example to get data from a URL: final url = cupertino.cupertinoHttp.NSURL(string: 'www.google.com')!; // Now use the URL to get data or perform any other NSURLSession task.
多平台應用程式中的平台特定網路
當我們設計此功能時,目標仍然是盡可能保持應用程式的多平台性。為了實現此目標,我們保留了用於基本 http 操作的通用多平台 http API 集,並允許為每個平台設定要使用的網路函式庫。您可以透過使用 package:http Client API 來最大限度地減少您需要編寫的平台特定程式碼的數量。此 API 可以為每個平台進行設定,但以平台獨立的方式使用。
Dart 2.18 提供了對兩個支援 package:httpClient API 的平台特定 http 函式庫的實驗性支援:
其次,大多數應用程式開發人員都在完全遷移到空安全的程式碼庫中工作。這一點至關重要。Dart 的完整 可靠空安全 在您遷移所有程式碼和所有依賴項(包括傳遞依賴項)之前不會生效。我們正在透過 flutter run 命令的遙測數據來追蹤這一點。
下圖顯示了 flutter run 的不可靠與可靠空安全執行。在引入空安全之前,兩者都沒有。隨後是不可靠空安全的快速增長。隨著應用程式開始遷移到空安全,開發人員進行了部分遷移。有些部分仍然需要遷移。隨著時間的推移,我們看到可靠空安全會話的健康增長。到上個月底,可靠空安全會話的數量是不可靠空安全會話的四倍。我們希望在接下來的幾個季度中,我們將看到可靠空安全方法達到 100%!
FCGT 包含一些在開發您自己的遊戲時很有用的服務整合:Apple Game Center、Google Play Games 服務、Google 行動廣告 SDK 和應用程式內購套件。這些更進階的整合最初是被停用的,因為它們需要您(開發人員)在使用它們之前進行一些設定。如果您查看遊戲範本的 main.dart 檔案,並向下捲動到第一個「TODO」,您將看到廣告、遊戲服務和應用程式內購 Plugin 的程式碼,處於休眠狀態,等待啟用。
void _musicOnHandler() { if (_settings!.musicOn.value) { // Music got turned on. if (!_settings!.muted.value) { _resumeMusic(); } } else { // Music got turned off. _stopMusic(); _log.severe("Someone is messing with the music!"); throw Exception(); } }