下面是作者發表的開發計劃和實施歷程
最近一直在學習 Electron 開發桌面應用程序,目的是想做一個桌面編輯器,雖然一直在使用Typora這款神器,但無奈Typora太過國際化,在國內水土不服,無法滿足我的一些需求。
比如實現本地圖片上傳到雲端(mac版可以借助iPic),無法幫我把本地圖片和文章一起發佈到博客園、CSDN、SegmentFault、掘金等國內知名博客平台,要麼使用一些免費或付費的圖床,借助類似iPic的工具,把圖片一鍵上傳到雲端。
我個人也嘗試過七牛雲的免費10G存儲空間,但是說實話,這些免費的空間到最後一定是為了讓你成為付費用戶,各種限制各種吐槽在網上很容易可以搜索到。
免費的圖床如新浪微博等,還算是比較好的圖床工具,相比一些網絡上的壓根不知道啥公司甚至是歸屬個人的免費圖床,新浪應該是比較靠譜的,相對來說可以保證圖片的存活時間,我個人用過一些免費的圖床網站,記得印象深刻的就是服務器出問題,網站掛個公告,曾經的圖片再去訪問就是默認的404。
雖然新浪家大業大不是說倒閉就倒閉的,圖片相對穩定可靠,不過新浪的圖片服務器會檢測訪問來源Referer來防止外部網站引用,造成訪問403。
總結起來就是一句話,圖片還是隨著文章一鍵發佈到博客平台比較好。要丟一起丟~
心理掙扎
緣起這個動機,但是下定決心依舊是困難重重。
我個人是一個Java工程師,雖說搞過Andorid、HTML前端,但對前端深感不適的我果斷放棄了。對於桌面程序開發,我連Swing都不會,造一個Markdown編輯器有點難,何況還要加上這些定制功能。
猶猶豫豫,還是決定去嘗試一下。於是調研寫跨平台的一些途徑。
先嘗試Swing,不過Swing不好實現我期望的一些功能,改成JavaFX倒是可以,不過說實話,寫起來很累,太過繁瑣,就放棄了。最後把目光瞄向electron,就它了,HTML+Js+Css,聽起來就很簡單,事實證明,無論是測試還是打包都很方便。
決定之後,便開始進行 Electron 的系統學習。
邁出第一步
第一步就是安裝 Electron 的本地開發環境,這也是大多數應用開發的第一步。
你需要安裝 Node.js 在你的本地電腦,Electron 也是依賴於 Node.js 的環境,嚴格來說, Electron 通過將 Chromium 和 Node.js 合併到同一個運行時環境中,並將其打包為Mac,Windows和Linux系統下的應用來實現這一目的。
關於 Electron 的具體開發流程,這裡不再贅述,你完全可以在開發中使用Web前端開發的思維,除了在處理多個窗口之間交互的時候,就不得不瞭解Eelctron的進程機制。
主進程和渲染進程
Electron 運行 package.json 的 main 腳本的進程被稱為主進程。在主進程中運行的腳本通過創建web頁面來展示用戶界面。一個 Electron 應用總是有且只有一個主進程。
由於 Electron 使用了 Chromium 來展示 web 頁面,所以 Chromium 的多進程架構也被使用到。每個 Electron 中的 web 頁面運行在它自己的渲染進程中。
在普通的瀏覽器中,web頁面通常在沙盒環境中運行,並且無法訪問操作系統的原生資源。然而 Electron 的用戶在 Node.js 的 API 支持下可以在頁面中和操作系統進行一些底層交互。
主進程與渲染進程的區別
主進程使用 BrowserWindow 實例創建頁面。每個 BrowserWindow 實例都在自己的渲染進程裡運行頁面。當一個 BrowserWindow 實例被銷毀後,相應的渲染進程也會被終止。
主進程管理所有的web頁面和它們對應的渲染進程。每個渲染進程都是獨立的,它只關心它所運行的 web 頁面。
在頁面中調用與 GUI 相關的原生 API 是不被允許的,因為在 web 頁面裡操作原生的 GUI 資源是非常危險的,而且容易造成資源洩露。如果你想在 web 頁面裡使用 GUI 操作,其對應的渲染進程必須與主進程進行通訊,請求主進程進行相關的 GUI 操作。
主進程與渲染進程通信
那麼進程間如何通訊?
Electron為主進程( main process)和渲染器進程(renderer processes)通信提供了多種實現方式,如可以使用ipcRenderer 和 ipcMain模塊發送消息,使用 remote模塊進行RPC方式通信。
你還可以用 Electron 內的 IPC 機制實現。將數據存在主進程的某個全局變量中,然後在多個渲染進程中使用 remote 模塊來訪問它。
示例代碼:
// 在主進程中
global.sharedObject = {
someProperty: 'default value'
}
// 在第一個頁面中
require('electron').remote.getGlobal('sharedObject').someProperty = 'new value'
// 在第二個頁面中
console.log(require('electron').remote.getGlobal('sharedObject').someProperty)
使用Electron的API
Electron在主進程和渲染進程中提供了大量API去幫助開發桌面應用程序, 在主進程和渲染進程中,你可以通過require的方式將其包含在模塊中以此,獲取Electron的API
const electron = require('electron')
所有Electron的API都被指派給一種進程類型。許多API只能被用於主進程或渲染進程中,但其中一些API可以同時在上述兩種進程中使用。每一個API的文檔都將聲明你可以在哪種進程中使用該API。
Electron中的窗口是使用BrowserWindow類型創建的一個實例, 它只能在主進程中使用。
// 這樣寫在主進程會有用,但是在渲染進程中會提示'未定義'
const { BrowserWindow } = require('electron')
const win = new BrowserWindow()
因為進程之間的通信是被允許的, 所以渲染進程可以調用主進程來執行任務。Electron通過remote模塊暴露一些通常只能在主進程中獲取到的API。為了在渲染進程中創建一個BrowserWindow的實例,通常使用remote模塊為中間件:
// 這樣寫在渲染進程中時行得通的,但是在主進程中是'未定義'
const { remote } = require('electron')
const { BrowserWindow } = remote
const win = new BrowserWindow()
使用Node.js的API
Electron同時在主進程和渲染進程中對Node.js 暴露了所有的接口。這裡有兩個重要的定義:
1)所有在Node.js可以使用的API,在Electron中同樣可以使用。在Electron中調用如下代碼是有用的:
const fs = require('fs')
const root = fs.readdirSync('/')
// 這會打印出磁盤根級別的所有文件
// 同時包含'/'和'C:\'。
console.log(root)
2)你可以在你的應用程序中使用Node.js的模塊。選擇您最喜歡的 npm 模塊。npm 提供了目前世界上最大的開源代碼庫,那裡包含良好的維護、經過測試的代碼,提供給服務器應用程序的特色功能也提供給Electron。
例如,在你的應用程序中要使用官方的AWS SDK,你需要首先安裝它的依賴:
npm install --save aws-sdk
然後在你的Electron應用中,通過require引入並使用該模塊,就像構建Node.js應用程序那樣:
// 準備好被使用的S3 client模塊
const S3 = require('aws-sdk/clients/s3')
有一個非常重要的提示: 原生Node.js模塊 (即指,需要編譯源碼過後才能被使用的模塊) 需要在編譯後才能和Electron一起使用。
最終產品殺青落地
終於搞明白了 Electron 的應用架構,那麼接著就要進入產品的開發階段。比較慶幸的是,ELectron 的UI完全由CSS+HTML組成,這部分可用的框架太多了,我選擇了又老又知名的 BootStarp 框架搭建界面UI,還引用了JS框架JQuery。選擇了 electron-store 作為本地存儲文件,至於最關鍵的Markdown語法解析,對比了一番主流解析框架,最終選擇了 markdown-it。貼一下效果圖:
這款軟件我給他起名為 JustWrite,意思就是現在就寫,也是在督促自己吧,畢竟猶豫徘徊,等於白來。
現在軟件的功能除了包含一鍵發佈本地文章加本地圖片到博客園、CSDN、SegmentFault、掘金、開源中國等平台,我還打算將他打造為一個體驗不錯的Markdown寫作軟件。現在你閱讀的這篇文章,就是我使用 JustWrite 書寫的,使用的字體是我個人喜歡的幼圓體,除此之外,還有六款風格迥異的字體可以切換使用。字號也是可以動態放大或者縮小,還可以關閉右側預覽,專注於寫作,如下圖所示:
這些截圖是我截屏後使用快捷鍵Ctrl+V一鍵粘貼的,圖片會自動放到當前md文件所在目錄下的picture文件夾內。
關於 JustWrite 從構思到實踐的心路歷程大致就以上這些了,這次開發 JustWrite 也讓我過了一把產品經理的癮,基本已經滿足了我的日常需求。如果你有更好的想法和創意也可以告訴我,說不定第二天就會實現了。 |