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