跳到主要內容
黯羽輕揚每天積累一點點

electron 入門指南

免費2017-09-17#Tool#electron系统托盘#electron状态栏icon#electron桌面通知#electron ETIMEDOUT#electron mac

從 0.2 開始 electron

一.認識

定位

Electron is a framework for creating native applications with web technologies like JavaScript, HTML, and CSS.

實現

Electron = Node + Chromium + V8

這些只是 Electron 的依賴項,跨平台最關鍵的自然是適配層,由供 node 呼叫的 C++ 模組來完成平台適配,提供系統級的平台介面

適用場景

桌面環境可能很難抹平差異,Electron 的大多數 API 都是分平台的,例如 quick start 裡的:

// Quit when all windows are closed.
app.on('window-all-closed', function () {
  // On OS X it is common for applications and their menu bar
  // to stay active until the user quits explicitly with Cmd + Q
  if (process.platform !== 'darwin') {
    app.quit()
  }
})

如果想用 Electron 實現完美的跨平台一致體驗,還要費不少功夫,甚至某些方面不可能做到一致(可能需要自己做一些 C++ 模組來完成適配),就 API 體驗來看,比 ionic 移動端跨平台更費勁,平台差異太多

但如果只是想「用 JS 寫個 Mac/Win 工具,說不定還能跨平台」的話,即不考慮平台差異的話,Electron 還算不錯

二.開發環境

quick start

官方提供了 quick-start,算是基本的試玩環境:

# Clone this repository
git clone https://github.com/electron/electron-quick-start
# Go into the repository
cd electron-quick-start
# Install dependencies
npm install
# Run the app
npm start

npm install 可能遇到 ETIMEDOUT,因為 electron 包非常大(120M):

node install.js

.../node_modules/electron/install.js:48
  throw err
  ^

Error: connect ETIMEDOUT 52.216.66.16:443
    at Object.exports._errnoException (util.js:1034:11)
    at exports._exceptionWithHostPort (util.js:1057:20)
    at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1096:14)

建議換用 taobao 鏡像下載:

# 刪除還沒下載完成的
rm -rf node_modules/electron
# 指定 taobao 鏡像
ELECTRON_MIRROR=http://npm.taobao.org/mirrors/electron/ npm install electron

一切正常的話,能跑出來一個 hello world 視窗,看看 API 文件,體驗一些系統原生 API,比如系統托盤,桌面通知等等,試玩結束

如果打算開始搞的話,強烈不建議從 quick start 開始,因為還缺很多東西:

  • 模組化方案

  • 構建方案(開發 - 打包 - 發布)

  • 元件庫(UI 庫)

  • 路由管理

  • 持久化方案

那麼可能還需要 react、webpack、antd、react-router、xxx-storage 等等一大堆東西,手動去做的話,只 webpack 構建方案就得小半天,所以,我們需要更強大的範本專案

boilerplate

對於 react 全家桶,這裡推薦兩份專案範本:

  • electron-react-boilerplate:yarn 管理依賴,webpack 構建

     React
     Redux
     React Router
     Webpack
     React Transform HMR
    
  • electron-react-redux-boilerplate:npm 管理依賴,npm scripts 構建

     React Router
     Redux Thunk
     Redux Actions
     Redux Local Storage
     Electron Packager
     Electron DevTools Installer
     Electron Mocha
     Browsersync
    

webpack 配置構建可擴充套件性更好一些,但實際使用發現 electron-react-boilerplate 構建配置相當複雜,本地沒能跑起來,嘗試解決無果後放棄了,改用 electron-react-redux-boilerplate

兩個範本都沒有提供 UI 元件庫,引入 antd 後發現 npm scripts 構建腳本很難解決自動引入 css 的問題(webpack 可以添 loader 解決),暫時先拿 cp 頂著,後續考慮切換到 webpack:

"private:style": "cp -f node_modules/antd/dist/antd.css build/antd.css; cp -rf app/css build/css"

P.S.在安裝依賴時,也會遇到 electron 下載超時的問題,同樣,環境變數指向 taobao 鏡像:

ELECTRON_MIRROR=http://npm.taobao.org/mirrors/electron/ yarn

三.常見問題

1.讓視窗緊貼托盤圖示正下方

有現成模組,相當好用:

先獲取托盤圖示的位置,再根據視窗大小計算居中

2.系統托盤圖示尺寸

For OS X, create icons:

icon.png (for best results aim 16x16px)

icon @2x.png (32x32px)

For Windows, create single icon:

icon.ico

ICO format will work better than classic PNG. If you want PNG, make it 32x32px.

摘自:Proper tray icon

Mac 頂部選單列高度是 22px,可以用 22px 或者 16pxpng 格式圖示

P.S.gif 格式圖片不可以用做圖示

3.Mac 系統通知中文亂碼

HTML 需要透過 meta 設定 charset

<meta charset="utf-8">

否則 HTML 裡引入的外部 JS 資源裡的字面量中文串,會出現亂碼

4.持久化儲存

建議使用 electron-store

用 JSON 檔案來存,放在應用安裝目錄裡,API 不太科學:

// set() 只能存基本值
store.set('unicorn', 'ma');
console.log(store.get('unicorn'));
//=> 'ma'

// 存物件路徑不方便
store.set('foo.bar', true);
console.log(store.get('foo'));
//=> {bar: true}

// store 只能整個替換所有資料
store.store = data

不很影響使用,讀寫都是同步的,存簡單的使用者配置比較合適。大量資料的話,可能存在效能問題

P.S.更多 Electron 資料儲存方式請檢視 [How to store user data in Electron](https://medium.com/ @ccnokes/how-to-store-user-data-in-electron-3ba6bf66bc1e)

5.IPC

Electron 裡有兩個程序,Main 和 Renderer,前者負責管理一切,並與平台互動,後者提供瀏覽器環境,渲染頁面

程序間通訊支援程度比較好,有同步和異步兩種方式,透過事件訊息來通訊

異步通訊(event.sender.send()):

// In main process.
const {ipcMain} = require('electron')
ipcMain.on('asynchronous-message', (event, arg) => {
  console.log(arg)  // prints "ping"
  event.sender.send('asynchronous-reply', 'pong')
})

// In renderer process (web page).
const {ipcRenderer} = require('electron')
ipcRenderer.on('asynchronous-reply', (event, arg) => {
  console.log(arg) // prints "pong"
})
ipcRenderer.send('asynchronous-message', 'ping')

同步通訊(event.returnValue):

// In main process.
const {ipcMain} = require('electron')
ipcMain.on('synchronous-message', (event, arg) => {
  console.log(arg)  // prints "ping"
  event.returnValue = 'pong'
})

// In renderer process (web page).
const {ipcRenderer} = require('electron')
console.log(ipcRenderer.sendSync('synchronous-message', 'ping')) // prints "pong"

P.S.如果 renderer 發來的參數是 undefined,直接傳入系統介面,可能會遇到錯誤:

ERROR:v8_value_converter.cc(374)] Unexpected v8 value type encountered.

傳遞給系統介面的參數,應該嚴格校驗,避免此類問題

6.開機自啟

有現成模組:node-auto-launch

npm install --save auto-launch

P.S.Mac 下確實添了一條啟動項,但沒有勾選,可能需要制定應用路徑,待深入瞭解

寫在最後

實際上,對系統級 API 的依賴比想象的少太多了,學習成本大多來自前端生態(React 全家桶),完全合心意的元件庫是不存在的

東西呢,還不成樣子,下週繼續

評論

暫無評論,快來發表你的看法吧

提交評論