Electron 快速入門


轉載自:https://zhuanlan.zhihu.com/p/27740025

簡介

Electron 是一個可以使用 Web 技術如 JavaScript、HTML 和 CSS 來創建跨平台原生桌面應用的框架。借助 Electron,我們可以使用純 JavaScript 來調用豐富的原生 APIs。

Electron用 web 頁面作為它的 GUI,而不是綁定了 GUI 庫的 JavaScript。它結合了 Chromium、Node.js 和用於調用操作系統本地功能的 APIs(如打開文件窗口、通知、圖標等)。

現在已經有很多由 Electron 開發應用,比如 AtomInsomniaVisual Studio Code 等。查看更多使用 Electron 構建的項目可以訪問 Apps Built on Electron

安裝

安裝 electron 之前,需要安裝 Node.js。

然后安裝 electron:

npm install electron -g

進程

Electron 的進程分為主進程和渲染進程。

主進程

在 electron 里面,運行 package.json 里面 main 腳本的進程成為主進程。主進程控制整個應用的生命周期,在主進程中可以創建 Web 形式的 GUI,而且整個 Node API 是內置其中。

渲染進程

每個 electron 的頁面都運行着自己的進程,稱為渲染進程。

主進程與渲染進程的聯系及區別

主進程使用 BrowserWindow 實例創建頁面。每個 BrowserWindow 實例都在自己的渲染進程里運行頁面。當一個 BrowserWindow 實例被銷毀后,相應的渲染進程也會被終止。

主進程管理所有頁面和與之對應的渲染進程。每個渲染進程都是相互獨立的,並且只關心他們自己的頁面。

在 electron 中,頁面不直接調用底層 APIs,而是通過主進程進行調用。所以如果你想在網頁里使用 GUI 操作,其對應的渲染進程必須與主進程進行通訊,請求主進程進行相關的 GUI 操作。

在 electron 中,主進程和渲染進程的通信主要有以下幾種方式:

  • ipcMain、ipcRender
  • Remote 模塊

進程通信將稍后詳細介紹。

打造第一個 Electron 應用

這也是官方的一個樣例,可直接在  找到。

一個最簡單的 electron 應用目錄結構如下:

electron-demo/
├── package.json
├── main.js
└── index.html

package.json 與 Node.js 的完全一致,所以我們可以使用 npm init 來生成。然后將 "main": "index.js" 修改為 "main": "main.js"。之所以命名為 main.js,主要是為了與主進程這個概念對應。

main.js

const electron = require('electron');

const {
  app, // 控制應用生命周期的模塊
  BrowserWindow, // 創建原生瀏覽器窗口的模塊
} = electron;

// 保持一個對於 window 對象的全局引用,如果不這樣做,
// 當 JavaScript 對象被垃圾回收, window 會被自動地關閉
let mainWindow;

function createWindow() {
  // 創建瀏覽器窗口。
  mainWindow = new BrowserWindow({
    width: 800, 
    height: 600,
    webPreferences: {
        nodeIntegration: true, // 是否集成 Nodejs, Uncaught ReferenceError: process is not defined
    }
  });

  // 加載應用的 index.html。
  // 這里使用的是 file 協議,加載當前目錄下的 index.html 文件。
  // 也可以使用 http 協議,如 mainWindow.loadURL('http://nodejh.com')。
  mainWindow.loadURL(`file://${__dirname}/index.html`);

  // 啟用開發工具。
  mainWindow.webContents.openDevTools();

  // 當 window 被關閉,這個事件會被觸發。
  mainWindow.on('closed', () => {
    // 取消引用 window 對象,如果你的應用支持多窗口的話,
    // 通常會把多個 window 對象存放在一個數組里面,
    // 與此同時,你應該刪除相應的元素。
    mainWindow = null;
  });
}

// Electron 會在初始化后並准備
// 創建瀏覽器窗口時,調用這個函數。
// 部分 API 在 ready 事件觸發后才能使用。
app.on('ready', createWindow);

// 當全部窗口關閉時退出。
app.on('window-all-closed', () => {
  // 在 macOS 上,除非用戶用 Cmd + Q 確定地退出,
  // 否則絕大部分應用及其菜單欄會保持激活。
  if (process.platform !== 'darwin') {
    app.quit();
  }
});

app.on('activate', () => {
  // 在 macOS 上,當點擊 dock 圖標並且該應用沒有打開的窗口時,
  // 絕大部分應用會重新創建一個窗口。
  if (mainWindow === null) {
    createWindow();
  }
});

注意,新版本的需要加上 nodeIntegration: true,不然會報錯 "Uncaught ReferenceError: process is not defined”

index.html

