WBlog

wangzhiwei blog

0%

electron 复习

URL在外部浏览器打开

require(‘electron’).shell.openExternal(‘https://github.com/electron/electron‘)

在 Electron 中,通信主要发生在主进程和渲染进程之间。

ipcRenderer 和 ipcMain:

ipcRenderer 模块用于渲染进程(网页)向主进程发送消息。
ipcMain 模块用于主进程接收来自渲染进程的消息,并可以向渲染进程发送消息。

preload 脚本:
使用 preload 脚本可以在渲染进程中安全地访问 Node.js API 或与主进程通信,通过 contextBridge 模块暴露有限的 API 给渲染进程。

下面是一个简单的例子展示如何使用 ipcRenderer 和 ipcMain 进行通信:

主进程代码

1
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
const { app, BrowserWindow, ipcMain } = require('electron')

app.whenReady().then(() => {
const mainWindow = new BrowserWindow({
webPreferences: {
preload: path.join(__dirname, 'preload.js'),
nodeIntegration: false,
contextIsolation: true
}
})

mainWindow.loadURL('https://example.com')
})

// 监听来自渲染进程的消息
ipcMain.on('message-from-renderer', (event, args) => {
console.log(args) // 打印渲染进程传递的数据
event.reply('response-to-renderer', '这是来自主进程的回复')
})

渲染进程代码 (通过 preload 脚本)

// preload.js
const { contextBridge, ipcRenderer } = require('electron')

contextBridge.exposeInMainWorld('electronAPI', {
sendMessageToMain: (message) => ipcRenderer.send('message-from-renderer', message),
receiveMessageFromMain: (callback) => ipcRenderer.on('response-to-renderer', callback)
})

// 在渲染进程中使用
window.electronAPI.sendMessageToMain('你好,主进程!')
window.electronAPI.receiveMessageFromMain((event, response) => {
console.log(response) // 打印主进程的回复
})

electron 和 iframe 的通信

渲染进程与 iframe 之间的通信

1
2
3
4
5
6
7
8
9
10
// 发送消息到 iframe
const iframe = document.getElementById('myIframe');
iframe.contentWindow.postMessage('你好,iframe!', '*');

// 监听来自 iframe 的消息
window.addEventListener('message', (event) => {
if (event.origin !== 'http://example.com') return; // 确保消息来源安全
console.log('来自 iframe 的消息:', event.data);
});

iframe 内部的脚本

1
2
3
4
5
6
7
8
9
// 监听来自父窗口的消息
window.addEventListener('message', (event) => {
if (event.origin !== 'http://parent-window-origin.com') return; // 确保消息来源安全
console.log('来自父窗口的消息:', event.data);

// 发送消息回父窗口
event.source.postMessage('你好,父窗口!', event.origin);
});

主进程与 iframe 之间的通信

由于 iframe 是渲染进程的一部分,主进程不能直接与 iframe 通信。但是,可以通过渲染进程作为桥梁来实现主进程与 iframe 之间的通信。

1
2
3
4
5
6
7
8
9
10
11
12
主进程


const { ipcMain } = require('electron');

// 监听来自渲染进程的消息
ipcMain.on('message-from-renderer', (event, args) => {
console.log('来自渲染进程的消息:', args);
// 将消息转发给 iframe
event.reply('forward-to-iframe', '这是来自主进程的消息');
});

渲染进程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

const { ipcRenderer } = require('electron');

// 发送消息到主进程
ipcRenderer.send('message-from-renderer', '你好,主进程!');

// 监听来自主进程的消息,并转发给 iframe
ipcRenderer.on('forward-to-iframe', (event, message) => {
const iframe = document.getElementById('myIframe');
iframe.contentWindow.postMessage(message, '*');
});

// 监听来自 iframe 的消息,并发送到主进程
window.addEventListener('message', (event) => {
if (event.origin !== 'http://example.com') return; // 确保消息来源安全
ipcRenderer.send('message-from-iframe', event.data);
});

iframe 内部的脚本

1
2
3
4
5
6
7
8
9
10

// 监听来自父窗口的消息
window.addEventListener('message', (event) => {
if (event.origin !== 'http://parent-window-origin.com') return; // 确保消息来源安全
console.log('来自父窗口的消息:', event.data);

// 发送消息回父窗口
event.source.postMessage('你好,父窗口!', event.origin);
});

主进程与渲染进程之间的通信 的使用场景

渲染进程需要读取或写入文件系统中的文件。
主进程具有更高的权限,可以直接访问文件系统。
渲染进程需要打开文件选择对话框、保存文件对话框等。
主进程可以更方便地调用 Electron 提供的对话框 API。
渲染进程需要发起网络请求,但可能需要使用 Electron 提供的特定功能或需要更高的权限。
主进程可以处理网络请求并返回结果。
渲染进程需要通知主进程执行某些操作,如退出应用、重启应用等。

1
2
3
4
5
6
const { ipcMain, app } = require('electron');

ipcMain.on('quit-app', () => {
app.quit();
});

demo 项目

克隆 https://github.com/zxwk1998/vue-admin-better.git

1
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
修改 index.html

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<!-- https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP -->
<!-- <meta http-equiv="Content-Security-Policy" content="default-src 'self'; frame-src http://localhost:8000/demo/"> -->
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; frame-src http://localhost:8001/demo/; style-src 'self'">

<!-- <meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'"> -->
<link href="./styles.css" rel="stylesheet">
<title>Hello World!</title>
</head>
<body>
<a href="http://localhost:8001/demo/">跳转</a>

<iframe src="http://localhost:8001/demo/" frameborder="0" class="my-iframe" sandbox='allow-scripts allow-same-origin'></iframe>


<!-- <h1>Hello World!</h1>
We are using Node.js <span id="node-version"></span>,
Chromium <span id="chrome-version"></span>,
and Electron <span id="electron-version"></span>. -->

<!-- You can also require other files to run in this process -->
<script src="./renderer.js"></script>
</body>
</html>


iframe 集成 ruoyi-vue 项目 点击登录不能跳转

发现cookie没有写上

1
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

修改 auth.js 替换 Cookies 为 localStorage

import Cookies from 'js-cookie'

const TokenKey = 'Admin-Token'

export function getToken() {
return Cookies.get(TokenKey)
}

export function setToken(token) {
return Cookies.set(TokenKey, token)
}

export function removeToken() {
return Cookies.remove(TokenKey)
}

改为:

// import Cookies from 'js-cookie'

const TokenKey = 'Admin-Token'

export function getToken() {
return localStorage.getItem(TokenKey)
}

export function setToken(token) {
return localStorage.setItem(TokenKey, token)
}

export function removeToken() {
return localStorage.removeItem(TokenKey)
}


打包配置

1
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
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
package.json 修改


{
"name": "electron-quick-start",
"version": "1.0.0",
"description": "A minimal Electron application",
"main": "main.js",
"scripts": {
"start": "electron .",
"build": "electron-builder"
},
"repository": "https://github.com/electron/electron-quick-start",
"keywords": [
"Electron",
"quick",
"start",
"tutorial",
"demo"
],
"author": {
"name": "Your Name",
"email": "your.email@example.com"
},
"license": "CC0-1.0",
"devDependencies": {
"electron": "^33.2.1",
"electron-builder": "^23.6.0"
},
"build": {
"appId": "com.example.electronquickstart",
"productName": "ElectronQuickStart",
"directories": {
"output": "build"
},
"files": [
"main.js",
"index.html",
"renderer.js",
"styles.css",
"preload.js",
"package.json"
],
"icon": "build/icons/icon",
"win": {
"target": [
{
"target": "nsis"
}
]
},
"mac": {
"target": [
{
"target": "dmg"
}
]
},
"linux": {
"target": [
{
"target": "deb"
},
{
"target": "AppImage"
}
],
"maintainer": "Your Name <your.email@example.com>"
}
}
}

上述代码在 ubuntu 上构建出 deb 和 AppImage 两种格式的应用程序。

对于不同的目标平台,需要在各个目标平台下构建

macOS (dmg): 需要在 macOS 上进行构建。
Windows (nsis): 需要在 Windows 上进行构建,或者使用 Wine 在 Linux 上进行构建。

参考:
https://blog.csdn.net/weixin_52799373/article/details/131513974

https://github.com/wangzhiwei1888/remote_electron

https://github.com/OblivionTime/remoteShell