Go Flutter Desktop (一) 初探

2023-11-18

Flutter 在去年的时候就有一个第三方的桌面引擎, 是用 golang 开发的

Github 地址是:https://github.com/go-flutter-desktop/go-flutter

目前在 mac,linux,windows 均可用, 作为一个 mac 用户, 除了 retina 下字显得有点小, 感觉没有单独适配外, 总体感觉是优于官方的 desktop 引擎的

另外我是真实的 golang 脑残粉, 我觉得 golang 这东西真的太好了, 用 golang, 准不会错

开发环境

需要的开发环境, 因为我是 MacOS, 我以 macOS 为例,其他的请参考对应的系统

  1. Xcode 命令行体系, 这个东西包含很多开发套件(Git), 无论你是否用 XCode 开发,都建议装一个…
  2. Flutter 环境和配套工具, 这个跑不掉,作为 flutter 开发者…
  3. go 语言环境(使用 brew 安装), 1.12+, IDE 用 Jetbrains 家的 goland (你用 VSCode 的话看你自己的情况)

环境安装

对 flutter 桌面版本感兴趣的一定接触过 flutter 开发, 我就默认你有 flutter 全套开发环境

go 语言环境安装

$ 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 相关的东西会被装在这个文件夹里

go-flutter 的环境

需要使用一个叫做 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

官方提供了几个 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

将原项目改为 desktop

官方说明文档是这样的, 不想看英文的, 可以跳过官方文档直接看我的中文说明

