首页文章关于

Electron-handbook

openaigptmodelllm

项目模版

对于electron无论是webpack、vite都需要分别对mainpreloadrenderer进行打包并和chromium、node api生成对应平台应用

  1. electron-forge: 通过其插件系统提供了项目环境、打包分发、包发布、等完整流程,并且具有webpack、vite两种构建可以选择
  2. electron-vite: 以vite为构建方案的不同框架模版

核心API

Main Process

主进程主要提供作用到操作系统的api及事件,通常位于main工程目录下

  • app: 包含了主应用程序事件触发及监听
ts
app.on('window-all-closed', () => {
app.quit();
})
  • BrowserWindow: 主应用窗口相关(配置、页面渲染、调试工具、窗口事及监听)
    • 一个应用可以存在多个窗口但需要指明父级窗口
ts
function createWindow() {
mainWIndow = new BrowserWindow({ /* ... */ })
secondaryWindow = new BrowserWindow({
// ...,
modal: false, // 是否以modal形式展示
show: false, // modal为true时生效
parent: mainWindow
});
}
  • webContents: 作为BrowserWindow的属性(对应的配置也将反映到属性当中)用于响应和控制web页面的事件触发及监听
    • mainWindow.webContents
ts
const wc = mmainWindow.webContents;
wc.on('did-finish-load', () => {})
wc.on('dom-ready', () => {})
wc.on('focus', () => {})
// ...
ts
globalShortcut.register('CommandOrControl+Shift+Alt+C', () => {
app.focus();
browserWindow.show();
browserWindow.focus();
});
  • Menu: 菜单相关配置(Menu、MenuItem、context-menu)
ts
const mainMenu = new Menu();
const menuItem = new MenuIitem({ label: 'File': subMenu: [/**/] })
mainMenu.append(menuItem)
Menu.setApplicationMenu(mainMenu)
const contextMenu = Menu.buildFromTemplate({ label: 'xxx', subMenu: [/**/]})
mainWindow.webContents.on('context-menu', e => contextMenu.popup())
  • Tray: 系统托盘图标菜单配置
ts
const someTray = new Tray('xxx/xxx/icon.png')
someTray.setToolTip('hover tip text')
someTray.on('click', e => {
// do something
})
  • screen: 屏幕相关事件及方法(尺寸、显示、光标位置)
ts
const [dp1, dp2] = screen.getAllDisplays()
console.log(`
primary monitor: ${dp1.size.width}x${dp1.size.height}\n
srcondary monitor: ${dp2.size.width}x${dp2.size.height}`
)
screen.on('display-metrics-changed', (e, display, metricsChanged) => {
console.log(metricsChanged)
})

Renderer Process

渲染进程主要包含mainwindow中渲染的web相关页面及资源,通常位于renderer工程目录下.新版本不能直接在渲染进程中使用必须通过preload桥接

  • clipboard: 系统粘贴板相关
  • contextBridge: 通过ipcRenderer通信暴露桥接主线程与渲染线程的事件,通常位于preload
  • crashRepoeter: 自动提交崩溃报告到远端服务器
  • ipcRenderer: 用于主进程和渲染进程之间监听和派发约定事件
  • webFrame: 用于自定义渲染当前的web页面(zooom、insertCSS、insetText、executeJavascript、...)
  • desktopCapturer: 桌面音视频捕捉

IPC(inter-process communication)

IPC主要用于ipcMainipcRenderer之间的通信

  • Renderer to main: 渲染进程到主进程,出了send > on这种通用订阅方式还有invoke > handle的异步返回方式
ts
import { contextBridge, ipcMain, ipcRenderer } from "electron"
// main.ts
ipcMain.on('someContent', (e, content: string) => console.log(content))
ipcMain.handle('otherContent', async (e, content: string) => dealWithContent(content))
// preload.ts
contextBridge.exposeInMainWorld('app', {
sendToMain: (content: string) => {
ipcRenderer.send('someContent', content)
},
otherToMain: async (content: stirng) => {
const result = await ipcRenderer.invoke('otherContent')
return result
}
})
// renderer/index.ts
document.getElementById('dom1').onclick = () => {
window.app.sendToMain()
}
document.getElementById('dom2').onclick = () => {
window.app.otherToMain()
}
  • Main to renderer: 主进程到渲染进程除了send > on以外的webContents方式
ts
import { BrowserWindow, ipcMain, ipcRenderer } from "electron"
// main.ts
const mainWindow = new BrowserWindow(/* ... */)
Menu.buildFromTemplate([
{
label: 'xxx'
subMenu: [
{
label: 'xxx',
click: () => mainWindow.webContents.send('updateSomething', 'xxx')
},
// ...
]
}
])
// preload.ts
// 这里可以不暴露到renderer中,直接定义在preload中
window.addEventListener('DOMContentLoaded', () => {
const contentDom = document.getElementById('dom')
ipcRenderer.on('updateSomthing', (_event, content) => {
contentDom.innerText = content
})
})
// index.html
<body>
<div id="dom">/* ... */</div>
</body>
<script type="module" src="renderer/index.ts">

Shared Modules

  • process: 包含了可以在主、渲染进程中访问使用的属性、方法、事件
  • shell: 包含了与桌面集成相关的功能(openPathshowItemInFolder、...,不同操作系统的表现也不相同)
  • nativeImage: 图片相关api可以通过本机路径、nativeImage实例创建并包含很多图片实例方法(toPNGtoJPEGtoDataURL、...)
  • clipboard: 粘贴板相关功能

扩展功能

  • Offsreen Rendering: 使用禁止硬件加速开启离屏渲染(不渲染页面的情况下进行逻辑处理)
ts
import { app, BrowserWindow } from "electron"
app.disableHardwareAcceleration()
const mainWindow = new BrowserWindow({
show: false,
webPreferences: {
nodeIntegration: true,
offscreen: true
}
}})
mainWindow.loadURL('https://electronjs.org')
let i = 1
mainWindow.webContents.on('paint', (e, dirty, image) => {
fs.writeFile(app.getPath('desktop') + `/screenshot_${i}`, image.toPNG(), console.log)
i++;
})
mainWindow.webContents.on('did-finish-load', () => {
// ...
})
Copyright © 2023, Daily learning records and sharing. Build by