Electron神器

517 阅读4分钟

神奇的Electron

前言

今天通过技术核心、发展历程、常用模块三部分内容简单的介绍一下Electron的身世。

技术核心

使用 JavaScript,HTML 和 CSS 构建跨平台的桌面应用程序的开源架构

1. Web技术

  • Electron 基于 Chromium 和 Node.js, 让你可以使用前端技术构建应用。
  • Electron = Chromium + Node.js + Native API

2. 开源

  • Electron 是一个由 GitHub 及众多贡献者组成的活跃社区共同维护的开源项目。

3. 跨平台

  • Electron 兼容 Mac、Windows 和 Linux,可以构建出三个平台的应用程序。
  • macOS: 仅提供64位版本,并且只支持 macOS 10.10 (Yosemite) 以及更高版本。

  • Windows: 仅支持 Windows 7 或更高版本, 旧版操作系统已不再支持(并且无法运行),提供了 ia32 (x86) 和 x64 (amd64) 两种二进制版本。

  • Linux:支持 Ubuntu 12.04、Fedora 21、Debian 8 及以上版本。Electron 的 ia32 (i686) 和 x64 (amd64) 预编译版本均是在Ubuntu 12.04 下编译的。

发展历程

  • 2013年4月11日,Electron以Atom Shell为名起步。
  • 2014年5月6日,Atom以及Atom Shell以MIT许可证开源。
  • 2015年4月17日,Atom Shell改名为Electron。
  • 2016年5月11日,1.0版本发布。
  • 2016年5月20日,允许向Mac应用商店提交软件包。
  • 2016年8月2日,支持Windows商店。
  • 2018年,2.0版本(5月2日),3.0版本(9月19日),4.0版本(12月21日)发布。
  • 2019年,5.0版本(4月25日),6.0版本(7月30日),7.0版本(10月22日)发布。
  • 2020年,8.0版本(2月4日),9.0版本(5月中旬)发布。

进程通讯

1. 主进程和渲染进程

Electron 中的 main.js 文件进程被称为主进程,在主进程中运行的脚本通过创建web页面来展示用户界面。一个 Electron 应用总是有且只有一个主进程。

由于 Electron 使用了 Chromium 来展示 web 页面,所以 Chromium 的多进程架构也被使用到。 每个 Electron 中的 web 页面叫做渲染进程。

在普通的浏览器中,web页面通常在沙盒环境中运行,并且无法访问操作系统的原生资源。 然而 Electron 的用户在 Node.js 的 API 支持下可以在页面中和操作系统进行一些底层交互。

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

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

主进程管理所有的web页面和它们对应的渲染进程。 每个渲染进程都是独立的,它只关心它所运行的 web 页面。

在页面中调用与 GUI 相关的原生 API 是不被允许的,因为在 web 页面里操作原生的 GUI 资源是非常危险的,而且容易造成资源泄露。 如果你想在 web 页面里使用 GUI 操作,其对应的渲染进程必须与主进程进行通讯,请求主进程进行相关的 GUI 操作。

3. 代码实例

  • 同步通讯
    // 渲染进程
    const { ipcRenderer } = require('electron')
    ipcRenderer.sendSync('synchronous-message', 'ping')

    // 主进程
    const { ipcMain } = require('electron')
    ipcMain.on('synchronous-message', (event, arg) => {
        console.log(arg) 
        event.returnValue = 'pong'
    })
  • 异步通讯
    // 渲染进程
    const { ipcRenderer } = require('electron')
    ipcRenderer.send('asynchronous-message', '我需要创建一个新窗口')

    // 主进程
    const { ipcMain } = require('electron')
    ipcMain.on('asynchronous-message', (event, arg) => {
        console.log(arg) 
        event.reply('asynchronous-reply', '好的,知道了')
    })

    // 渲染进程
    ipcRenderer.on('asynchronous-reply', (event, arg) => {
    	console.log('谢谢');
    })

常用模块

app

  • 代码举例
const { app } = require('electron')
app.on('window-all-closed', () => {
  app.quit()
})

BrowserWindow

  • 代码举例
const { BrowserWindow } = require('electron')

let win = new BrowserWindow({ width: 800, height: 600 })
win.on('closed', () => {
  win = null
})

win.loadURL('https://github.com')

dialog

  • 代码举例
const { dialog } = require('electron') 

dialog.showMessageBox(mainWindow, {
            type: 'info',
            defaultId: 0,
            message: '您是否确定现在退出?',
            buttons: ['退出','取消']
        })

Menu

  • 代码举例
const { Menu, MenuItem } = require('electron')

const menu = new Menu()
menu.append(new MenuItem({ label: 'MenuItem1', click() { console.log('item 1 clicked') } }))
menu.append(new MenuItem({ type: 'separator' }))
menu.append(new MenuItem({ label: 'MenuItem2', type: 'checkbox', checked: true }))

desktopCapturer

  • 代码举例
// In the renderer process.
const { desktopCapturer } = require('electron')

desktopCapturer.getSources({ types: ['window', 'screen'] }).then(async sources => {
  for (const source of sources) {
    if (source.name === 'Electron') {
      try {
        const stream = await navigator.mediaDevices.getUserMedia({
          audio: false,
          video: {
            mandatory: {
              chromeMediaSource: 'desktop',
              chromeMediaSourceId: source.id,
              minWidth: 1280,
              maxWidth: 1280,
              minHeight: 720,
              maxHeight: 720
            }
          }
        })
        handleStream(stream)
      } catch (e) {
        handleError(e)
      }
      return
    }
  }
})

function handleStream (stream) {
  const video = document.querySelector('video')
  video.srcObject = stream
  video.onloadedmetadata = (e) => video.play()
}

function handleError (e) {
  console.log(e)
}

clipboard

  • 代码举例
const { clipboard } = require('electron')

clipboard.writeText('hello i am a bit of text!')

const text = clipboard.readText()
console.log(text)
// hello i am a bit of text!'

参考资料