进程通信
由于 preload.js
并无法使用全部 Node 的API ,比如:不能使用 Node 中的 fs
模块,但主进程(main.js)是可以的,这时就需要进程通信了。简单说:要让 preload.js
通知 main.js
去调用 fs
模块。
关于Electron进程通信,我们要知道:
IPC
全称为:InterProcess Communication
,即:进程通信。IPC
是Electron
中最为核心的内容,它是从UI
调用原生API
的唯一方法!Electron
中,主要使用ipcMain
和ipcRenderer
来定义“通道”,进行进程通信。
渲染进程=>主进程(单向)
在渲染器进程中 ipcRenderer.send
发送消息,在主进程中使用 ipcMain.on
接收消息。
常用于:在 Web 中调用主进程的 API
(1)页面中添加相关元素,renderer.js 中添加对应脚本
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta
http-equiv="Content-Security-Policy"
content="default-src 'self'; script-src 'self'"
/>
<title>Hello World!</title>
</head>
<body>
<input
id="content"
type="text"
/>
<button id="btn">在用户的桌面创建一个hello.txt</button>
<script
type="text/javascript"
src="./renderer.js"
></script>
</body>
</html>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
const btn = document.getElementById("btn")
const content = document.getElementById("content")
btn.addEventListener("click", () => {
console.log(content.value)
myAPI.saveFile(content.value)
})
2
3
4
5
6
(2)preload.js 中使用 ipcRenderer.send('信道',参数)
发送消息,与主进程通信。
const { contextBridge, ipcRenderer } = require("electron")
// 暴露数据给渲染进程
contextBridge.exposeInMainWorld("myAPI", {
name: "dancy",
age: 28,
saveFile(str) {
// 渲染进程给主进程发送一个消息
ipcRenderer.send("create-file", str)
},
})
2
3
4
5
6
7
8
9
10
11
(3)主进程中,在加载页面之前,使用 ipcMain.on('信道',回调)
配置对应回调函数,接收消息。
const { app, BrowserWindow, ipcMain } = require("electron")
const fs = require("node:fs")
const path = require("node:path")
// 获取桌面路径
const desktopPath = path.join(process.env.HOME, "Desktop")
// 要写入的文件名
const fileName = "hello.txt"
// 使用writeFileSync方法创建并写入文件
function createFile(event, data) {
fs.writeFileSync(path.join(desktopPath, fileName), data)
}
const createWindow = () => {
const win = new BrowserWindow({
width: 300,
height: 200,
autoHideMenuBar: true,
webPreferences: {
preload: path.resolve(__dirname, "./preload.js"),
},
})
// 主进程注册对应回调
ipcMain.on("create-file", createFile)
win.loadFile("./pages/index.html")
}
app.on("ready", () => {
createWindow()
app.on("activate", () => {
if (BrowserWindow.getAllWindows().length === 0) createWindow()
})
})
app.on("window-all-closed", () => {
if (process.platform !== "darwin") app.quit()
})
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
渲染进程<=>主进程(双向)
渲染进程通过 ipcRenderer.invoke
发送消息,主进程使用 ipcMain.handle
接收并处理消息。
备注:ipcRender.invoke
的返回值是 Promise
实例。
常用于:从渲染器进程调用主进程方法并等待结果
(1)页面中添加相关元素,renderer.js中添加对应脚本
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta
http-equiv="Content-Security-Policy"
content="default-src 'self'; script-src 'self'"
/>
<title>Hello World!</title>
</head>
<body>
<button id="btn">读取用户桌面hello.txt的内容</button>
<script
type="text/javascript"
src="./renderer.js"
></script>
</body>
</html>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
const btn = document.getElementById("btn")
btn.addEventListener("click", async () => {
const data = await myAPI.readFile()
document.body.innerHTML += `<h2>${data}</h2>`
})
2
3
4
5
(2)preload.js中使用 ipcRenderer.invoke('信道',参数)
发送消息,与主进程通信。
const { contextBridge, ipcRenderer } = require("electron")
// 暴露数据给渲染进程
contextBridge.exposeInMainWorld("myAPI", {
name: "dancy",
age: 28,
saveFile(str) {
// 渲染进程给主进程发送一个消息
ipcRenderer.send("create-file", str)
},
readFile() {
return ipcRenderer.invoke("read-file")
},
})
2
3
4
5
6
7
8
9
10
11
12
13
14
(3)主进程中,在加载页面之前,使用 ipcMain.handle('信道',回调)
接收消息,并配置回调函数。
const { app, BrowserWindow, ipcMain } = require("electron")
const fs = require("node:fs")
const path = require("node:path")
// 获取桌面路径
const desktopPath = path.join(process.env.HOME, "Desktop")
// 要写入的文件名
const fileName = "hello.txt"
// 使用writeFileSync方法创建并写入文件
function createFile(event, data) {
fs.writeFileSync(path.join(desktopPath, fileName), data)
}
//读取文件
function readFile() {
return fs.readFileSync(path.join(desktopPath, fileName)).toString()
}
const createWindow = () => {
const win = new BrowserWindow({
width: 300,
height: 200,
autoHideMenuBar: true,
webPreferences: {
preload: path.resolve(__dirname, "./preload.js"),
},
})
ipcMain.on("create-file", createFile)
// 主进程注册对应回调
ipcMain.handle("read-file", readFile)
win.loadFile("./pages/index.html")
}
app.on("ready", () => {
createWindow()
app.on("activate", () => {
if (BrowserWindow.getAllWindows().length === 0) createWindow()
})
})
app.on("window-all-closed", () => {
if (process.platform !== "darwin") app.quit()
})
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
主进程到=>渲染进程
概述:主进程使用 win.webContents.send
发送消息,渲染进程通过 ipcRenderer.on
处理消息
常用于: 从主进程主动发消息给渲染进程
(1)页面中添加相关元素, renderer.js 中添加对应脚本
window.onload = () => {
myAPI.getMessage(logMessage)
}
function logMessage(event, str) {
console.log(event, str)
document.body.innerHTML = str
}
2
3
4
5
6
7
(2)preload.js中使用 ipcRenderer.on ('信道',回调)
接收消息,并配置回调函数。
const { contextBridge, ipcRenderer } = require("electron")
// 暴露数据给渲染进程
contextBridge.exposeInMainWorld("myAPI", {
name: "dancy",
age: 28,
saveFile(str) {
// 渲染进程给主进程发送一个消息
ipcRenderer.send("create-file", str)
},
readFile() {
return ipcRenderer.invoke("read-file")
},
getMessage: (callback) => {
return ipcRenderer.on("message", callback)
},
})
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
(3)主进程中,在合适的时候,使用 win.webContents.send('信道',数据)
发送消息。
const { app, BrowserWindow, ipcMain } = require("electron")
const fs = require("node:fs")
const path = require("node:path")
// 获取桌面路径
const desktopPath = path.join(process.env.HOME, "Desktop")
// 要写入的文件名
const fileName = "hello.txt"
// 使用writeFileSync方法创建并写入文件
function createFile(event, data) {
fs.writeFileSync(path.join(desktopPath, fileName), data)
}
//读取文件
function readFile() {
return fs.readFileSync(path.join(desktopPath, fileName)).toString()
}
// 创建窗口
const createWindow = () => {
const win = new BrowserWindow({
width: 300,
height: 200,
autoHideMenuBar: true,
webPreferences: {
preload: path.resolve(__dirname, "./preload.js"),
},
})
// 主进程注册对应回调
ipcMain.on("create-file", createFile)
// 主进程注册对应回调
ipcMain.handle("read-file", readFile)
// 加载指定的文件到新创建的窗口中,这个文件通常是应用的主页面。
win.loadFile("./pages/index.html")
// 创建一个定时器
setTimeout(() => {
win.webContents.send("message", "你好啊!")
}, 2000)
}
app.on("ready", () => {
createWindow()
app.on("activate", () => {
if (BrowserWindow.getAllWindows().length === 0) createWindow()
})
})
app.on("window-all-closed", () => {
if (process.platform !== "darwin") app.quit()
})
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54