Go Flutter Desktop (一) 初探
文章目录
Flutter 在去年的时候就有一个第三方的桌面引擎, 是用 golang 开发的
Github 地址是:https://github.com/go-flutter-desktop/go-flutter
目前在 mac,linux,windows 均可用, 作为一个 mac 用户, 除了 retina 下字显得有点小, 感觉没有单独适配外, 总体感觉是优于官方的 desktop 引擎的
另外我是真实的 golang 脑残粉, 我觉得 golang 这东西真的太好了, 用 golang, 准不会错
开发环境
需要的开发环境, 因为我是 MacOS, 我以 macOS 为例,其他的请参考对应的系统
- Xcode 命令行体系, 这个东西包含很多开发套件(Git), 无论你是否用 XCode 开发,都建议装一个...
- Flutter 环境和配套工具, 这个跑不掉,作为 flutter 开发者...
- go 语言环境(使用 brew 安装), 1.12+, IDE 用 Jetbrains 家的 goland (你用 VSCode 的话看你自己的情况)
环境安装
对 flutter 桌面版本感兴趣的一定接触过 flutter 开发, 我就默认你有 flutter 全套开发环境
go 语言环境安装
$ brew install go
如果你的 go 比较老, 请升级,使用$ brew upgrade go
配置 GOPATH 环境变量
$ vi ~/.bash_profile
1export GOPATH=~/code/go # 这个是必须配置的, 等号后的部分根据你的情况修改, 简单来说里面放的是你自己的代码,不是go的SDK,不是go的SDK,不是go的SDK, 具体的话是你 go 语言的三方库源码/自己写的go代码/中间产物/应用程序所在的目录
2PATH=$PATH:$GOPATH/bin # 这个是选配, 但是强烈建议配置,不然以后的go工具链需要全路径引用
你下载的 go 相关的东西会被装在这个文件夹里
go-flutter 的环境
需要使用一个叫做 hover 的工具, 这个工具是由 go 编写的, 编译打包运行都使用这个工具
$ go get -u github.com/go-flutter-desktop/hover
, 这样这个工具会被安装到$GOPATH/bin
目录下
当你可以直接在命令行输入 hover 可以出现如下情况时就说明可用了
1➜ ~ hover -h
2Hover helps developers to release Flutter applications on desktop.
3
4Usage:
5 hover [flags]
6 hover [command]
7
8Available Commands:
9 build Build a desktop release
10 help Help about any command
11 init Initialize a flutter project to use go-flutter
12 run Build and start a desktop release, with hot-reload support
13
14Flags:
15 -h, --help help for hover
16
17Use "hover [command] --help" for more information about a command.
18➜ ~
安装 hover 出现问题的话可以参考
运行 example
官方提供了几个 example:
1cd /tmp
2git clone https://github.com/go-flutter-desktop/examples.git flutter-examples
3cd flutter-examples/pointer_demo
4flutter pub get
5hover run
通过以上几个步骤就可以把项目跑起来了
是一个关于鼠标移入移出监听的 demo
将原项目改为 desktop
官方说明文档是这样的, 不想看英文的, 可以跳过官方文档直接看我的中文说明
这里要注意, 因为插件系统的原因, 如果不是纯 dart 插件, 则插件内容不能用
我模拟一下这个过程, 创建一个+++的 helloworld 工程, 你如果是要改造已有项目, 则应该 cd 到你的 flutter 的根目录进行 $ hover init 项目url
的操作, 这里根据官方说, url 无所谓, 后面可改
1flutter create flutter_example_1
2cd flutter_example_1
3flutter pub get
4hover init github.com/Caijinglong/flutter-go-example # 初始化 desktop 工程
这时候运行项目$ hover run
会有一个提示: Target file "lib/main_desktop.dart" not found.
我们查询可知, 可能是考虑到兼容性的问题, go 引擎的项目使用 main_desktop.dart
作为入口, 我们创建一个文件
main_desktop.dart
:
1import 'package:flutter/foundation.dart';
2import 'package:flutter/widgets.dart';
3
4import 'main.dart';
5
6void main() {
7 debugDefaultTargetPlatformOverride = TargetPlatform.fuchsia;
8 runApp(MyApp());
9}
$ hover run
这样项目就跑起来了
测试基础的项目
测试下常用的几项:
- 事件响应
- ListView
- 图片
- 输入框情况
事件响应
点击事件是可行的,数字可加, 说明鼠标事件能响应, 其他的长按双击等等都是 flutter 实现的, 理论上就不需要测试了
最开始的官方 demo 中有鼠标移入移出事件
ListView 滚动
1import 'package:flutter/material.dart';
2
3class ListViewPage extends StatefulWidget {
4 @override
5 _ListViewPageState createState() => _ListViewPageState();
6}
7
8class _ListViewPageState extends State<ListViewPage> {
9 @override
10 Widget build(BuildContext context) {
11 return Scaffold(
12 appBar: AppBar(),
13 body: ListView.builder(
14 itemBuilder: _buildItem,
15 ),
16 );
17 }
18
19 Widget _buildItem(BuildContext context, int index) {
20 return ListTile(
21 title: Text(index.toString()),
22 );
23 }
24}
没有移动端的惯性, 可以响应鼠标滚轮上下
改成横向的
1 Widget build(BuildContext context) {
2 return Scaffold(
3 appBar: AppBar(),
4 body: ListView.builder(
5 itemBuilder: _buildItem,
6 scrollDirection: Axis.horizontal,
7 ),
8 );
9 }
横向同样没惯性, shift+滚动可以横向
图片
网络图片
1import 'package:flutter/material.dart';
2
3class ImagePage extends StatefulWidget {
4 @override
5 _ImagePageState createState() => _ImagePageState();
6}
7
8class _ImagePageState extends State<ImagePage> {
9 @override
10 Widget build(BuildContext context) {
11 return Scaffold(
12 appBar: AppBar(),
13 body: ListView(
14 children: <Widget>[
15 Container(
16 width: 500,
17 height: 500,
18 child: Image.network(
19 "https://raw.githubusercontent.com/kikt-blog/image/master/img/20190704171705.png"),
20 ),
21 ],
22 ),
23 );
24 }
25}
网络图片可行
文件
File 的图片, 直接使用本地图片就可以了, 我因为是 mac,所以是这样的,windows 可能是c:\\XXXX\\XXX\\X.jpg
1Container(
2 width: 500,
3 height: 500,
4 child: Image.file(File("/Users/cai/Desktop/auto-angle.jpg")),
5),
内存
memory , 这里需要模拟一下
读取上面的文件,然后转为 Uint8List
1Container(
2 width: 500,
3 height: 500,
4 child: Image.memory(
5 Uint8List.fromList(
6 File("/Users/cai/Desktop/auto-angle.jpg").readAsBytesSync(),
7 ),
8 ),
9),
资产
asset: 这种方式的加载我印象中去年这个引擎需要使用约定式文件夹, 与 flutter-web 的方式类似
而现在不需要这种方式了, 直接与 flutter 官方的方式一致,只需要在 pubspec.yaml 中配置即可
1flutter:
2 # The following line ensures that the Material Icons font is
3 # included with your application, so that you can use the icons in
4 # the material Icons class.
5 uses-material-design: true
6
7 # To add assets to your application, add an assets section, like this:
8 assets:
9 - assets/
1Container(
2 width: 500,
3 height: 500,
4 child: Image.asset(R.ASSETS_HAVE_EXIF_JPG),
5),
1/// generate by resouce_generator library, shouldn't edit.
2class R {
3 /// ![preview](file:///private/tmp/flutter-go-example/./assets/have-exif.jpg)
4 static const String ASSETS_HAVE_EXIF_JPG = "assets/have-exif.jpg";
5}
这里插入一句, 图片会根据 exif 信息旋转至正确的方向
但是图片多了后 ListView 的滚动性能似乎变差了
输入框
使用 Material 体系的 TextField 作为测试, Cupertino 和 Widget 体系的输入框请自行测试吧
有如下几个测试方向(有其他的需求可说, 我会加入)
- 输入响应
- 显示行为
- 系统快捷键
- 鼠标行为
输入响应
这个很好理解, 就是用键盘能否输入字符... 因为 flutter 上的官方的 plugin 就没法输入(我都是道听途说)
1import 'package:flutter/material.dart';
2
3class InputPage extends StatefulWidget {
4 @override
5 _InputPageState createState() => _InputPageState();
6}
7
8class _InputPageState extends State<InputPage> {
9 @override
10 Widget build(BuildContext context) {
11 return Scaffold(
12 appBar: AppBar(title: Text('input')),
13 body: Container(
14 child: TextField(),
15 ),
16 );
17 }
18}
输入英文还算正常
试试中文:
文字位置正常,输入框没跟随
显示行为
单行没问题, 试试多行, 直接回车不行 我们需要将 TextField 设置为多行, 我这里分别设置 10/50 行
50 行的话,一页放不下,滚动也算正常
但是这里有一个问题, 中英文混合的情况下, 水滴不正常
开头和结尾都是英文则没问题, 都是中文同理
系统快捷键+鼠标行为
常用的几个快捷键(复制,粘贴,全选)都是 OK 的, 基本行为和正常的输入框完全吻合,这里要给好评, 比官方桌面引擎好用多了, 其他系统的请自行测试
鼠标行为顺便一起测试了,基本符合正常的操作习惯
插件
这个版本的插件和官方的不一样, 需要用 golang 去写, 而不是各自平台的, 当然如果各自平台有特殊的 api, 也需要使用 golang 去调用
总体有如下几个步骤:
- 创建插件
- 编写代码(go+dart)
- 引入插件
官方文档在此:
创建并编写插件
go 端
打开 goland, 或者其他的什么编辑器
具体的 golang 知识没法展开讲解,
可以理解为在 gopath 的 src 目录下创建一个包, 大部分情况下模仿别人, 建议放在 github.com 目录下
$ mkdir -p src/github.com/caijinglong/go-flutter-plugin/version
创建一个目录, 这个就是我插件的文件夹
version.go
:
1package version
2
3import (
4 "github.com/go-flutter-desktop/go-flutter"
5 "github.com/go-flutter-desktop/go-flutter/plugin"
6)
7
8const (
9 channelName = "top.kikt/go/version"
10 getVersion = "getVersion"
11)
12
13type VersionPlugin struct{}
14
15var _ flutter.Plugin = &VersionPlugin{}
16
17func (VersionPlugin) InitPlugin(messenger plugin.BinaryMessenger) error {
18 channel := plugin.NewMethodChannel(messenger, channelName, plugin.StandardMethodCodec{})
19 channel.HandleFunc(getVersion, getVersionFunc)
20 return nil;
21}
22
23func getVersionFunc(arguments interface{}) (reply interface{}, err error) {
24 return "0.0.1", nil
25}
这个文件就是我们的插件, 必须要有的是结构体声明, 初始化插件的方法
下面那个getVersionFunc
就是我们处理的方法, 这里可以使用 golang 编程,返回你需要通过 golang 获取的数据或任何东西, 我这里返回了一个简单的字符串
dart 端
1import 'package:flutter/services.dart';
2
3class GetVersionPlugin {
4 static const _channel = const MethodChannel("top.kikt/go/version");
5
6 static Future<String> get version async => _channel.invokeMethod("getVersion");
7}
发布插件
为了让我们的 flutter 应用可以找到这个插件, 需要一些配置
go-flutter 使用的是 go module 的方案管理的 go 包
我们需要如下几步
1cd $GOPATH/src/github.com/caijinglong/go-flutter-plugin/version
2export GO111MODULE=on
3go mod init github.com/caijinglong/go-flutter-plugin/version
4go mod tidy
目前我们的目录结构是这样的
1/Users/cai/code/go/src/github.com/caijinglong/go-flutter-plugin/version
2├── go.mod
3├── go.sum
4└── version.go
要想发布, 其实得发布到 github 上, 这样别人才能访问, 我们目前不这么做, 仅本地使用
引入插件
这里需要修改 desktop/cmd 目录下的 options.go 文件
1package main
2
3import (
4 "github.com/caijinglong/go-flutter-plugin/version"
5 "github.com/go-flutter-desktop/go-flutter"
6)
7
8var options = []flutter.Option{
9 flutter.WindowInitialDimensions(800, 1280),
10 flutter.AddPlugin(version.VersionPlugin{}),
11}
这时候重新运行下项目会报一个错
1build github.com/Caijinglong/flutter-go-example/desktop/cmd: cannot load github.com/caijinglong/go-flutter-plugin/version: cannot find module providing package github.com/caijinglong/go-flutter-plugin/version
这个是因为插件没有发布到 github 所致, 我们先在本地测试下, 需要按照官方文档修改一下
1module github.com/Caijinglong/flutter-go-example/desktop
2
3go 1.12
4
5require (
6 github.com/go-flutter-desktop/go-flutter v0.24.1
7 github.com/pkg/errors v0.8.1
8 .com/stretchr/objx v0.2.0 // indirect
9)
10
11replace github.com/caijinglong/go-flutter-plugin/version => /Users/cai/code/go/src/github.com/caijinglong/go-flutter-plugin/version // 添加这行
接着就可以运行了
运行
代码如下:
1import 'package:flutter/material.dart';
2
3import 'get_version_plugin.dart';
4
5class PluginPage extends StatefulWidget {
6 @override
7 _PluginPageState createState() => _PluginPageState();
8}
9
10class _PluginPageState extends State<PluginPage> {
11 @override
12 Widget build(BuildContext context) {
13 return Scaffold(
14 appBar: AppBar(),
15 body: FutureBuilder<String>(
16 future: GetVersionPlugin.version,
17 builder: (c, snapshot) {
18 if (!snapshot.hasData) {
19 return Container();
20 }
21 return Text(snapshot.data);
22 },
23 ),
24 );
25 }
26}
后记
本章简单使用了一下 go-flutter 项目, 仓库地址:
这里需要注意下, 由于 go 插件的原因,直接 clone 是跑不起来的, 你需要配置 go 以后, 把 go 插件复制到$GOPATH/src/github.com/caijinglong/go-flutter-plugin/version
目录内
后面有时间补测下打包产物
以上