1. 程式人生 > >原創|我是如何從零學習開發一款跨平臺桌面軟體的(Markdown編輯器)

原創|我是如何從零學習開發一款跨平臺桌面軟體的(Markdown編輯器)

原始衝動

最近一直在學習 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 也讓我過了一把產品經理的癮,基本已經滿足了我的日常需求。如果你有更好的想法和創意也可以告訴我,說不定第二天就會實現了。

Github:https://github.com/yueshutong/JustWrite