Wails
WebView
WebView是一个基于webkit的引擎,可以解析DOM元素,展示html页面的空间,它和浏览器展示页面的原理是相同的,所以可以把它当作浏览器看待。
加载流程:
- 原生应用加载html页面(加载页面的方式可能有多种,比如加载本地写好的html文件,或者放置在服务器的文件)
- 加载完成,展示就是通过webview来渲染展示的,如果系统没有webview,则是无法渲染展示html的
Wails项目
wails是一个可以让你使用Go和Web技术编写桌面应用的项目
可以将它看作Go的快并且轻量级的Electron替代品。可以使用Go的功能,并结合现代化UI完成桌面应用程序的开发
功能
- 原生菜单、对话框、主题和半透明
- Windows、macOS 和 linux 支持
- 内置 Svelte、React 、Preact 、Vue、Lit 和 Vanilla JS 的模板
- 从 JavaScript 轻松调用 Go 方法
- 自动将 Go 结构体转换为 TypeScript 模块
- Windows 上不需要 CGO 或外部 DLL
- 使用 Vite 的实时开发模式
- 可以轻松创建、构建和打包应用的强大命令行工具
- 丰富的 运行时库
- 使用 Wails 构建的应用程序兼容 Apple & Microsoft 商店
安装Wails
Wails 有许多安装前需要的常见依赖项(确保您电脑的环境中是符合下述要求的):
- Go 1.20+
- NPM (Node 15+)
直接执行这个安装命令:
go install -v github.com/wailsapp/wails/v3/cmd/wails3@latest
安装完成后,运行
wails3
查看是否有wails提示,如果有则表示安装完成
注意:
- 如果输入wails提示不是一个命令,有可能你的path变量没有指向GO的安装路径
PATH变量:
PATH变量需要指向你GO安装的bin目录,这样才能识别到安装的wails.exe文件
创建项目
安装好Wai-CLI后,可以使用wails init 命令生成一个新项目
使用JavaSciprt生成一个Svelte项目:
wails3 init -n myproject -t svelte
也可以使用TypeScript
wails3 init -n myproject -t svelte
项目布局
Wails 项目有以下布局:
├─ build # 包含构建过程使用的文件 │ ├─ darwin # 后台管理应用模块(安装saas时存在、不安装则删除) │ │ ├─ icons.icns # macOS 应用程序图标 │ │ ├─ Info.dev.plist # 开发配置 │ │ ├─ Info.plist # 生产配置 │ │ └─ Taskfile.yml # macOS 构建任务 │ ├─ linux # 特定于 Linux 的构建文件 │ │ ├─ appimage # AppImage 打包 │ │ │ └─ build.sh # AppImage 构建脚本 │ │ ├─ nfpm # NFPM 包装 │ │ │ ├─ scripts # 构建脚本 │ │ │ │ ├─ postinstall.sh # │ │ │ │ ├─ postremove.sh # │ │ │ │ ├─ preinstall.sh # │ │ │ │ └─ preremove.sh # │ │ │ └─ nfpm.yaml # 文件包配置 │ │ └─ Taskfile.yml # Linux 构建任务 │ ├─ windows # 特定于 Windows 的构建文件 │ │ ├─ nsis # NSIS 安装程序文件 │ │ │ ├─ project.nsi # NSIS 项目文件 │ │ │ └─ wails_tools.nsh # NSIS 帮助程序脚本 │ │ ├─ icon.ico # Windows 应用程序图标 │ │ ├─ info.json # 应用程序元数据 │ │ ├─ Taskfile.yml # Windows 生成任务 │ │ └─ wails.exe.manifest # Windows 清单文件 │ ├─ appicon.png # 应用程序图标 │ ├─ config.yml # 构建配置 │ └─ Taskfile.yml # 生成任务 ├─ frontend # 前端应用程序文件 ├─ greetservice.go # Go后端服务 ├─ main.go # 主要应用程序代码 ├─ README.md # 项目文档 └─ Taskfile.yml # 项目任务配置
运行
使用命令进行运行
wails3 dev
第一次运行会非常长,需要耐心等待
直接获取项目
如果嫌弃上述步骤麻烦,可以直接拉取wails-go-init仓库进行开发,仓库内的项目已经搭建好了基本的目录结构。
- 项目的地址:
git clone https://gitee.com/rix_renex/wails-go-init.git
运行项目前,请确保您的电脑上安装了以下环境:
- Go - 1.23+
- Node.js - 18+
- wails3
前后端双端数据绑定
框架通过wails命令内置模板在frontend前端目录下生成bindings代码绑定Go和前端通讯,前通过js函数调用后端Go函数。
其实,前后端双端的数据绑定只要看如下三个点即可:
Service声明
在新建一个Service时,不论是否是一个Service文件,还是方法,Wails生成时它会根据结构体来进行链式输出
- WebService.go
package web import ( ... ) // 必须存在,这是双端绑定的关键 type WebService struct{} // 打开网页跳转 func (g *WebService) JumpWebUrl(url string) { link.JumpWeb(url) } // 获取常见网址名称 func (g *WebService) GetWebNameList() map[string]_struct.WebAction { return _struct.CheckWebNameList() }
来看一个Service创建的过程:在函数声明的时候 (g *WebService) 这个必须指向当前Service所拥有的某个struct结构体;
我们所有的Service都依靠这个struct结构体进行连接调用
当创建Service文件后,还需要在main.go文件中声明该Service文件
- main.go
app := application.New(application.Options{ // ... Services: []application.Service{ // 添加go方法程序 application.NewService(&web.WebService{}), }, // ... })
在这里main.go文件中,声明app变量时,需要添加go的方法程序,也就是application.NewService()方法;
- 该方法内部传递的就是你上一步在Service中声明的struct结构
wails在内部解析时,就会依靠这里传递的struct来生成binding中对应的Service类,然后通过引用变量名进行调用
bindings源码:
可以看到它生成了两个文件
index.js和webservice.js
- index.js
// @ts-check // Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL // This file is automatically generated. DO NOT EDIT import * as WebService from "./webservice.js"; export { WebService };
- webservice.js
// @ts-check // Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL // This file is automatically generated. DO NOT EDIT // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore: Unused imports import {Call as $Call, Create as $Create} from "@wailsio/runtime"; // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore: Unused imports import * as _struct$0 from "../../struct/models.js"; /** * 获取常见网址名称 * @returns {Promise<{ [_: string]: _struct$0.WebAction }> & { cancel(): void }} */ export function GetWebNameList() { let $resultPromise = /** @type {any} */($Call.ByID(2464737837)); let $typingPromise = /** @type {any} */($resultPromise.then(($result) => { return $$createType3($result); })); $typingPromise.cancel = $resultPromise.cancel.bind($resultPromise); return $typingPromise; } /** * 打开网页跳转 * @param {string} url * @returns {Promise<void> & { cancel(): void }} */ export function JumpWebUrl(url) { let $resultPromise = /** @type {any} */($Call.ByID(1783560979, url)); return $resultPromise; } // Private type creation functions const $$createType0 = _struct$0.WebInformation.createFrom; const $$createType1 = $Create.Array($$createType0); const $$createType2 = _struct$0.WebAction.createFrom; const $$createType3 = $Create.Map($Create.Any, $$createType2);
生成的bindings包内的内容,其实就是对Service进行解析成js文件,以便前端进行调用。而在main.go中声明就是打开Service的开放,使得wails能够扫描到对应的service
引用路径与使用
那么此时Service已经创建完毕了,下面来在实际的js或vue业务中进行调用
import { WebService } from "../bindings/passwordManagement/src/service/web"; /** 传值 */ const jumpWeb =(url)=>{ WebService.JumpWebUrl(url) } /** 获取数据 */ WebService.GetWebNameList().then(data=>{ })
是不是很简单?其实只要引入bindings中index.js所在目录就行了,然后将index.js中暴露出来的变量进行声明,就可以使用Service了,其他的值传递@wailsio/runtime包中的代码会帮你解决的