前言 自從 Google I/O 公開 Flutter for Web 之後大家便開始瘋狂測試,似乎都忘了它目前只是預覽版本,接下來大家另一個期待便是 Flutter 什麼時候開始支援桌面系統,今天剛好看到一篇令人心動的文章-Flutter for Desktop: Create and Run a Desktop Application ,這篇文章使用的是 Google 之前在 GitHub 上釋出的試驗性專案 flutter-desktop-embedding ,這也意味著目前官方的進度,接下來當然實機測試看看了。
環境 首先我們先下載 flutter-desktop-embedding 專案,可以直接下載壓縮檔或是透過 Git 指令下載。git clone https://github.com/google/flutter-desktop-embedding.git
開啟專案內的 README.md
可以看到各個開發需要的安裝的工具。
You will need developer tools for your platform:
Linux: A recent version of GCC
macOS: The current version of Xcode
Windows: Visual Studio 2017 or 2019, including the “Desktop development with C++” workload.
因為筆者是在 Windows 上所以需要安裝 Visual Studio 2017 以上的版本,特別要注意的是需要安裝 **使用 C++ 的桌面開發(Desktop development with C++)**。
若未安裝 **使用 C++ 的桌面開發(Desktop development with C++)**,執行時會出現找不到 vcvars64.bat 的錯誤。
Flutter SDK 接下來我們開啟專案內的範例程式 flutter-desktop-embedding\example\
,從 pubspec.yaml
內可以看到執行環境需要 Flutter SDK 1.5.9-pre.270 以上版本。
如果沒有修改,在下載 packages 時也會提醒。
如果版本太低可透過指令 flutter upgrade
來升級 SDK 版本,透過 flutter --version
可以查看目前的版本資訊,筆者目前版本為 1.6.1-pre.41 。
環境變數 ENABLE_FLUTTER_DESKTOP 開啟範例程式的 README.md(flutter-desktop-embedding\example\README.md
) 可以知道還需要新增一個環境變數 ENABLE_FLUTTER_DESKTOP
,並將值設為 true
。
README.md 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 ### Enable Desktop Support The desktop support in the `flutter` tool is still highly experimental, and must be enabled with an environment variable. Run the command below in the terminal/console you will be using to build and run the example. On macOS or Linux: 1 export ENABLE_FLUTTER_DESKTOP=true
On Windows: * PowerShell: 1 $env:ENABLE_FLUTTER_DESKTOP="true"
* CMD: 1 set ENABLE_FLUTTER_DESKTOP=true
透過指令 flutter devices
,可以驗證是否連結成功。
執行 接下來透過開啟終端機並切換到範例程式的路徑 flutter-desktop-embedding\example
,最後透過指令 flutter run
來執行,效果如下: 開啟 main.dart
可以看到其實與原本我們自己建立的專案幾乎一樣,比較明顯的是在呼叫 runApp
之前特別將執行的環境設為 fuchsia
。
main.dart 1 2 3 4 5 6 void main() { debugDefaultTargetPlatformOverride = TargetPlatform.fuchsia; runApp(new MyApp()); }
這主要是因為目前 TargetPlatform 只有 android
、fuchsia
、iOS
3種,目前桌面系統均無法識別,為了避免發生錯誤,所以暫時設定為 fuchsia
,這樣也可避免將 Package 與 Android 或 iOS 相關的部分一起打包進來。
範例二 與之前測試 Flutter for Web 時一樣,我們套用上一篇文章 Flutter 當我們黏在一起:Provider 的範例。 我們用開發工具開啟範例專案,筆者是用 Visual Studio Code,並在 pubspec.yaml
內加入 provider
這個 package,儲存後透過 flutter package get
來下載(VS Code 儲存 pubspec.yaml
時會自動執行指令)。 接著將 rx.dart
複製到 lib
資料夾下。 最後將 main.dart
內 MaterialApp 的 home
改為 RxPage 。 在透過指令 flutter run
重新執行,可以看到操作效果與 App 以及 Web 一樣。 完整程式碼如下:
main.dart 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 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 import 'dart:io' show Platform;import 'package:flutter/foundation.dart' show debugDefaultTargetPlatformOverride;import 'package:flutter/material.dart' ;import 'package:provider/provider.dart' ;import 'package:example_flutter/rx.dart' ;final controller = StreamController<bool >();void main() { debugDefaultTargetPlatformOverride = TargetPlatform.fuchsia; runApp(new MyApp()); } class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: 'Flutter Demo' , theme: ThemeData( primarySwatch: Colors.blue, fontFamily: 'Roboto' , ), home: StreamProvider.value( initialData: false , stream: controller.stream, child: RxPage(), ), ); } } class RxPage extends StatefulWidget { @override _RxPageState createState() => _RxPageState(); } class _RxPageState extends State <RxPage > { @override Widget build(BuildContext context) { List <Widget> list = <Widget>[]; bool isLogin = Provider.of<bool >(context); if (isLogin) { list.add(UserAccountsDrawerHeader( accountEmail: Text("jonnyhuang@outlooj.com" ), accountName: Text("Jonny" ), currentAccountPicture: CircleAvatar( child: Text("J" ), ), )); } else { list.add(DrawerHeader( decoration: BoxDecoration( color: Colors.orange, ), child: Text("Guest" ), )); } list.add(ListTile( title: Text(isLogin ? "登出" : "登入" ), trailing: Icon(Icons.exit_to_app), onTap: () { controller.add(!isLogin); }, )); return Scaffold( appBar: AppBar( title: Text('RxDart' ), ), drawer: Drawer( child: ListView( children: list, ), ), body: Page1Page(), ); } } class Page1Page extends StatefulWidget { @override _Page1PageState createState() => _Page1PageState(); } class _Page1PageState extends State <Page1Page > { @override Widget build(BuildContext context) { bool isLogin = Provider.of<bool >(context); return Scaffold( body: Container( color: isLogin ? Colors.green : Colors.grey, alignment: Alignment.center, child: MaterialButton( child: Text(isLogin ? "登出" : "登入" ), onPressed: () { controller.add(!isLogin); }, ), ), ); } }
後記 比起 Flutter for Web 的進度似乎還有點落後,但是我們可以看到 Flutter 移植到其他平台時修改幅度並不大,可以看的出來 Flutter 團隊不只是想讓 Flutter 只是可以在各種平台上執行而已,減少重工降低維護成本在實務應用上更加重要,這不論是對於公司還是個人來說應該都是很大的導入誘因。