使用 Golang 和 HTML5 開發一個 MacOS App

{"type":"doc","content":[{"type":"heading","attrs":{"align":null,"level":1},"content":[{"type":"text","text":"前言"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Go語言(也稱爲Golang)是 google 在 2009 年推出的一種編譯型編程語言。相對於其他編程語言,golang 具有編寫併發程序或網絡交互簡單、數據類型豐富、編譯速度快等特點,比較適合於高性能、高併發場景。Go 語言一直在網絡編程、雲平臺開發、分佈式系統等領域佔據着重要的地位,尤其在雲原生領域,殺手級項目 Docker 和 Kubernetes 都是採用 Go 語言開發的。而在其他領域,比如桌面應用開發,也有一些框架可以使用,本篇文章就來介紹如何使用 Go 語言 和 HTML5 來開發一個 MacOS App。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":1},"content":[{"type":"text","text":"框架選擇"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"這裏我選用了 "},{"type":"link","attrs":{"href":"https://github.com/labstack/echo","title":""},"content":[{"type":"text","text":"echo[1]"}]},{"type":"text","text":" 作爲 web 框架,當然也可以選擇其他的 web 框架,選擇 echo 只不過因爲其比較輕量。要做桌面應用,還需要一個 GUI 框架來構建應用,這裏我選擇的是"},{"type":"link","attrs":{"href":"https://github.com/zserge/lorca","title":""},"content":[{"type":"text","text":" Lorca[2]"}]},{"type":"text","text":",使用 Lorca 可以用 Go 編寫 HTML5 桌面程序,依賴 Chrome 進行 UI 渲染,但卻不需要把 Chrome 打包到應用中,也就是說使用應用的電腦,需要安裝 Chrome。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"lorca"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"echo 的使用方式中規中矩,沒有什麼需要介紹的。這裏簡要介紹一下 lorca,其的使用方法和原理都很簡單,可以將其看做是一個瀏覽器,可在其上運行 web 應用,lorca 可直接將 web 應用包裝成桌面應用。這裏提供一個簡單的示例:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"go"},"content":[{"type":"text","text":"ui, _ := lorca.New(\"\", \"\", 480, 320)\ndefer ui.Close()\n\n// Bind Go function to be available in JS. Go function may be long-running and\n// blocking - in JS it's represented with a Promise.\nui.Bind(\"add\", func(a, b int) int { return a + b })\n\n// Call JS function from Go. Functions may be asynchronous, i.e. return promises\nn := ui.Eval(`Math.random()`).Float()\nfmt.Println(n)\n\n// Call JS that calls Go and so on and so on...\nm := ui.Eval(`add(2, 3)`).Int()\nfmt.Println(m)\n\n// Wait for the browser window to be closed\n\n"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n\n\n\tCFBundleExecutable\n\tkustomize\n\tCFBundleIconFile\n\ticon.icns\n\tCFBundleIdentifier\n\tio.guoxudong.kustomize-remote-observer\n\tNSHighResolutionCapable\n \n\tLSUIElement\n 1\n\n"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"使用腳本構建 App"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"上面的這些只不過是介紹一下原理及手動修改方式,實際應用中可以使用腳本來完成這些工作。使用如下腳本,可以一鍵完成:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":".app"}]},{"type":"text","text":" 應用的構建"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"go 應用的打包"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"清單文件的生成"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"靜態資源的拷貝"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"shell"},"content":[{"type":"text","text":"#!/bin/sh\n\nAPP=\"Kustomize.app\"\nmkdir -p $APP/Contents/{MacOS,Resources}\ngo build -o $APP/Contents/MacOS/kustomize\ncat > $APP/Contents/Info.plist << EOF\n\n"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n\n\n\tCFBundleExecutable\n\tkustomize\n\tCFBundleIconFile\n\ticon.icns\n\tCFBundleIdentifier\n\tio.guoxudong.kustomize-remote-observer\n\tNSHighResolutionCapable\n \n\tLSUIElement\n 1\n\n\nEOF\ncp icons/icon.icns $APP/Contents/Resources/icon.icns\ncp -r assets $APP/Contents/Resources/assets\ncp -r views $APP/Contents/Resources/views\nfind $APP"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"注意"},{"type":"text","text":" 在 MacOS 中,當您運行 App bundle 時,進程的工作目錄是根目錄("},{"type":"codeinline","content":[{"type":"text","text":"/"}]},{"type":"text","text":"),而不是 "},{"type":"codeinline","content":[{"type":"text","text":"Contents/Resources"}]},{"type":"text","text":" 目錄。如果需要從 "},{"type":"codeinline","content":[{"type":"text","text":"Resources"}]},{"type":"text","text":" 加載資源,則需要進行如下更改:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"go"},"content":[{"type":"text","text":"ep, err := os.Executable()\nif err != nil {\n\tlog.Fatalln(\"os.Executable:\", err)\n}\nerr = os.Chdir(filepath.Join(filepath.Dir(ep), \"..\", \"Resources\"))\nif err != nil {\n\tlog.Fatalln(\"os.Chdir:\", err)\n}"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"製作 DMG 文件"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"DMG 文件用於分發應用程序,將 "},{"type":"codeinline","content":[{"type":"text","text":".app"}]},{"type":"text","text":" 文件壓縮製成鏡像,可以很方便的通過拖拽的形式完成安裝。"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"製作模板"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"製作 DMG 文件首先需要製作模板。打開"},{"type":"codeinline","content":[{"type":"text","text":"磁盤工具 - 文件 - 新建映象 - 空白映象"}]},{"type":"text","text":"(或直接按 "},{"type":"codeinline","content":[{"type":"text","text":"⌘N"}]},{"type":"text","text":")創建一個新的磁盤鏡像。給它取個名字,設置足夠的空間空間,分區選擇"},{"type":"codeinline","content":[{"type":"text","text":"CD/DVD"}]},{"type":"text","text":"。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/00/00400ccbad8dbc511797b72199432a74.jpeg","alt":null,"title":"新建模板","style":[{"key":"width","value":"50%"},{"key":"bordertype","value":"boxShadow"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"製作好後,打開該鏡像,進行文件夾視圖定製(按"},{"type":"codeinline","content":[{"type":"text","text":"⌘J"}]},{"type":"text","text":"),選擇展示圖標的大小及背景圖片,這裏可以隱藏工具欄"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/4a/4a31998c0b32c5cd2855f9c732b0a139.jpeg","alt":null,"title":"文件夾視圖定製","style":[{"key":"width","value":"100%"},{"key":"bordertype","value":"boxShadow"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"右鍵"},{"type":"codeinline","content":[{"type":"text","text":"應用程序"}]},{"type":"text","text":"選擇製作替身,將替身移動到鏡像中"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/0f/0f2f6056b1247a12d84ec8dd097cd672.jpeg","alt":null,"title":"製作替身","style":[{"key":"width","value":"50%"},{"key":"bordertype","value":"boxShadow"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"將打包好的 app 加入到 DMG 鏡像中就完成了 DMG 模板的定製"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/65/6586cd17f98ab51a08d7d128e7af45fa.jpeg","alt":null,"title":"定製好的視圖","style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"boxShadow"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"轉換 DMG 文件"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"目前的 DMG 模板文件還沒有經過壓縮並且是可寫的狀態,這樣是不能作爲程序發佈的,所以這裏需要對模板進行轉換。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/9e/9e275a766ffea5c08e2ef6137599e4b2.jpeg","alt":null,"title":"轉換","style":[{"key":"width","value":"50%"},{"key":"bordertype","value":"boxShadow"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"打開 "},{"type":"codeinline","content":[{"type":"text","text":"磁盤工具 - 映象 - 轉換"}]},{"type":"text","text":",然後選擇壓縮後存儲的目錄就完成了最後一步 DMG 文件的轉換。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/da/da0441d60397bc8fe564cf29250fb840.jpeg","alt":null,"title":"轉換成功","style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"boxShadow"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"現在點開 DMG 文件,將應用拖動到應用程序中,就可以在啓動臺中看到我們的應用程序了!"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/24/2457202b7ca2655f82a5544068b2ff96.jpeg","alt":null,"title":"啓動臺","style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"boxShadow"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"自動化"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"上面只是展示瞭如何手動製作 DMG 鏡像,實際使用當然是要將這些步驟自動化的。我將這部分內容做成了一個 go 腳本,原理其實就是使用 "},{"type":"codeinline","content":[{"type":"text","text":"hdiutil"}]},{"type":"text","text":" 這個命令行工具,有興趣的同學可以文末找到項目地址,"},{"type":"codeinline","content":[{"type":"text","text":"Makefile"}]},{"type":"text","text":" 中有詳細構建的命令。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":1},"content":[{"type":"text","text":"項目展示"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我使用 Go + HTML5 製作了一個 "},{"type":"codeinline","content":[{"type":"text","text":"Kustomize Remote"}]},{"type":"text","text":" 的項目,可以從遠程 kustomize 項目中獲取配置,並 build 成 yaml 文件,UI樣式爲微信風格,支持 public 和 private 項目。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/44/44c4e119d83e7de31e3abf51be9bddd1.jpeg","alt":null,"title":"kustomize-remote-observer","style":[{"key":"width","value":"50%"},{"key":"bordertype","value":"boxShadow"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/86/869e51deb8e70fc8814898b1f007e337.jpeg","alt":null,"title":"yaml result","style":[{"key":"width","value":"50%"},{"key":"bordertype","value":"boxShadow"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"項目地址:"},{"type":"link","attrs":{"href":"https://github.com/sunny0826/kustomize-remote-observer","title":""},"content":[{"type":"text","text":"https://github.com/sunny0826/kustomize-remote-observer"}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"也可以直接在 "},{"type":"link","attrs":{"href":"https://github.com/sunny0826/kustomize-remote-observer/releases","title":""},"content":[{"type":"text","text":"release 頁面[5]"}]},{"type":"text","text":" 下載 DMG 文件安裝試用,只需 Mac 上有 Chrome 即可。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":1},"content":[{"type":"text","text":"結語"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Go 語言一直在網絡編程、雲平臺開發、分佈式系統等領域佔據着重要的地位,但是像桌面應用或者機器學習這樣的領域,同樣也能做出不錯的效果。作爲一門受歡迎的編程語言 Golang 已經有十多年的歷史了,相信它在將來還能在更多的領域煥發生機,創造輝煌。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/a4/a45c3a602d914f821ca970e51f9dcd2d.gif","alt":null,"title":"","style":[{"key":"width","value":"50%"},{"key":"bordertype","value":"boxShadow"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"heading","attrs":{"align":null,"level":4}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}}]}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章