随着时间的逐渐推移, Flutter 开始了扩张之路

flutter 已经不满足于移动端了,桌面端也有着自己的野心

但无论如何,目前 flutter desktop 还仅仅处于 demo 玩一玩的阶段, 如果谁敢生产项目来一套, 我佩服你是个勇士


官方说明

https://github.com/flutter/flutter/wiki/Desktop-shells

目前完成度最高的是 macOS 的版本,可用度很高, 而且由于同样使用 cocoapod,所以相对来说官方制作 engine 难度应该是最低的

创建项目

现在建议使用官方本身提供的脚手架, 自己创建的话比较麻烦

https://github.com/google/flutter-desktop-embedding 这个库目前托管在 google 下,还没有转给 flutter,也就是说暂时还不能称之为 flutter sdk 的一部分

git clone https://github.com/google/flutter-desktop-embedding

我根据文档创建了一个 sh 脚本,专门用于输出我如果想尝鲜 desktop 版需要的东西, 也就是环境变量了

export FLUTTER_ROOT=$PWD/flutter
echo "使用前复制如下命令\n"

echo "export FLUTTER_ROOT=$FLUTTER_ROOT"
echo "export FLUTTER_HOME=$FLUTTER_ROOT"
echo "export PATH=$FLUTTER_ROOT/bin:$PATH"
echo "export ENABLE_FLUTTER_DESKTOP=true"

echo "\n以上"

20190610151138.png

这里我单独的 clone 了一份 sdk, 跑在了 flutter 的 master 分支上

然后把 flutter 设置环境变量到这个 flutter sdk 上

然后通过如下的方案检查:

which flutter
/Volumes/Evo512/code/flutter_desktop/flutter/bin/flutter

这里就说明我的 flutter 是用的这个 example

当然这个是临时的环境变量,如果你想要真正来开发 flutter_desktop 的应用,则应该将这些环境变量设置在.bash_profile 中

打开项目

$ code flutter-desktop-embedding/example && cd flutter-desktop-embedding/example

20190610151657.png

这里就和平时运行 flutter 不太一样了

稍等片刻就能看到这个 20190610151740.png

20190610151819.png

内存占用并不高

官方建议是本地依赖,但是我尝试了一下,如果是纯粹的 dart 库,是可以直接用的

也就是说没有直接或间接使用过 iOS/android 代码的 pub 库都是可以用的, 比如我写的 oktoast 就可以用 😁 20190610152044.png

当然还有一些其他的库, 有没有用原生库请查看库的代码或文档

控件测试

输入

  1. 可以输入
  2. 选中总体来说还好
  3. 不支持复制粘贴全选
  4. 也不支持快捷键

Kapture 2019-06-10 at 15.50.19.gif

无限滚动

20190610155510.png

帧数也还好, 这个总体表现还算 ok

图片

没测试 memory,但是其他方式的都使用了

asset 的使用方式和移动版相同, 而不是 web 的那种约定式

import 'dart:io';

import 'package:flutter/material.dart';

import 'const/resource.dart';

class ImagePage extends StatefulWidget {
  @override
  _ImagePageState createState() => _ImagePageState();
}

class _ImagePageState extends State<ImagePage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(),
      body: ListView(
        children: <Widget>[
          Container(
            color: Colors.red,
            child: Image.network(
                'https://raw.githubusercontent.com/kikt-blog/image/master/img/20190610151657.png'),
          ),
          Container(
            color: Colors.blue,
            child: Image.file(File('/Users/cai/Desktop/apng_spinfox.png')),
          ),
          Container(
            color: Colors.red,
            child: Image.asset(R.ASSETS_1_PNG),
          ),
        ],
      ),
    );
  }
}

20190610154620.png

库的使用

以本地提供的 file_chooser 为例

修改 yaml

file_chooser:
  path: ../plugins/file_chooser

修改代码

import 'dart:io';

import 'package:file_chooser/file_chooser.dart';

import 'package:flutter/material.dart';

class LocalFilePickerPage extends StatefulWidget {
  @override
  _LocalFilePickerPageState createState() => _LocalFilePickerPageState();
}

class _LocalFilePickerPageState extends State<LocalFilePickerPage> {
  File file;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('测试使用文件选择器'),
      ),
      body: Container(
        child: Text('我选择的文件 : ${file?.path}'),
      ),
      floatingActionButton: FloatingActionButton(
        child: Icon(Icons.attach_file),
        onPressed: () async {
          showOpenPanel((results, path) {
            print('results: $results, path = $path');
          });
        },
      ),
    );
  }
}

查看界面

20190610160611.png

使用的是原生的选择器

结果是这样的

20190610160645.png

results 是是否成功

path 是选择的文件, 这里之所以是数组是因为支持多选, 不过默认关闭而已

粗略分析插件目录

目录结构:

tree
.
├── LICENSE
├── analysis_options.yaml
├── lib
│   ├── file_chooser.dart
│   └── src
│       ├── callbacks.dart
│       ├── channel_controller.dart
│       └── utilities.dart
├── linux
│   ├── Makefile
│   ├── file_chooser_plugin.cc
│   └── file_chooser_plugin.h
├── macos
│   ├── Classes
│   │   ├── FileChooserPlugin.h
│   │   └── FileChooserPlugin.m
│   ├── Flutter
│   │   ├── GeneratedPluginRegistrant.h
│   │   ├── GeneratedPluginRegistrant.m
│   │   └── ephemeral
│   │       └── Flutter-Generated.xcconfig
│   └── file_chooser.podspec
├── pubspec.lock
└── pubspec.yaml

这里没有 window 的选择器,我们使用一个其他的文件夹来查看

tree ../example_plugin
../example_plugin
├── LICENSE
├── lib
│   └── example_plugin.dart
├── linux
│   ├── Makefile
│   ├── example_plugin.cc
│   └── example_plugin.h
├── macos
│   ├── Classes
│   │   ├── ExamplePlugin.h
│   │   └── ExamplePlugin.m
│   └── example_plugin.podspec
├── pubspec.yaml
└── windows
    ├── ExamplePlugin.vcxproj
    ├── ExamplePlugin.vcxproj.filters
    ├── example_plugin.cpp
    ├── example_plugin.h
    └── scripts
        └── cache_flutter.bat

可以看到,如果要做 desktop 的插件,需要开发 linux,macOS 和 windows 的文件

mac 使用.h 和.m, 使用 cocoapod 来组织库文件

linux 使用.h 和.cc, 使用 Make 来构建

windows 使用.h 和.cpp,还有 vsxproj 文件, 这个 vsXXX 似乎是 VS 的文件, 也就是使用 VS 来构建, 当然还有一个.bat 脚本不知道具体作用是什么

当然,还有 lib 下的 dart 文件,作为 dart 的调用入口

创建插件

根据官方说法, 因为目前不支持 flutter create -t 的方式来创建 desktop 插件, 所以请使用 example-plugin 作为起点

查看 https://github.com/google/flutter-desktop-embedding/tree/master/plugins#writing-your-own-plugins

后记

因为还没有 release 版本释出,所以目前为止还没有完整的打包方案, 无法测试 release 版的文件大小,但是内存来看是比较优秀的

补充一下, 之前 flutter web 无法使用的 Icons,在 desktop 中完全没问题

因为我这里只有 mac,其他平台没测试, 可用程度, 暂时未知

代码在这: https://github.com/CaiJingLong/flutter_desktop_example_1

以上