美文网首页
electron 初步学习

electron 初步学习

作者: 南土酱 | 来源:发表于2023-12-10 16:01 被阅读0次

    原理

    Electron通过将Chromium和Node.js合并到同⼀个运⾏时环境中,并将其打包为Mac, Windows和Linux系统下的应⽤来实现这⼀⽬的。

    Electron本质就是提供了一个浏览器的壳子,用于运行我们的web应用。

    目前浏览器采用多线程架构:

    其中:

    • 浏览器主进程,实现浏览器的主要UI、负责和文件、网络等等操作系统底层接口对接通信。

    • 渲染进程,每一个tab独立开一个渲染进程,核心进行web代码解析和渲染工作。

    • 插件进程,负责浏览器插件的控制。

    • GPU进程,独立的进程负责处理GPU图像的渲染绘制。

    这样设计架构的好处主要有两个:

    1. 保证每个tab独立进程,这样在某一个页面crash的时候,仅仅影响当前的Tab,而不至于让整个浏览器崩溃。这提升了软件的健壮性和用户体验。

    2. 有利于实现沙箱隔离的安全机制,基于进程可以很方便地控制不同页面之间的安全访问策略,确保每个renderer进程在自己单独的沙箱环境内安全地运行。

    Electron本身参考了这个架构的实现,将各个GUI窗口通过renderer进程实现,交由chromium来加载渲染,主进程集成Node.js,负责与系统API交互,处理核心事务。

    技术集成

    Electron是一个集成项目,允许开发者使用前端技术开发桌面端应用。它做了如下几个重要的工作:

    1. 定制 Chromium,并把定制版本的 Chromium 集成在 Electron 内部;

    2. 定制 Node.js,并把定制版本的 Node.js 集成在 Electron 内部;

    3. 通过消息轮询机智打通 Node.js 和 Chromium 的消息循环;

    4. 通过 electron 的内置模块向开发者提供桌面应用开发必备的API;

    其中Chromium 基础能力可以让应用渲染HTML(CSS)页面,可以执行页面的JavaScript脚 本,让应用可以在Cookie、LocalStorage或IndexedDB 中存取数据。除此之外,Electron还允许 开发者突破同源策略的限制:伪装请求,截获响应,修改session等。

    Node.js 基础能力可以让开发者读写本地磁盘的文件、通过socket访问网络、创建和控制子进程等。除此之外,还修改了Node的加解密机制让Chromium的BoringSSL和Node的OpenSSL兼容的 更好,让Node.js可以加载asar压缩包内的文件等。

    Electron 内置模块可以让开发者创建操作系统的托盘图标、访问操作系统的剪切板、屏幕信息、发送系统通知等,除此之外还提供了崩溃报告收集能力、性能问题追踪能力等。

    另外,Electron继承了Chromium的多进程架构Q,也是分一个主进程多个渲染进程的。

    大致目录

    Electron
    ├── build/ - 构建相关
    ├── buildflags/ - feature flag
    ├── chromium_src/ - chromium的一份拷贝(源码仅包含build文件)
    ├── default_app/ - 默认启动时的app程序
    ├── docs/ -文档
    ├── lib/ - 使用JS/TS编写的模块
    |   ├── browser/ - 主进程初始化相关
    |   |   ├── api/ - 主进程暴露的API,通过_linkedBinding调用C++模块
    |   ├── common/ - 主进程和渲染进程共用代码
    |   |   └── api/ - 主进程和渲染进程共同暴露的API
    |   ├── renderer/ - 渲染进程初始化相关
    |   |   ├── api/ - 渲染进程API
    |   |   └── web-view/ - webview相关逻辑
    ├── patches/ - 关于依赖的一些patch,主要是chromium、node、v8的
    ├── shell/ - C++编写的模块
    |   ├── app/ - 入口
    |   ├── browser/ - 主进程相关
    |   |   ├── ui/ - 系统UI组件的一些实现
    |   |   ├── api/ - 主进程API实现
    |   |   ├── net/ - 网络相关实现
    |   |   ├── mac/ - Mac系统下的一些实现(OC实现)
    |   ├── renderer/ - 渲染进程相关
    |   |   └── api/ - 渲染进程API实现
    |   └── common/ - 主进程渲染进程通用实现
    |       └── api/ - 主进程渲染进程通用API实现
    └── BUILD.gn - 构建入口
    

    进程

    主进程

    每个 Electron 应用都有一个单一的主进程,作为应用程序的入口点。 主进程在 Node.js 环境中运行,这意味着它具有 require 模块和使用所有 Node.js API 的能力。

    Electron 中,启动项目时运行的 main.js 脚本就是我们说的主进程。在主进程运行的脚本可以以创建 web 页面的形式展示 GUI

    一个 Electron 应用有且只有一个主进程。并且创建窗口等所有系统事件都要在主进程中进行。

    窗口管理

    主进程的主要目的是使用 [BrowserWindow](https://link.juejin.cn/?target=https%3A%2F%2Fwww.electronjs.org%2Fzh%2Fdocs%2Flatest%2Fapi%2Fbrowser-window) 模块创建和管理应用程序窗口。

    渲染器进程

    每个 Electron 应用都会为每个打开的 BrowserWindow ( 与每个网页嵌入 ) 生成一个单独的渲染器进程。 洽如其名,渲染器负责 渲染 网页内容。 所以实际上,运行于渲染器进程中的代码是须遵照网页标准的。

    这也意味着渲染器无权直接访问 require 或其他 Node.js API。 为了在渲染器中直接包含 NPM 模块,您必须使用与在 web 开发時相同的打包工具 (例如 webpackparcel)。

    主进程和渲染进程之间的区别

    主进程使用 BrowserWindow 实例创建网页。每个 BrowserWindow 实例都在自己的渲染进程中运行。当一个 BrowserWindow 实例被销毁后,相应的渲染进程也会被终止。

    主进程管理所有页面和与之对应的渲染进程。每个渲染进程都是相互独立的,并且只关心他们自己的网页。

    主进程和渲染进程之间通信

    Electron 的主进程是在后台运行,对应 main.js 文件。而渲染进程是前端看到的,对应 index.html 文件。这个两个进程之间的通信首选 ipc 方式,因为它会在完成时返回,而不会阻止同一进程中的其他操作。

    1. LocalStorage, window.postMessage

    在前端开发中,鉴于浏览器对本地数据有严格的访问限制,所以一般通过该两种方式进行窗口间的数据通讯,该方式同样适用于 Electron 开发中。然而因为 API 设计目的仅仅是为了前端窗口间简单的数据传输,大量以及频繁的数据通讯会导致应用结构松散,同时传输效率也值得怀疑。

    1. IPC (Inner-Process Communication)

    Electron 中提供了 ipcRenderipcMain 作为主进程以及渲染进程间通讯的桥梁,该方式属于 Electron 特有传输方式,不适用于其他前端开发场景。Electron 沿用 Chromium 中的 IPC 方式,不同于 socket、http 等通讯方式,Chromium 使用的是命名管道 IPC ,能够提供更高的效率以及安全性。

    渲染进程发异步消息给主进程

    // 渲染进程脚本
    const { ipcRenderer } = require('electron')
    // 发送异步消息
    btns[0].addEventListener('click', () => {
        ipcRenderer.send('msg1', '这是一条来自于异步的消息')
    })
    // 监听消息
    ipcRenderer.on('msg1Re', (ev, data) => {
        console.info(data)
    })
    // 主进程脚本
    const { ipcMain } = require('electron')
    ipcMain.on('msg1', (ev, data) => {
        console.info(data)
        // 发送消息给渲染进程
        ev.sender.send('msg1Re', '这是一条来自主进程的反馈消息')
    })
    

    渲染进程发同步消息给主进程

    // 渲染进程脚本
    const { ipcRenderer } = require('electron')
    // 发送同步消息
    btns[1].addEventListener('click', () => {
        const result = ipcRenderer.sendSync('msg2', '这是一条来自于同步的消息')
        console.info(result)
    })
    // 主进程脚本
    const { ipcMain } = require('electron')
    ipcMain.on('msg2', (ev, data) => {
        console.info(data)
        // 反馈消息
        ev.returnValue = '这是一条来自主进程的同步反馈消息'
    })
    

    主进程发消息给渲染进程

    // 主线程脚本
    BrowserWindow.getFocusedWindow().webContents.send(
        'mtp',
        '主进程发送消息给渲染进程'
    )
    // 渲染进程脚本
    ipcRenderer.on('mtp', (ev, data) => {
        console.info(data)
    })
    

    渲染进程间通信

    基于本地存储的渲染进程间通信

    即采用 localStorage 机制

    借助主进程,进行不同渲染进程间的通信
    // 发起消息的渲染进程
    ipcRenderer.send('mti', '这是条来自于 modal 的消息')
    // 主进程
    ipcMain.on('mti', (ev, data) => {
        // 通过 id 获取到对应的渲染进程,然后消息传递
        BrowserWindow.fromId(mainId).webContents.send('mti2', data)
    })
    // 接收消息的渲染进程 
    ipcRenderer.on('mti2', (ev, data) => {
            console.info(data)
    })
    
    使用 sendTo

    前提是要知道另一渲染窗口的 webContents 对应的 id 这边采用 global 存储窗口 ID

      const modalMain = new BrowserWindow({
              width: 200,
            height: 200,
            parent: BrowserWindow.fromId(mainId), // 这样关闭父窗口,则子窗口会一并关闭
            webPreferences: {
                    nodeIntegration: true,
                    contextIsolation: false
            }
      })
      global.sharedObject =  {
        modalMainWebContentsId: modalMain.webContents.id
      }
    

    然后在渲染进程里通过 getGlobal 来获取该 ID 值,并通过 sendTo 来发送消息

    let sharedObject = getGlobal('sharedObject') 
    let modalMainWebContentsId = sharedObject.modalMainWebContentsId
    ipcRenderer.sendTo(modalMainWebContentsId, 'do-some-work', 1)
    

    这样其他渲染进程就通过监听 do-some-work 来获取消息

    ipcRenderer.on('do-some-work', (e, data) => {
        console.info(data)
      })
    

    实践

    参看教程:

    无vite版本:https://juejin.cn/post/6983843979133468708

    vite版本: https://blog.csdn.net/yanxinyun1990/article/details/130944508

    相关文章

      网友评论

          本文标题:electron 初步学习

          本文链接:https://www.haomeiwen.com/subject/apkpgdtx.html