💎一站式轻松地调用各大LLM模型接口,支持GPT4、智谱、星火、月之暗面及文生图 广告
[TOC] # 安装 ``` ELECTRON_MIRROR="https://cdn.npm.taobao.org/dist/electron/" npm install // mac 命令行下 ``` > [tutorial/installation](https://www.electronjs.org/docs/tutorial/installation) # Electron 架构 ![](https://img.kancloud.cn/4d/ca/4dcadc9c8d5e7ecba05361beef75d577_1760x1360.png) ![](https://img.kancloud.cn/d3/2d/d32d17855568aaf0a5ea059461bd26c4_689x768.png) > [Electron:PC 端多端融合方案](https://segmentfault.com/a/1190000022543101) # 基础 一个 Electron 应用总是有且只有一个主进程。 每个`electron`中的 web 页面 运行在它自己的渲染进程中 每个`BrowserWindow`实例都在自己的渲染进程里运行页面 nodejs 在主进程和渲染进程中都可以使用。渲染进程因为安全限制,不能直接操作原生 GUI。 # 右键菜单 ~~~ /* *给窗口加事件 */ window.addEventListener('contextmenu', (e) => { e.preventDefault(); //阻止默认事件 var rightM = Menu.buildFromTemplate([ {label:'返回'}, {label:'前进'}, {label:'重新加载'}, {type:'separator'}, {label:'存储为...'}, {label:'打印...'}, {label:'投射...'}, {label:'翻译成中文(简体)'}, {type:'separator'}, {label:'查看网页源代码'}, {label:'检查'}, ]); rightM.popup({window: remote.getCurrentWindow()}); }, false); ~~~ # 主进程 ## session 管理浏览器会话,Cookie,缓存,代理设置等。 ## webContents `webContents`是一个[EventEmitter](https://nodejs.org/api/events.html#events_class_eventemitter)。 它负责渲染并控制BrowserWindow实例的内容,并且是该`BrowserWindow`对象的属性。 ## contentTracing 从Chromium的内容模块收集跟踪数据,以查找性能瓶颈和缓慢的操作。 # 渲染进程模块 主进程模块就不介绍了,渲染模块之外或者部分都在主进程模块可用~ ## shell 用来操作本地文件 ## clipboard ## crashReporter 将崩溃报告提交给远程服务器,要搭建专用的服务器 ~~~javascript const {crashReporter} = require('electron') crashReporter.start({ productName: 'YourName', companyName: 'YourCompany', submitURL: 'https://your-domain.com/url-to-submit', uploadToServer: true }) ~~~ > [tencent-Electron 教程](https://cloud.tencent.com/developer/section/1116147) ## nativeImage 使用 PNG 或 JPG 文件创建托盘,底座和应用程序图标。 ## ipcRenderer 渲染进程 ipc 通信的模块 ## remote 可以调用 main 进程对象的方法, 而不必显式发送进程间消息。 1. 给主进程传递回调函数 2. 访问主进程中的内置模块 3. `remote.require(module)` 4. `remote.getCurrentWindow()` -获取主进程的窗体 5. `remote.getCurrentWebContents()` - 获取主进程的 webContent 属性 6. `remote.getGlobal(name)` -用于数据共享。 ~~~ const { dialog } = require('electron').remote dialog.showMessageBox({type: 'info', message: '在渲染进程中直接使用主进程的模块'}) ~~~ ## desktopCapturer 从桌面捕获音频和视频的媒体源的信息 ## webFrame 自定义当前网页的呈现。 ## contextBridge ![核心模块](https://img.kancloud.cn/ee/e8/eee8538d2aebd7f2901d450c41c77521_1331x784.png) # 进程间通信 ![](images/screenshot_1594105357343.png) * 自主到从:从 Main 到 Renderer 的消息传递,借助`BrowerWindow.webContents.send()` 向所有渲染进程发送消息。 * 自从到主:从 Renderer 到 Main 的消息传递,借助`ipcRender`和`ipcMain`发送/接收消息。 * 事件机制:无论是`BrowerWindow.webContents.send()`,还是`ipc`,其实都是`node`的事件机制,都是`EventEmitter`的实例。 **** :-: 从渲染进程到主进程 * Callback 写法: * ipcRenderer.send(channel, ...args) * ipcMain.on(channel, handler) * Promise 写法(Electron 7.0 之后,处理请求 + 响应模式): * ipcRenderer.invoke(channel, ...args) * ipcMain.handle(channel, handler) > [主进程与渲染进程/主进程与webview通信](https://dushusir.com/electron-ipcmain-ipcrenderer/) # 通知渲染进程 ~~~ //主进程 const {ipcMain} = require('electron'); /** * 接受渲染进程发送过来的数据 * 使用 event.sender.send() 于渲染进程通信 */ ipcMain.on('msg', (event, data) => { event.sender.send('reply','hi lee my name is yuan, age is 17'); // # 主进程接收到异步消息以后通知渲染进程 console.log(data); }) ~~~ ## 主进程与渲染进程共享数据 [https://www.yuque.com/xiaoershangjiu-mattw/bhgamp/eyzdrz#hw8Jk](https://www.yuque.com/xiaoershangjiu-mattw/bhgamp/eyzdrz#hw8Jk) ## 渲染进程于渲染进程通信 1. 获取当前窗口的 id: ~~~ const winId = BrowserWindow.getFocusedWindow().id; ~~~ 2. 通过 id 查找窗口: ~~~ let win = BrowserWindow.fromId(winId); ~~~ > [渲染进程于渲染进程通信](https://www.kancloud.cn/lihaotian001/electron-01/731073) # preload `electron`渲染进程默认为`nodejs`环境,在里面你可以调用`require`引入第三方模块,但有时候我们想要的是一个真实的浏览器环境。`electron`需要做的配置如下: ``` const mainWindow = new BrowserWindow({ resizable: true, width: size.width, height: size.height, title: 'HolaStudio', webPreferences: { nodeIntegration: false, preload: path.join(__dirname, 'tangide', 'expose-window-apis.js') } }); ``` 创建`BrowserWindow`的时候指定`nodeIntegration`为`false`。 这样在`electron`内置浏览器里面不会有`module`和`require`全局变量。但 preload 文件 `expose-window-apis.js`仍可以访问; preload 脚本文件,会在页面加载资源前就加载执行,保证了页面无论是在什么地方、什么时候调用注入接口都能调用到。 ## 示例 preload 文件 `expose-window-apis.js` 文件的内容: ``` const { BrowserWindow } = require('electron') const path = require('path') const renderProcessApi = path.join(__dirname, './inject.js') let win = new BrowserWindow({ webPreferences: { preload: renderProcessApi } }) ``` `preload.js`是一个特殊且单独的文件,在此文件中可以访问`node模块`、`electron`、`其他node 模块`提供的api,并挂载到`window`对象中,你其他的普通j avascript 代码就可以访问这些 api。 > [在Electron中最快速预加载脚本](https://www.cnblogs.com/lovesong/p/11161293.html) > [Uncaught ReferenceError: require is not defined](https://github.com/electron/electron/issues/9920) # asar [asar 加密打包](https://electronjs.org/docs/tutorial/application-packaging),仅仅是对`resource/app`目录的封装,让人们不是那么容易看到你写的代码结果而已。 安装asar ``` npm install -g asar asar p/pack your-app app.asar // 用 asar pack 打包 asar list xxxxxx.asar // 读取 asar 里面的文件 ``` 从 asar 包读取一个文件: ``` const fs = require('fs'); fs.readFileSync('/path/to/example.asar/file.txt'); ``` 列出 asar 包中根目录下的所有文件: ``` const fs = require('fs'); fs.readdirSync('/path/to/example.asar'); ``` 使用 asar 包中的一个模块: ``` require('/path/to/example.asar/dir/module.js'); ``` 使用 BrowserWindow 来显示一个 asar 包里的 web 页面: ``` const BrowserWindow = require('electron').BrowserWindow; var win = new BrowserWindow({width: 800, height: 600}); win.loadURL('file:///path/to/example.asar/static/index.html'); ``` # 参考 [Electron webview完全指南](http://www.ayqy.net/blog/electron-webview%E5%AE%8C%E5%85%A8%E6%8C%87%E5%8D%97/)