title: 翻桌吧!Flutter for Desktop
date: 2019-05-20
categories: Flutter
keywords:
 
  
自從 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-desktop-embedding\example\,從 pubspec.yaml 內可以看到執行環境需要 Flutter SDK 1.5.9-pre.270 以上版本。 
  
如果沒有修改,在下載 packages 時也會提醒。

如果版本太低可透過指令 flutter upgrade 來升級 SDK 版本,透過 flutter --version 可以查看目前的版本資訊,筆者目前版本為 1.6.1-pre.41。
 
  
開啟範例程式的 README.md(flutter-desktop-embedding\example\README.md) 可以知道還需要新增一個環境變數 ENABLE_FLUTTER_DESKTOP,並將值設為 true。
{% codeblock README.md lang:md %}
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:
export ENABLE_FLUTTER_DESKTOP=true
On Windows:
PowerShell:
$env:ENABLE_FLUTTER_DESKTOP="true"
CMD:
set ENABLE_FLUTTER_DESKTOP=true
{% endcodeblock %}
透過指令 flutter devices,可以驗證是否連結成功。 
  
接下來透過開啟終端機並切換到範例程式的路徑 flutter-desktop-embedding\example,最後透過指令 flutter run 來執行,效果如下:
開啟 main.dart 可以看到其實與原本我們自己建立的專案幾乎一樣,比較明顯的是在呼叫 runApp 之前特別將執行的環境設為 fuchsia。
{% codeblock main.dart lang:dart %}
void main() {
  // See https://github.com/flutter/flutter/wiki/Desktop-shells#target-platform-override
  debugDefaultTargetPlatformOverride = TargetPlatform.fuchsia;
  runApp(new MyApp());
}
{% endcodeblock %}
這主要是因為目前 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 一樣。
完整程式碼如下:
{% codeblock main.dart lang:dart %}
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
void main() {
  // See https://github.com/flutter/flutter/wiki/Desktop-shells#target-platform-override
  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,
        // See https://github.com/flutter/flutter/wiki/Desktop-shells#fonts
        fontFamily: ‘Roboto’,
      ),
      // home: MyHomePage(title: ‘Flutter Demo Home Page’),
      home: StreamProvider.value(
        initialData: false,
        stream: controller.stream,
        child: RxPage(),
      ),
    );
  }
}
class RxPage extends StatefulWidget {
  @override
  _RxPageState createState() => _RxPageState();
}
class _RxPageState extends State
  @override
  Widget build(BuildContext context) {
    List
    bool isLogin = Provider.of
    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
  @override
  Widget build(BuildContext context) {
    bool isLogin = Provider.of
    return Scaffold(
      body: Container(
        color: isLogin ? Colors.green : Colors.grey,
        alignment: Alignment.center,
        child: MaterialButton(
          child: Text(isLogin ? “登出” : “登入”),
          onPressed: () {
            controller.add(!isLogin);
          },
        ),
      ),
    );
  }
}
{% endcodeblock %}
比起 Flutter for Web 的進度似乎還有點落後,但是我們可以看到 Flutter 移植到其他平台時修改幅度並不大,可以看的出來 Flutter 團隊不只是想讓 Flutter 只是可以在各種平台上執行而已,減少重工降低維護成本在實務應用上更加重要,這不論是對於公司還是個人來說應該都是很大的導入誘因。