[外链图片转存失败(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

20190704171705.png

这样项目就跑起来了

测试基础的项目

测试下常用的几项:

  1. 事件响应
  2. ListView
  3. 图片
  4. 输入框情况

事件响应

点击事件是可行的,数字可加, 说明鼠标事件能响应, 其他的长按双击等等都是 flutter 实现的, 理论上就不需要测试了

最开始的官方 demo 中有鼠标移入移出事件

ListView 滚动

import 'package:flutter/material.dart';

class ListViewPage extends StatefulWidget {
  @override
  _ListViewPageState createState() => _ListViewPageState();
}

class _ListViewPageState extends State<ListViewPage> {
  @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<ImagePage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(),
      body: ListView(
        children: <Widget>[
          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<InputPage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('input')),
      body: Container(
        child: TextField(),
      ),
    );
  }
}

20190705102958.png

输入英文还算正常

试试中文:

[外链图片转存失败(img-AilDMdOn-1562911906086)(https://raw.githubusercontent.com/kikt-blog/image/master/img/20190705103106.png)]

文字位置正常,输入框没跟随

显示行为

单行没问题, 试试多行, 直接回车不行 我们需要将 TextField 设置为多行, 我这里分别设置 10/50 行

20190705103327.png

50 行的话,一页放不下,滚动也算正常
[外链图片转存失败(img-xmoUxOSz-1562911906086)(https://raw.githubusercontent.com/kikt-blog/image/master/img/Kapture 2019-07-05 at 10.34.23.gif)]

但是这里有一个问题, 中英文混合的情况下, 水滴不正常

20190705103537.png

开头和结尾都是英文则没问题, 都是中文同理
20190705103646.png
[外链图片转存失败(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 去调用

总体有如下几个步骤:

  1. 创建插件
  2. 编写代码(go+dart)
  3. 引入插件

官方文档在此: https://hover.build/docs/create-a-plugin/

创建并编写插件

go 端

打开 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 获取的数据或任何东西, 我这里返回了一个简单的字符串

dart 端

import 'package:flutter/services.dart';

class GetVersionPlugin {
  static const _channel = const MethodChannel("top.kikt/go/version");

  static Future<String> 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<PluginPage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(),
      body: FutureBuilder<String>(
        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目录内

后面有时间补测下打包产物

以上

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Go Flutter Desktop (一) 初探 的相关文章

随机推荐

  • .secret勒索病毒数据恢复

    导言 在数字时代 随着科技的迅猛发展 我们的生活更加便捷 但也引发了一系列新的威胁 其中之一就是勒索软件 而 secret 勒索病毒 则是这个威胁中的一颗明亮而又毒辣的星 91数据恢复本文将带您深入了解 secre 勒索病毒的特点 并探讨如
  • Image Sensor的FSIN/VSYNC

    本文介绍Image Sensor的FSIN VSYNC 产品开发过程 比如3D成像 中 有时会遇到需要2个及以上的Image Sensor同步采集 因此 Image Sensor厂家对于他们的产品都提供了同步功能 也就是我们经常所见的FSI
  • 学习Vue基础的分享

    Vue是一个前端框架 所以就有自己特定的语法 所以在这里列出学到的基础语法作用 基础模板参考 div h1 testName a baidu a h1 div
  • c语言ofstream未定义标识符,关于c++:c中ifstream及ofstream超详细说明

    前文说过 ifstream是继承于istream ofstream是继承于ostream fstream是继承于iostream类 而他们应用的缓冲区类是filebuf 对于这些类之间的关系 有趣味能够去查看我之前的文章 c 规范输入输出流
  • httpclient错误

    Caused by org apache http ProtocolException Target host is not specified at org apache http impl conn DefaultRoutePlanne
  • 用python实现计算器

    上次我用我学习的python做一个简易的计算器 我对计算器进行了 更改优化 变成了一个真正的计算器 实现流程 1 计算机布局 2 计算机执行 首先导入模块 Tkinter 作为 Python GUI 开发工具之一 它具有 GUI 软件包的必
  • 技术大佬和普通程序员改bug的区别!

    阅读本文大概需要2min 文 强哥 未经授权禁止转载 在我这么多年的工作生涯里 难免遇到那些工作糊弄的开发同事 随意编程的实习生 不够细致的测试 缺乏专业度的产品 产品的体验 取决于多个环节的把控 但很多情况下 由于bug严重影响体验 或者
  • 【原创】遇到 ORACLE 错误 1017

    1 错误描述 expdp sys leixiao orcl1 schemas sys directory DATA PUMP DIR dumpfile expdp test1 dmp logfile expdp test1 log 以sys
  • 做影视剪辑短视频,新手小白一个月赚5000多,用点心你也可以

    大周有一个学员把短视频当自己兴趣爱好 空余时间做二次剪辑 谁想到一个月多赚了5000多 他在一家私企上班 工作还算稳定 每天朝九晚五的工作 他不想就这样日复一日平淡的过下去 找到了大周 开始了自己短视频之旅 他这个人比较腼腆 本人出镜拍视频
  • 解决Android通过chrome://inspect/调试WebView出现 HTTP/1.1 404 Not Found 的问题

    问题描述 无论是调试Web页面还是调试Hybrid混合应用 只要是调试Android的webview 都需要使用Chrome inspect进行调试 但是国内开发者会出现404 Not Found错误 原因解析 国内网络无法访问 https
  • Java中九大内置对象

    1 Request对象 该对象封装了用户提交的信息 通过调用该对象相应的方法可以获取封装的信息 即使用该对象可以获取用户提交的信息 当Request对象获取客户提交的汉字字符时 会出现乱码问题 必须进行特殊处理 首先 将获取的字符串用ISO
  • 全国计算机等级考试题库二级C操作题100套(第91套)

    第91套 函数fun的功能是 计算请在程序的下划线处填入正确的内容并把下划线删除 使程序得出正确的结果 注意 源程序存放在考生文件夹下的BLANK1 C中 不得增行或删行 也不得更改程序的结构 给定源程序 include
  • Spring Cloud 2.2.2 源码之三十九nacos配置动态刷新原理一

    Spring Cloud 2 2 2 源码之三十九nacos配置动态刷新原理一 RefreshScope注解类实例化基本流程 nacos如何通过RefreshScope注解进行属性刷新 RefreshEventListener的handle
  • Selenium安装及环境配置

    目录 一 Selenium 简介 1 组件 2 特点 二 安装Selenium 三 下载对应版本的Chromedriver 1 查看Chrome的版本号 2 下载驱动 chromedriver和配置 3 解压到本地 4 复制文件放入pyth
  • 一次吃透Qt中信号与槽(包含信号与槽的使用,自定义以及重构示例,建议收藏)

    1 Qt中信号和槽 信号与槽 信号与槽 Signal Slot 是 Qt 编程的基础 也是 Qt 的一大创新 因为有了信号与槽的编程机制 在 Qt 中处理界面各个组件的交互操作时变得更加直观和简单 它可以让应用程序编程人员把这些互不了解的对
  • 2023领导力测评启示录

    导读 在现今这个由数据驱动的世界里 人力资源专业人士也越来越注重在进行人才选拔和发展时 运用客观数据来辅助决策 然而 面对市场上种类繁多的测评选择 首要挑战就是要了解不同类型的领导力测评 通常 测评主要分为两类 这两类测评的区别在于收集的数
  • Go语言实现区块链与加密货币-Part1(基本原型、工作量证明、持久化)

    区块链 Blockchain 是21世纪最具革命性的技术之一 它仍然处于不断成长的阶段 而且还有很多潜力尚未显现 作为比特币的底层技术 它本质上只是一个分布式数据库 不过使它独一无二的是 区块链是一个公开的而不是私人的数据库 每个使用它的人
  • 使用Arduino开发ESP32(22):蓝牙作为客户端使用

    文章目录 目的 基础准备 搜索蓝牙设备 搜索设备 信息查询 连接与交互 总结 目的 ESP32的蓝牙除了作为服务器 从设备 使用还可以作为客户端 主机 使用 这篇文章将对相关内容做个简单说明 基础准备 这篇文章中测试需要先准备一个蓝牙服务器
  • 字符串翻转

    给定两个字符串 s和goal 如果在若干次旋转操作之后 s能变成goal 那么返回true s的旋转操作就是将s最左边的字符移动到最右边 例如 若s abcde 在旋转一次之后结果就是 bcdea 示例 1 输入 s abcde goal
  • Go Flutter Desktop (一) 初探

    Flutter 在去年的时候就有一个第三方的桌面引擎 是用 golang 开发的 Github 地址是 https github com go flutter desktop go flutter 目前在 mac linux windows