用 Go 開發(fā)桌面應用程序(GUI)的幾種方法對比(使用go開發(fā)桌面gui程序)
我想構(gòu)建一個本地 Go 桌面應用程序,有幾種方法可以做到:
- Electron[1]:將 Node.js[2] 和 Chromium[3] 瀏覽器綁定在一起,以創(chuàng)建一個打包的本地 Web 應用程序。可與 Go 框架(例如 go-app[4] 或 go-astilectron[5])一起使用。
- Lorca[6]:使用本地安裝的 Chrome 瀏覽器,通過 dev-tools communication protocol[7] 實現(xiàn)。
- Webview[8]:使用 webview[9] 創(chuàng)建一個本地窗口,并使用 CGo 綁定在其中渲染應用程序。
我已經(jīng)寫過有關構(gòu)建一個簡單的 electron 應用程序的文章[10],因此本文將探討如何使用 Lorca 和 Webview 構(gòu)建應用程序,然后比較這三種的不同。
Lorca
Go 中一個簡單的 Lorca[11] 應用:
func main() { // Create UI with data URI ui, _ := lorca.New("data:text/html," url.PathEscape(` <html> <head><title>Hello</title></head> <body><h1>Hello, world!</h1></body> </html> `), "", 600, 200) defer ui.Close() // Create a GoLang function callable from JS ui.Bind("hello", func() string { return "World!" }) // Call above `hello` function then log to the JS console ui.Eval("hello().then( (x) => { console.log(x) })") // Wait until UI window is closed <-ui.Done()}
因為復雜性被隱藏了,所以看起來非常簡單!上面的代碼打開一個 Chome 窗口,通過 websocket 連接到其 dev-tools[12] 端點,發(fā)送要加載的 HTML,并提供 Go 和 JS 之間的通信:
更酷的是,您可以在 Chrome 中調(diào)用 JS 函數(shù)并在 Go 中獲取輸出:
n := ui.Eval(`Math.random()`).Float()fmt.Println(n)
使用這個庫是如此容易,如此直觀,如此實用,以至于我剛使用它時感到困惑。我以為一定有陷阱,不會這么簡單。但是沒有,它就是這么簡單。
另外一個好處是您可以使用 Chrome 開發(fā)工具來幫助調(diào)試任何問題或調(diào)整布局。另外,鑒于我自 2014 年以來[13]一直在寫 Promise,我喜歡使用 JS Promise 在 Go 和 JS 之間實現(xiàn)異步調(diào)用。
Lorca 的最大缺點是,由于它使用 Chrome,因此某些應用程序詳細信息(如系統(tǒng)菜單,圖標,標題)無法自定義。然后,需要在應用程序優(yōu)化和簡單應用程序之間進行權衡。根據(jù)您構(gòu)建內(nèi)容的不同,有好有弊,例如,如果您正在構(gòu)建內(nèi)部工具,那會很好,但是對于企業(yè)應用程序,這可能看起來并不好。
Webview
Webview[14] 是一個庫,可幫助直接在本地組件之上構(gòu)建 Web 應用程序。執(zhí)行此操作的代碼如下:
func main() { w := webview.New(true) defer w.Destroy() w.SetSize(600, 200, webview.HintNone) // Create a GoLang function callable from JS w.Bind("hello", func() string { return "World!" }) // Create UI with data URI w.Navigate(`data:text/html, <!doctype html> <html> <head><title>Hello</title></head> <body><h1>Hello, world!</h1></body> <script> hello().then((x) => { console.log(x) }) </script> </html>`) w.Run()}
這與 Lorca 非常相似,我認為 Lorca 也是基于 Webview 的。盡管與 Lorca 相似,但輸出還是有些不同:
從上圖可以看到 Webview 應用程序窗口沒有陰影,沒有邊框,并且在屏幕的左下角進行了初始化??梢酝ㄟ^將Window返回一個 unsafe.Pointer到 OS 依賴的窗口對象的方法(在 macOS 中是 NSWindow)進行定制。這是開始難的地方。
要使用該 Window 對象,我們必須將 Go 的綁定寫入本地組件。舉例來說,如果我們希望我們的窗口居中啟動,我們會調(diào)用 NSWindow 的 Center 方法。因此,我們需要在三個文件中寫綁定(改編自 gogoa[15]):
ns_window.go
package main// #cgo CFLAGS: -x objective-c// #cgo LDFLAGS: -framework Cocoa//#include "ns_window.h"import "C"import "unsafe"type NSWindow struct { ptr unsafe.Pointer}func (self *NSWindow) Center() { C.Center(self.ptr)}
ns_window.h
#include <Cocoa/Cocoa.h>void Center(void *);
ns_window.m
#include "ns_window.h"void Center(void *self) { NSWindow *window = self; [window center];}
然后在main()函數(shù)中,我們可以將窗口居中:
window := NSWindow {w.Window()}window.Center()
與 Lorca 不同,Webview 可以針對我們的應用程序進行完全自定義。問題在于它需要一些工作。
Webview 的一些其他部分使得用它變得有些困難:
- 如果使用 Bazel 和 gazelle,則webview生成的Build.bazel文件不正確,clinkopts = ["-framework WebKit"] 必須對其進行修補。
- 調(diào)用 w.Init 僅在w.Navigate被調(diào)用時有效,但隨后w.Eval調(diào)用將停止工作。
- 要設置標題,您可以如上所述編寫綁定,或者您必須使用Dispatch方法w.Dispatch(func() { w.SetTitle("Title") })。
我不確定有多少是Webview,有多少是 NSWindow。我需要進行更多的調(diào)查和學習,才能更清楚地說明這些發(fā)生的原因。
Electron
我之前的文章[16]是關于構(gòu)建一個簡單的 Electron 應用程序的,該應用程序如下所示:
Electron 用于許多大型產(chǎn)品,例如 VSCode。這可能是因為將所有內(nèi)容捆綁到一個應用程序中使可移植性變得更加簡單,并且可以廣泛地定制應用程序。將應用程序與瀏覽器和 Node.js 捆綁在一起的不利之處在于,它導致程序 非常龐大。
讓 Go 與 Electron 一起工作也有些困難。但有一些框架可以簡化[17]此過程,例如 go-astilectron[18],不過這些框架很復雜,并且大多數(shù)功能不完整。另一種方法可能是使用我之前寫過的[19] Go 編譯為 WASM ,但這也不是簡單的解決方案。
Electron 的優(yōu)勢在于它是便攜式的,可定制的,并且經(jīng)過了應用程序分發(fā)的嚴格測試。只是和 Go 結(jié)合有點復雜。
三者比較
我認為要進行的主要比較是可定制性與簡單性。到目前為止,Lorca 是最簡單的,其可定制性非常有限,Webview 可以完全自定義,但有些困難,而 Electron 則可以完全自定義,但很難與 Go 一起使用。
同樣,框架之間的捆綁包大小也有很大差異。Lorca 的二進制文件大小為 8.7 MB,Webview 的大小為 3.7Mb,Electron 的大小為 157Mb。
調(diào)試工具也有所不同:Lorca 和 Electron 使用 Chrome 開發(fā)工具,而 Webview 使用 Safari 開發(fā)工具。
結(jié)論
Lorca 和 Webview 都可以與 Go 一起很好地使用,最終二進制較小,并且具有類似的 API。主要區(qū)別在于基礎渲染器(本機)和調(diào)試工具。
我認為 Electron 與 Go 一起使用可能太復雜了,但沒有太多困難。
一個潛在的工作流程是在開發(fā)和 Webview 分發(fā)期間使用 Lorca。Lorca 提供了用于調(diào)試和開發(fā)的熟悉工具,其中 Webview 提供了可分發(fā)的可定制性。Lorca 也是很好的備份,可以交叉編譯到 Webview 不支持的其他操作系統(tǒng)。
注意:還有更多類似的選項,wails[20] 或 gotk[21] 可以提供其他方式來構(gòu)建/分發(fā)應用程序。
作者:Graham Jenson
原文鏈接:https://maori.geek.nz/golang-desktop-app-webview-vs-lorca-vs-electron-a5e6b2869391
譯者:polaris
參考資料
[1]
Electron: https://www.electronjs.org/
[2]
Node.js: https://nodejs.org/
[3]
Chromium: https://www.chromium.org/
[4]
go-app: https://github.com/maxence-charriere/go-app
[5]
go-astilectron: https://github.com/asticode/go-astilectron
[6]
Lorca: https://github.com/zserge/lorca
[7]
dev-tools communication protocol: https://chromedevtools.github.io/devtools-protocol/
[8]
Webview: https://github.com/webview/webview
[9]
webview: https://developer.apple.com/documentation/webkit/webview
[10]
構(gòu)建一個簡單的 electron 應用程序的文章: https://maori.geek.nz/building-an-electron-app-with-bazel-d124ed550957
[11]
Lorca: https://github.com/zserge/lorca
[12]
dev-tools: https://chromedevtools.github.io/devtools-protocol/
[13]
自 2014 年以來: https://maori.geek.nz/jquery-promises-and-deferreds-i-promise-this-will-be-short-d10275f82717
[14]
Webview: https://github.com/webview/webview
[15]
gogoa: https://github.com/alediaferia/gogoa
[16]
之前的文章: https://maori.geek.nz/building-an-electron-app-with-bazel-d124ed550957
[17]
簡化: https://github.com/asticode/go-astilectron
[18]
go-astilectron: https://github.com/asticode/go-astilectron
[19]
之前寫過的: https://maori.geek.nz/a-web-app-using-bazel-golang-wasm-and-proto-c020914f4341
[20]
wails: https://github.com/wailsapp/wails
[21]
gotk: https://github.com/gotk3/gotk3