使用Wails构建跨平台GUI程序快速入门,Electron的不错平替方案。

Wails简介

Wails 是一个能让你使用 Go 和 Web 技术栈构建桌面应用程序的项目。你可能听说过 Electron,这是 Github 开源的一个跨平台桌面应用程序开发的解决方案。像我们熟知的 VS Code、Typora 都是使用 Electron 开发的,界面部门使用 Web 技术栈实现,所以你会感觉跟使用浏览器无异。

今天要介绍的 Wails 和 Electron 区别是:Wails 后端使用 Go 实现,利用 JS 函数绑定 Go 函数,然后调用,由 Go 的运行时来实现调用的过程。而 Electron 的后端是使用 Node.js 实现,渲染进程和主进程之间通过内置的 IPC(Inter Process Communication) 模块实现进程间通信。注意,这里的后端不是指 Web 后端,如 Java 的 SpringBoot、Python 的 Flask、Django 等 Web 后端程序。这里的后端是指本地的服务进程,其实和 Web 后端区别不大,只不过渲染进程和主进程之间通信使用本地接口调用(可能是某种二进制协议、也可能是像 DLL、SO 之类的动态库),传统 Web 应用程序使用 HTTP、WebSocket 协议进行前后端通信。 这里的渲染进程也就是前端。

你也可能听过 Tauri 跨平台桌面应用程序解决方案,后端使用 Rust 开发。今天在这里不做讨论,因为笔者对 Rust 不是很熟悉。

工作原理

Wails 使用 Webkit 作为内核,Go 语言部分的应用程序由应用程序代码和一个提供了很多实用功能的运行时库组成。比如,控制应用程序窗口。在前端,Webkit 窗口会展示前端资源,同时前端还有一个 JavaScript 运行时库。最后前端的和后端的 Go 函数绑定到一起,并且这些看起来像是可以被调用本地 JavaScript 函数。

快速入门

安装

支持的系统

  • Windows 10/11 AMD64/ARM64
  • MacOS 10.13+ AMD64
  • MacOS 11.0+ ARM64
  • Linux AMD64/ARM64

依赖项

  • Go 1.18+
  • Node 15+

安装Wails CLI

这里还需要安装 Wails 脚手架命令行工具,它本身是使用 Go 开发的一个二进制可执行文件。你可以使用它来创建工程。

输入命令安装:

shell 复制代码
go install github.com/wailsapp/wails/v2/cmd/wails@latest

这一切前提是你安装了 Go SDK,并且配置了 GOPATH 环境变量。GOPATH 用于存放下载的 Go 二进制文件(命令行工具)还有第三方库文件。

创建一个工程

生成脚手架工程

使用 wails init 命令可以初始化一个标准的 Wails 工程。Wails 官方提供了多种 Web 前端框架可供选择,选择自己熟悉的 Web 前端框架即可:

我这里使用 React 结合 TS 语言演示,输入命令创建工程:

shell 复制代码
wails init -n wails-first -t react-ts

目录结构

go 复制代码
.
├── build/
│   ├── appicon.png
│   ├── darwin/
│   └── windows/
├── frontend/
├── go.mod
├── go.sum
├── main.go
└── wails.json
  • /main.go - 主程序
  • /frontend/ - 前端工程文件
  • /build/ - 打包过后的文件夹
  • /build/appicon.png - 应用程序图标
  • /build/darwin/ - Mac 系统特定文件
  • /build/windows/ - Windows 系统特定文件
  • /wails.json - 工程配置文件
  • /go.mod - Go module 文件
  • /go.sum - Go module 版本锁文件

开发应用程序

前端是使用 vite 构建的所以对热更新支持得很棒。

输入 wails dev 命令可以初始化工程依赖库并启动应用程序。应用程序界面如下:

简单看一下 App.tsx 文件代码:

tsx 复制代码
import { useState } from 'react'
import logo from './assets/images/logo-universal.png'
import './App.css'
import { Greet } from '../wailsjs/go/main/App'

function App() {
  const [resultText, setResultText] = useState('Please enter your name below 👇')
  const [name, setName] = useState('')
  const updateName = (e: any) => setName(e.target.value)
  const updateResultText = (result: string) => setResultText(result)

  function greet() {
    Greet(name).then(updateResultText)
  }

  return (
    <div id="App">
      <img src={logo} id="logo" alt="logo" />
      <div id="result" className="result">{resultText}</div>
      <div id="input" className="input-box">
        <input id="name" className="input" onChange={updateName} autoComplete="off" name="input" type="text" />
        <button className="btn" onClick={greet}>Greet</button>
      </div>
    </div>
  )
}

export default App

可以看出来是一个输入一个名字然后替换屏幕上一段话的程序。点击按钮触发点击事件并且触发 input 元素 onChange 事件调用 updateName 函数更新 name 变量,然后调用 greet 函数,greet 函数最终又调用了跟 Go 函数绑定的 JS 函数:

ts 复制代码
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
// This file is automatically generated. DO NOT EDIT

export function Greet(arg1:string):Promise<string>;

这是自动生成的文件,不可以修改,不然会出毛病。最终这个 ts 文件被编译成 js 文件:

js 复制代码
// @ts-check
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
// This file is automatically generated. DO NOT EDIT

export function Greet(arg1) {
  return window['go']['main']['App']['Greet'](arg1);
}

可以看到调用了 window 对象的某个属性的函数。按照顺序来讲就是调用 go 对象的 main 文件对象的 App 结构体的 Greet 方法,这个是按照文件目录层级调用的。

顺藤摸瓜找到 go 文件里面的函数:

go 复制代码
package main  
  
import (  
"context"  
"fmt"  
)  
  
// App struct  
type App struct {  
    ctx context.Context  
}  
  
// NewApp creates a new App application struct  
func NewApp() *App {  
    return &App{}  
}  
  
// startup is called when the app starts. The context is saved  
// so we can call the runtime methods  
func (a *App) startup(ctx context.Context) {  
    a.ctx = ctx  
}  
  
// Greet returns a greeting for the given name  
func (a *App) Greet(name string) string {  
    return fmt.Sprintf("Hello %s, It's show time!", name)  
}

可以清晰看到 Greet 方法返回一个模板字符串,这个用起来确实比 Electron 的 IPC 模块通信简单一些。

打包应用程序

可以使用 wails build 命令来打包应用程序:

shell 复制代码
wails build

最终编译的文件在 build/bin 文件夹内,在 Mac OS 上会编译成一个二进制可执行文件,在 Windows 就是 .exe 文件。

相关推荐
Casual_Lei36 分钟前
ClickHouse 的底层架构和原理
clickhouse·架构
吕彬-前端3 小时前
使用vite+react+ts+Ant Design开发后台管理项目(二)
前端·react.js·前端框架
小白小白从不日白3 小时前
react hooks--useCallback
前端·react.js·前端框架
恩婧3 小时前
React项目中使用发布订阅模式
前端·react.js·前端框架·发布订阅模式
cooldream20094 小时前
828华为云征文 | 在华为云X实例上部署微服务架构的文物大数据管理平台的实践
微服务·架构·华为云·文物大数据平台
程序员小杨v14 小时前
如何使用 React Compiler – 完整指南
前端·react.js
码拉松5 小时前
千万不要错过,优惠券设计与思考初探
后端·面试·架构
谢尔登6 小时前
Babel
前端·react.js·node.js
卸任6 小时前
使用高阶组件封装路由拦截逻辑
前端·react.js
小筱在线6 小时前
使用SpringCloud构建可伸缩的微服务架构
spring cloud·微服务·架构