前言
Go語言(也稱為Golang)是 google 在 2009 年推出的一種編譯型編程語言。相對於其他編程語言,golang 具有編寫併發程序或網絡交互簡單、數據類型豐富、編譯速度快等特點,比較適合於高性能、高併發場景。Go 語言一直在網絡編程、雲平臺開發、分佈式系統等領域佔據著重要的地位,尤其在雲原生領域,殺手級項目 Docker 和 Kubernetes 都是採用 Go 語言開發的。而在其他領域,比如桌面應用開發,也有一些框架可以使用,本篇文章就來介紹如何使用 Go 語言 和 HTML5 來開發一個 MacOS App。
框架選擇
這裡我選用了 echo 作為 web 框架,當然也可以選擇其他的 web 框架,選擇 echo 只不過因為其比較輕量。要做桌面應用,還需要一個 GUI 框架來構建應用,這裡我選擇的是 Lorca,使用 Lorca 可以用 Go 編寫 HTML5 桌面程序,依賴 Chrome 進行 UI 渲染,但卻不需要把 Chrome 打包到應用中,也就是說使用應用的電腦,需要安裝 Chrome。
lorca
echo 的使用方式中規中矩,沒有什麼需要介紹的。這裡簡要介紹一下 lorca,其的使用方法和原理都很簡單,可以將其看做是一個瀏覽器,可在其上運行 web 應用,lorca 可直接將 web 應用包裝成桌面應用。這裡提供一個簡單的示例:
ui, _ := lorca.New("", "", 480, 320)
defer ui.Close()
// Bind Go function to be available in JS. Go function may be long-running and
// blocking - in JS it's represented with a Promise.
ui.Bind("add", func(a, b int) int { return a + b })
// Call JS function from Go. Functions may be asynchronous, i.e. return promises
n := ui.Eval(`Math.random()`).Float()
fmt.Println(n)
// Call JS that calls Go and so on and so on...
m := ui.Eval(`add(2, 3)`).Int()
fmt.Println(m)
// Wait for the browser window to be closed
<-ui.Done()
製作 MacOS App
在完成基本的編碼後,接下來的工作才是重點:將應用包裝成一個 MacOS APP。
製作圖標
一個 MacOS APP 首先需要一個圖標,這裡請選擇一個 1024 X 1024 分辨率,背景透明的 PNG 圖片。這裡假設該圖片名為 logo.png
:
- 新建一個名為
tmp.iconset
的臨時目錄,用於存放不同大小的臨時圖片 - 執行如下命令,將原圖轉為不同大小的圖片並放入臨時目錄
$ sips -z 16 16 logo.png --out tmp.iconset/icon_16x16.png
$ sips -z 32 32 logo.png --out tmp.iconset/[email protected]
$ sips -z 32 32 logo.png --out tmp.iconset/icon_32x32.png
$ sips -z 64 64 logo.png --out tmp.iconset/[email protected]
$ sips -z 128 128 logo.png --out tmp.iconset/icon_128x128.png
$ sips -z 256 256 logo.png --out tmp.iconset/[email protected]
$ sips -z 256 256 logo.png --out tmp.iconset/icon_256x256.png
$ sips -z 512 512 logo.png --out tmp.iconset/[email protected]
$ sips -z 512 512 logo.png --out tmp.iconset/icon_512x512.png
$ sips -z 1024 1024 logo.png --out tmp.iconset/[email protected]
- 使用 iconutil 生成圖標
$ iconutil -c icns tmp.iconset -o icon.icns
icon.icns
就是製作好的 MacOS App 圖標。
製作 .app bundle
macOS 上安裝的可運行程序是一個 .app
的目錄,裡面包含了應用的二進制文件、資源文件以及清單文件。其的目錄結構為(也可以通過”右鍵-顯示包內容“來查看 .app
文件內容):
$ tree Kustomize.app
Kustomize.app
└── Contents
├── Info.plist
├── MacOS
│ └── kustomize
└── Resources
├── assets
│ ├── css
│ │ ├── page.css
│ │ ├── prism.css
│ │ └── weui.min.css
│ ├── images
│ │ └── favicon.ico
│ └── js
│ ├── jquery.min.js
│ ├── prism.js
│ └── weui.min.js
├── icon.icns
└── views
├── copyreght.html
├── footer.html
├── header.html
├── index.html
└── yaml.html
可以看到:
-
Info.plist
為清單文件,存儲應用信息 -
MacOS
中存放二進制可執行文件 -
Resources
存放靜態資源文件和圖標
Info.plist 文件
這是一個清單文件,根據自己應用的內容對齊進行修改,更多內容可以參考 trayhost 項目的說明。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleExecutable</key>
<string>kustomize</string>
<key>CFBundleIconFile</key>
<string>icon.icns</string>
<key>CFBundleIdentifier</key>
<string>io.guoxudong.kustomize-remote-observer</string>
<key>NSHighResolutionCapable</key>
<true/>
<key>LSUIElement</key>
<string>1</string>
</dict>
</plist>
使用腳本構建 App
上面的這些只不過是介紹一下原理及手動修改方式,實際應用中可以使用腳本來完成這些工作。使用如下腳本,可以一鍵完成:
-
.app
應用的構建 - go 應用的打包
- 清單文件的生成
- 靜態資源的拷貝
#!/bin/sh
APP="Kustomize.app"
mkdir -p $APP/Contents/{MacOS,Resources}
go build -o $APP/Contents/MacOS/kustomize
cat > $APP/Contents/Info.plist << EOF
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleExecutable</key>
<string>kustomize</string>
<key>CFBundleIconFile</key>
<string>icon.icns</string>
<key>CFBundleIdentifier</key>
<string>io.guoxudong.kustomize-remote-observer</string>
<key>NSHighResolutionCapable</key>
<true/>
<key>LSUIElement</key>
<string>1</string>
</dict>
</plist>
EOF
cp icons/icon.icns $APP/Contents/Resources/icon.icns
cp -r assets $APP/Contents/Resources/assets
cp -r views $APP/Contents/Resources/views
find $APP
注意
在 MacOS 中,當您運行 App bundle 時,進程的工作目錄是根目錄(/
),而不是 Contents/Resources
目錄。如果需要從 Resources
加載資源,則需要進行如下更改:
ep, err := os.Executable()
if err != nil {
log.Fatalln("os.Executable:", err)
}
err = os.Chdir(filepath.Join(filepath.Dir(ep), "..", "Resources"))
if err != nil {
log.Fatalln("os.Chdir:", err)
}
製作 DMG 文件
DMG 文件用於分發應用程序,將 .app
文件壓縮製成鏡像,可以很方便的通過拖拽的形式完成安裝。
製作模板
製作 DMG 文件首先需要製作模板。打開磁盤工具 - 文件 - 新建映象 - 空白映象
(或直接按 ⌘N
)創建一個新的磁盤鏡像。給它取個名字,設置足夠的空間空間,分區選擇CD/DVD
。
製作好後,打開該鏡像,進行文件夾視圖定製(按⌘J
),選擇展示圖標的大小及背景圖片,這裡可以隱藏工具欄
右鍵應用程序
選擇製作替身,將替身移動到鏡像中
將打包好的 app 加入到 DMG 鏡像中就完成了 DMG 模板的定製
轉換 DMG 文件
目前的 DMG 模板文件還沒有經過壓縮並且是可寫的狀態,這樣是不能作為程序發佈的,所以這裡需要對模板進行轉換。
打開 磁盤工具 - 映象 - 轉換
,然後選擇壓縮後存儲的目錄就完成了最後一步 DMG 文件的轉換。
現在點開 DMG 文件,將應用拖動到應用程序中,就可以在啟動臺中看到我們的應用程序了!
自動化
上面只是展示瞭如何手動製作 DMG 鏡像,實際使用當然是要將這些步驟自動化的。我將這部分內容做成了一個 go 腳本,原理其實就是使用 hdiutil
這個命令行工具,有興趣的同學可以文末找到項目地址,Makefile
中有詳細構建的命令。
項目展示
我使用 Go + HTML5 製作了一個 Kustomize Remote
的項目,可以從遠程 kustomize 項目中獲取配置,並 build 成 yaml 文件,UI樣式為微信風格,支持 public 和 private 項目。
項目地址:https://github.com/sunny0826/kustomize-remote-observer
也可以直接在 release 頁面 下載 DMG 文件安裝試用,只需 Mac 上有 Chrome 即可。
結語
Go 語言一直在網絡編程、雲平臺開發、分佈式系統等領域佔據著重要的地位,但是像桌面應用或者機器學習這樣的領域,同樣也能做出不錯的效果。作為一門受歡迎的編程語言 Golang 已經有十多年的歷史了,相信它在將來還能在更多的領域煥發生機,創造輝煌。