在這里編輯需要展示的 index.html:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Hello World!</title>
    <style media="screen">
      .version {
        color: red;
      }
    </style>
  </head>
  <body>
    <h1>Hello World!</h1>
    We are using Node.js
    <span id="version-node" class="version"></span>
    and Electron
    <span id="version-electron" class="version"></span>
    <script type="text/javascript">
      console.log('process: ', process);
      var versionNode = process.version;
      var versionElectron = process.versions['electron'];
      console.log(versionNode, versionElectron)
      document.getElementById('version-node').innerText = versionNode
      document.getElementById('version-electron').innerText = versionElectron
    </script>
  </body>
</html>

在這個例子中,我們顯示出了 electron 使用的 Node.js 版本和 electron 的版本。index.html 跟網頁的 HTML 一摸一樣,只是多了一些 electron 的全局對象。

運行

因為前面已經全局安裝了 electron,所以我們可以使用 electron 命令來運行項目。在 electron-demo/ 目錄里面運行下面的命令:

$ electron .

然后會彈出一個 electron 應用客戶端,如圖所示:

因為在主進程中啟用了開發模式 mainWindow.webContents.openDevTools(),所以默認啟動開發者工具。

如果是局部安裝的 electron,即 npm install --save electron,則可以運行下面的命令來啟動應用:

$ ./node_modules/.bin/electron .

進行通信

對於 electron 來說,主進程和渲染進程直接的通信是必不可少的。

前面提到過 electron 進程間的通信的方式主要有兩種,一種是用於發送消息的 ipcMain 和 ipcRenderer 模塊,一種用於 RPC 的 remote 模塊。

現在假設一個業務場景,用戶在頁面中輸入文本消息,渲染進程將消息發送給主進程,主進程處理后將處理結果返回給頁面。為了方便起見,主進程的處理就假設為翻轉文本。當然,這個功能在前端完全可以實現,這里只是為了演示進程通信。

ipcMain 和 ipcRenderer

首先在渲染進程中添加一個輸入框和一個按鈕,並實現點擊按鈕獲取輸入框的內容。然后使用 ipcRenderer 發送消息。主進程接收到消息並處理之后,會返回處理結果。所以渲染進程中還需要接收主進程的消息。

修改 index.html,添加下面的代碼:

<!-- 在 body 部分添加一個輸入框和按鈕 -->
<div>
  <input type="text" id="message" name="" value="">
  <br/>
  <button type="button" id="button" name="button">click me</button>
</div>

<script type="text/javascript">
  // ...

  // 添加下面的代碼。
  // 引入 ipcRenderer 模塊。
  var ipcRenderer = require('electron').ipcRenderer;
  document.getElementById('button').onclick = function () {
    var message = document.getElementById('message').value;
    // 使用 ipcRenderer.send 向主進程發送消息。
    ipcRenderer.send('asynchronous-message', message);
  }

  // 監聽主進程返回的消息
  ipcRenderer.on('asynchronous-reply', function (event, arg) {
    alert(arg);
  });
</script>

接下來在主進程中接收渲染進程的消息,並進行處理(翻轉字符串),然后將處理結果發送給主進程。修改 main.js 如下:

const ipcMain = require('electron').ipcMain;

//...

// 監聽渲染進程發送的消息
ipcMain.on('asynchronous-message', (event, arg) => {
  const reply = arg.split('').reverse().join('');
  console.log('reply: ', reply);
  // 發送消息到主進程
  event.sender.send('asynchronous-reply', reply);
});

remote

remote 模塊提供了一種在渲染進程(網頁)和主進程之間進行進程間通訊(IPC)的簡便途徑。

使用 remote 模塊,我們可以很方便地調用主進程對象的方法,而不需要發送消息。

在 index.html 的 <script> 標簽中添加如下代碼:

// 引入 remote 模塊
var remote = require('electron').remote;
// 獲取主進程中的 BrowserWindow 對象
var BrowserWindow = remote.BrowserWindow;
// 創建一個渲染進程
var win = new BrowserWindow({ width: 200, height: 150 });
win.loadURL('https://www.cnblogs.com/lfri/');

然后使用 ctr + r 組合鍵刷新應用,就會看到創建出的一個新窗口。

打包

Electron 應用開發完成之后,還需要將其打包成對應平台的客戶端。常用的打包工具有 electron-packager 和 asar(聽說electron-builder 更好用?)

這里以 electron-packager 為例。首先全局安裝 electron-packager:

$ npm install electron-packager -g

然后在項目中安裝 electron:

$ npm install electron --save-dev

然后打包:

$ electron-packager . electron-demo

總結

本文首先對 electron 做了簡單的介紹,然后講解了 electron 進程的概念,其進程包括主進程和渲染進程。然后創建了一個簡單的 electron 應用,並通過實現一個簡單的應用場景,對 electron 進程間的通信做了實踐。

總體來說,使用 electron 創建桌面客戶端的開發體驗跟寫 Node.js 和網頁差不多。但本文對內置模塊比如 app、ipcMain、ipcRender、remote 等的介紹比較粗淺,涉及到一些內置模塊的使用,還需要繼續查詢 electron 的官方文檔,只有實踐越多,才能越熟悉。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM