2016年11月12日 星期六

[Electron] 學習筆記(2) - IPC 機制

source code @ github

這次來說明一下 Electron 的 IPC 機制

Electron 使用 Chromium multi-process 的機制,由 main process 來創建 application

renderer process 來負責繪製 web page,而 process 之間是無法直接溝通的

那如果想要 web page 和 GUI 有互動,例如可以透過 button 來關閉整個視窗,那該怎麼做?

這時候就必須透過 IPC (inter-process communication) 來做溝通

Electron 的 IPC 溝通的概念,是透過 channel來傳遞訊息

channel 的一方監聽,另一方送訊息進來,示意圖如下



官方的文件在這邊,ipcMain 以及 ipcRenderer

相關 source code 放在 ipc 資料夾下

這個程式會示範如何透過 IPC,讓使用者可以透過在 web page 的 button來關閉整個應用程式

  • 先說明一下這次的資料結構
ipc
 |- app
 |     |- index.html
 |     |- index.js
 |
 |- main.js
 |- package.json

  • index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Electron IPC</title>
</head>
<body>
<center>
<h1>Electron IPC</h1>
<button id="close">Close Window</button>
<script src="index.js"></script>
</center>
</body>
</html>
view raw index.html hosted with ❤ by GitHub
這邊建立一個按鈕,並用 renderer process 來跑 index.js

  • index.js
'use strict';
//> ipc for renderer process
let ipcRenderer = require('electron').ipcRenderer;
//> close button
let closeBtn = document.querySelector('#close');
closeBtn.addEventListener('click', () => {
//> send a message to close-main-window channel without args
ipcRenderer.send('close-main-window');
});
view raw index.js hosted with ❤ by GitHub
首先,在 renderer process 拿到 ipcRenderer 的 instance

之後就可以透過這個 instance 來和 main process 做溝通

這邊要注意一點是,在 renderer process 就只能拿 ipcRenderer

如果改寫成

let ipcRenderer = require('electron').ipcMain
會發現 ipcRenderer 會是 undefined

這是因為 electron 會區別是 main process 還是 renderer process 的關係

接著讓按鈕監聽 click 事件

當按鈕被點擊後,透過 ipcRenderer 送訊息到 close-main-window 這個 channel

來和 main process 溝通

  • mina.js
'use strict';
const {app, BrowserWindow, ipcMain} = require('electron');
const path = require('path');
const url = require('url');
//> keep a global reference of the window object, if you don't, the window will
//> be closed automatically when the JavaScript object is garbage collected.
let win = null;
//> create the browser window
function createWindow() {
win = new BrowserWindow({width: 400, height: 300});
//> load the index.html of the app
win.loadURL(url.format({
protocol: 'file',
slashes: true,
pathname: path.join(__dirname, 'app/index.html')
}));
//> open the DevTools
//win.webContents.openDevTools();
//> emitted when the window is closed
win.on('closed', () => {
//> dereference the window object, usually you would store windows
//> in an array if your app supports multi windows, this is the time
//> when you should delete the corresponding element
win = null
});
}
//> This method will be called when Electron has finished
//> initialization and is ready to create browser windows.
//> Some APIs can only be used after this event occurs.
app.on('ready', createWindow);
//> Quit when all windows are closed
app.on('window-all-closed', () => {
//> On macOS 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();
}
});
app.on('activate', () => {
//> On macOS it is common to re-create a window in the app when the
//> dock icon is clicked and there are no other windows open
if(win === null) {
createWindow();
}
});
//> ipcMain is ipc of main process
//> ipcMain listen to close-main-window channel here
ipcMain.on('close-main-window', () => {
console.log('closed by ipc');
app.quit();
});
view raw main.js hosted with ❤ by GitHub
在 require electron 的時候,順便拿 ipcMain 這個 instance

然後在最後面,叫 ipcMain 監聽 close-main-window 這個 channel

當從這個 channel 收到訊息的時候,就把視窗關掉

  • 執行程式

> npm install
> ./node_modules/.bin/electron .


沒有留言:

張貼留言