项目目录
- 通信方面
- app/main 下有 ipc.js 和 signal.js
- ipc 负责主进程和渲染进程的通信
- signal 负责客户端与 server的 ws 服务的通信
- client 与 server 建立 ws 服务,每次 ws.on('message')时,signal.emit 把信息发射出去(singal 是一个 EventEmitter 实例)
- 在 ipc 中 ,把 signal.on(对应的事件) 再去给渲染进程通知(通过主进程 win.webContents.send(channel, ...args))
- app/main 下有 ipc.js 和 signal.js
├── app // 主入口
│ ├── main
│ │ ├── crash-reporter.js
│ │ ├── index.js
│ │ ├── ipc.js // ipc通信
│ │ ├── robot.js
│ │ ├── signal.js // 信令通信
│ │ ├── trayAndMenu // 托盘
│ │ │ ├── darwin.js
│ │ │ ├── icon_darwin.png
│ │ │ ├── icon_darwin@2x.png
│ │ │ ├── icon_win32.png
│ │ │ ├── icon_win32@2x.png
│ │ │ ├── index.js
│ │ │ └── win32.js
│ │ ├── updater.js
│ │ └── windows // 窗口
│ │ ├── about.js // 关于窗口
│ │ ├── control.js // 控制窗口
│ │ ├── icon.png
│ │ └── main.js // 傀儡窗口
│ └── renderer // view
│ ├── pages
│ │ ├── control // 控制端 view
│ │ │ ├── app.js
│ │ │ ├── index.html
│ │ │ └── peer-control.js // 控制端主逻辑
│ │ └── main // 打包后的产物,忽略!
│ │ ├── asset-manifest.json
│ │ ├── favicon.ico
│ │ ├── index.html
│ │ ├── logo192.png
│ │ ├── logo512.png
│ │ ├── manifest.json
│ │ ├── robots.txt
│ │ └── static
│ └── src // 傀儡端代码,用的cra
│ └── main
│ ├── README.md
│ ├── build.js
│ ├── config-overrides.js
│ ├── package-lock.json
│ ├── package.json
│ ├── pnpm-lock.yaml
│ ├── public
│ └── src // 傀儡端主逻辑
├── build // 打包后的
│ └── config.gypi
├── package.json
├── pnpm-lock.yaml
├── resources // 打包需要的资源
│ ├── background.png
│ ├── background@2x.png
│ ├── icon.icns
│ ├── icon.ico
│ └── icon.png
└── robot_test.js
进程间通信
- 单向 ipcMain.on , ipcRenderer.send
- 双向 ipcMain.handle , ipcRenderer.invoke , 渲染进程执行 invoke 可以拿到主进程执行的结果的回调,在执行逻辑
- 主进程通过 mainWindow.webContents.send 向对应的渲染进程发信息;ipcRenderer.on
- 主进程,与主进程通信。因为 ipcMain是一个 Emitter 的实例,可以直接使用 ipcMain.emit 和 ipcMain.on 通信
注意,electron 的上下文是隔离的,也就是 预加载脚本和Electron的内部逻辑运行,和所加载的 webContent网页 之间,是独立的上下文;所以在 Renderer 进程中,不能直接使用 ipcRenderer.on 一个事件
- 解决办法2个:
- 第一个方法:是在 creatWindow 的时候,修改属性
webPreferences:{
nodeIntegration:true,
contextIsolation:false // 上下文隔离环境取消,默认是true,为了安全
}
- 第二个方法:在 preLoader.js 中,显式的暴露出要调用的 api,在 renderer在中使用
// main.js
const mainWindow = new BrowserWindow({
webPreferences: {
preload: path.join(__dirname, 'preload.js')
}
})
// preload.js
const { contextBridge, ipcRenderer } = require('electron')
contextBridge.exposeInMainWorld('electronAPI', {
setTitle: (title) => ipcRenderer.send('set-title', title)
})
// renderer.js
const setButton = document.getElementById('btn')
const titleInput = document.getElementById('title')
setButton.addEventListener('click', () => {
const title = titleInput.value
window.electronAPI.setTitle(title)
});
IPC回顾
- 渲染进程请求 + 主进程响应 (获取自己的控制码) ipcRenderer.invoke + ipcMain.handle
- 主进程推送(告知状态),webContents.send + ipcRenderer.on
- 渲染进程发起请求 (申请控制), ipcRenderer.send + ipcMain.on
其他
react 项目中支持 electron 模块
方法一 使用 window.require 加载
- 在 doc 项目中有叙述,略过
方法二 cra 项目,修改webpack配置,支持识别 electron 环境的依赖
- 如 在renderer 页面中直接使用
import { ipcRenderer } from 'electron'
- 安装
- "customize-cra": "^1.0.0",
- "react-app-rewired": "^2.2.1"
- 新增覆盖文件
- config-overrides.js
const { override } = require('customize-cra');
function addRendererTarget(config) {
config.target = 'electron-renderer'
return config
}
module.exports = override(addRendererTarget)
- 修改脚本,用 react-app-rewired 启动
"scripts": {
"start": "BROWSER=none react-app-rewired start",
},