跳转至主要内容

从 Electron 中的原生到 JavaScript

·4 分钟阅读

Electron 用 C++ 或 Objective-C 编写的功能如何到达 JavaScript,以便最终用户可以使用它们?


背景

Electron 是一个 JavaScript 平台,其主要目的是降低开发人员构建强大的桌面应用程序的门槛,而无需担心特定于平台的实现。然而,在其核心,Electron 本身仍然需要用给定的系统语言编写特定于平台的功能。

实际上,Electron 为您处理原生代码,以便您可以专注于单个 JavaScript API。

但这又是如何工作的呢?Electron 用 C++ 或 Objective-C 编写的功能如何到达 JavaScript,以便最终用户可以使用它们?

要追踪此路径,让我们从 app 模块开始。

通过打开我们 lib/ 目录中的 app.ts 文件,您会在顶部找到以下代码行

const binding = process.electronBinding('app');

此行直接指向 Electron 将其 C++/Objective-C 模块绑定到 JavaScript 以供开发人员使用的机制。此函数由 ElectronBindings 类的标头和 实现文件创建。

process.electronBinding

这些文件添加了 process.electronBinding 函数,该函数的行为类似于 Node.js 的 process.bindingprocess.binding 是 Node.js 的 require() 方法的较低级别实现,只是它允许用户 require 原生代码而不是用 JS 编写的其他代码。此自定义 process.electronBinding 函数赋予了从 Electron 加载原生代码的能力。

当顶层 JavaScript 模块(如 app)需要此原生代码时,如何确定和设置该原生代码的状态?方法在哪里暴露给 JavaScript?属性呢?

native_mate

目前,可以在 native_mate 中找到此问题的答案:它是 Chromium 的 gin的一个分支,它使在 C++ 和 JavaScript 之间编组类型变得更容易。

native_mate/native_mate 中,有一个用于 object_template_builder 的标头和实现文件。这使我们能够在原生代码中形成模块,其形状符合 JavaScript 开发人员的预期。

mate::ObjectTemplateBuilder

如果我们把每个 Electron 模块都看作一个 object,就更容易理解为什么我们要使用 object_template_builder 来构造它们。这个类构建在 V8 公开的一个类之上,V8 是谷歌用 C++ 编写的开源高性能 JavaScript 和 WebAssembly 引擎。V8 实现了 JavaScript (ECMAScript) 规范,因此其原生功能实现可以直接与 JavaScript 中的实现相关联。例如,v8::ObjectTemplate 为我们提供了没有专用构造函数和原型的 JavaScript 对象。它使用 Object[.prototype],在 JavaScript 中相当于 Object.create()

要查看此操作,请查看 app 模块的实现文件 atom_api_app.cc。底部是以下内容

mate::ObjectTemplateBuilder(isolate, prototype->PrototypeTemplate())
.SetMethod("getGPUInfo", &App::GetGPUInfo)

在上面的行中,.SetMethodmate::ObjectTemplateBuilder 上调用。.SetMethod 可以在 ObjectTemplateBuilder 类的任何实例上调用,以在 JavaScript 中的 Object 原型上设置方法,语法如下

.SetMethod("method_name", &function_to_bind)

这相当于 JavaScript 的

function App{}
App.prototype.getGPUInfo = function () {
// implementation here
}

此类还包含在模块上设置属性的函数

.SetProperty("property_name", &getter_function_to_bind)

.SetProperty("property_name", &getter_function_to_bind, &setter_function_to_bind)

这些将依次是 Object.defineProperty 的 JavaScript 实现

function App {}
Object.defineProperty(App.prototype, 'myProperty', {
get() {
return _myProperty
}
})

function App {}
Object.defineProperty(App.prototype, 'myProperty', {
get() {
return _myProperty
}
set(newPropertyValue) {
_myProperty = newPropertyValue
}
})

可以创建具有原型和属性的 JavaScript 对象,正如开发人员所期望的那样,并且可以更清晰地推理在此较低系统级别实现的功能和属性!

关于在何处实现任何给定模块方法的决定本身就是一个复杂且常常不确定的决定,我们将在以后的文章中介绍。

Electron 治理

·2 分钟阅读

随着 Electron 在桌面应用程序中的普及,从事 Electron 工作的团队也在壮大:我们有更多为不同公司工作、居住在不同时区并有不同兴趣的全职维护人员。我们正在引入治理结构,以便我们能够保持平稳增长。


为什么事情在变化?

Electron 项目中的人员与世界各地的志愿者、全职维护人员以及依赖 Electron 的多家公司一起在不同时区进行协调。到目前为止,我们通过非正式协调取得了成功;但随着团队的壮大,我们发现这种方法无法扩展。我们也希望让新的贡献者更容易在项目中找到自己的归属感。

工作组

Electron 治理包括负责项目不同部分的工作组。我们从七个小组开始

  • 社区与安全:处理 行为准则 问题。
  • 文档 & 工具:负责外部工具(例如 FiddleForge)和 Electron 文档
  • 拓展:帮助发展 Electron 社区。
  • 发布:确保发布稳定并按计划进行。
  • 安全:执行安全测试并响应安全问题。
  • 升级:集成上游升级,例如 V8、Chromium 和 Node 的新版本。
  • 网站:维护和改进 Electron 网站

这些小组将相互协调,但每个小组都有自己的会议时间表和议程,以自主地高效工作。有关这些小组的更多详细信息,请访问治理存储库

这是否会改变 Electron 项目的方向?

这不应该对 Electron 的方向产生任何直接影响。如果我们的策略成功,工作组将使新的贡献者更容易找到他们感兴趣的主题,并通过将与他们日常工作无关的讨论转移到其他小组来简化维护者的生活。如果这种情况发生,它可能会通过让更多没有受阻的人一起工作而间接地影响事情。

在哪里可以了解更多信息?

Chromium FileReader 漏洞修复

·一分钟阅读

在 Chrome 中发现了一个高危漏洞,该漏洞会影响所有基于 Chromium 的软件,包括 Electron。

此漏洞已分配 CVE-2019-5786。您可以在 Chrome 博客文章 中阅读有关它的更多信息。

请注意,Chrome 报告称该漏洞已被实际利用,因此强烈建议您尽快升级 Electron。


范围

这会影响任何可能运行第三方或不受信任的 JavaScript 的 Electron 应用程序。

缓解

受影响的应用程序应升级到 Electron 的已修补版本。

我们发布了新版本的 Electron,其中包括此漏洞的修复程序

Electron 5 的最新测试版正在跟踪 Chromium 73,因此已经进行了修补

更多信息

此漏洞由 Google 的威胁分析小组的 Clement Lecigne 发现并报告给了 Chrome 团队。可以在此处找到 Chrome 博客文章。

要了解有关保持 Electron 应用程序安全的最佳实践的更多信息,请参阅我们的安全教程

如果您希望报告 Electron 中的漏洞,请发送电子邮件至 [email protected]

停止支持 32 位 Linux

·3 分钟阅读

Electron 团队将从 Electron v4.0 开始停止支持 32 位 Linux (ia32 / i386)。支持基于 32 位 Linux 安装的最后一个 Electron 版本是 Electron v3.1,它将收到支持版本,直到 Electron v6 发布。对基于 64 位 Linux 和 armv7l 的支持将保持不变。


Electron 不再支持什么?

您可能在您的计算机上或在下载软件的选项中看到了“64 位”和“32 位”的描述。该术语用于描述特定的计算机体系结构。20 世纪 90 年代和 21 世纪初制造的大多数计算机都使用基于 32 位体系结构的 CPU,而后来制造的大多数计算机都使用更新、功能更强大的 64 位体系结构。任天堂 64(明白了吗?)和 PlayStation 2 是首批广泛使用新体系结构的消费设备,2010 年后销售的计算机几乎都包含 64 位处理器。因此,支持一直在减少:Google 在 2016 年 3 月停止发布适用于 32 位 Linux 的 Chrome,Canonical 在 2017 年停止提供 32 位桌面镜像,并在 Ubuntu 18.10 中完全放弃了对 32 位的支持。Arch Linux、elementary OS 和其他主要的 Linux 发行版已经放弃了对老旧处理器体系结构的支持。

到目前为止,Electron 已经提供并支持在较旧的 32 位体系结构上运行的构建。从 v4.0 版本开始,Electron 团队将不再能够提供 32 位 Linux 的二进制文件或支持。

Electron 一直是一个充满活力的开源项目,我们将继续支持和鼓励有兴趣为异构架构构建 Electron 的开发人员。

这对开发人员意味着什么?

如果您当前没有为 Linux 提供应用程序的 32 位发行版,则无需执行任何操作。

发布 32 位 Linux Electron 应用程序的项目将需要决定如何进行。Electron 3 将支持 32 位 Linux 直到 Electron 6 发布,这为做出决定和计划提供了一些时间。

这对用户意味着什么?

如果您是 Linux 用户,并且不确定您是否正在运行基于 64 位的系统,那么您很可能正在运行基于 64 位的体系结构。要确保这一点,您可以在终端中运行 lscpuuname -m 命令。其中任何一个都将打印您当前的体系结构。

如果您在 32 位处理器上使用 Linux,那么您可能已经遇到了难以找到为您的操作系统发布的最新软件的困难。Electron 团队与 Linux 社区的其他重要成员一起建议您升级到基于 64 位的体系结构。

BrowserView window.open() 漏洞修复

·一分钟阅读

发现了一个代码漏洞,该漏洞允许在子窗口中重新启用 Node。


使用 sandbox: truenativeWindowOpen: truenodeIntegration: false 打开 BrowserView 会导致 webContents,其中可以调用 window.open,并且新打开的子窗口将启用 nodeIntegration。此漏洞会影响所有受支持的 Electron 版本。

缓解

我们发布了新版本的 Electron,其中包括此漏洞的修复程序:2.0.173.0.153.1.34.0.45.0.0-beta.2。我们鼓励所有 Electron 开发人员立即将其应用程序更新到最新的稳定版本。

如果由于某种原因您无法升级您的 Electron 版本,您可以通过禁用所有子 web 内容来缓解此问题

view.webContents.on('-add-new-contents', (e) => e.preventDefault());

更多信息

此漏洞由 PalmerAL 发现并负责任地报告给了 Electron 项目。

要了解有关保持 Electron 应用程序安全的最佳实践的更多信息,请参阅我们的安全教程

如果您希望报告 Electron 中的漏洞,请发送电子邮件至 [email protected]

Node.js 原生插件和 Electron 5.0

·2 分钟阅读

如果您在使用带有 Electron 5.0 的本机 Node.js 插件时遇到问题,则可能需要更新该插件才能使用最新版本的 V8。


再见 v8::Handle,你好 v8::Local

2014 年,V8 团队弃用了 v8::Handle,转而使用 v8::Local 作为本地句柄。Electron 5.0 包含一个最终完全删除了 v8::Handle 的 V8 版本,并且仍在使用它的本机 Node.js 插件需要在与 Electron 5.0 一起使用之前进行更新。

所需的代码更改非常少,但每个仍在使用 v8::Handle 的本机 Node 模块都将无法使用 Electron 5.0 构建,并且需要进行修改。好消息是 Node.js v12 也将包含此 V8 更改,因此无论如何,任何使用 v8::Handle 的模块都需要更新才能与即将发布的 Node 版本一起使用。

我维护一个原生插件,我该如何提供帮助?

如果你维护一个 Node.js 的原生插件,请确保将所有出现的 v8::Handle 替换为 v8::Local。前者只是后者的别名,因此无需进行其他更改即可解决此特定问题。

你可能也会对 N-API 感兴趣,它是作为 Node.js 本身的一部分独立于 V8 维护的,旨在使原生插件免受底层 JavaScript 引擎更改的影响。你可以在 Node.js 网站上的 N-API 文档中找到更多信息。

救命!我在我的应用中使用了一个原生插件,它无法工作!

如果你在你的应用程序中使用了 Node.js 的原生插件,并且该原生插件由于此问题而无法构建,请与该插件的作者联系,查看他们是否发布了修复此问题的新版本。如果没有,联系作者(或者发起一个 Pull Request!)可能是你最好的选择。

Electron v5.0.0 时间线

·2 分钟阅读

Electron 首次公开我们的发布计划,从 v5.0.0 开始。这是我们迈向公开长期时间表的第一步。


正如我们在 v4.0.0 稳定版本博客文章中提到的,我们计划大约每季度发布一次,以保持与 Chromium 版本更紧密的节奏。Chromium 版本更新非常快 —— 每 6 周一个新版本。

看看 Electron 和 Chromium 并排的进展

line graph comparing Electron versus Chromium versions

在 2018 年下半年,我们的首要任务是更快地发布并更接近 Chromium。我们通过坚持预定的时间表取得了成功。Electron 3.0.0 和 4.0.0 的发布时间都是 2-3 个月。我们对以相同的速度发布 5.0.0 及更高版本感到乐观。随着每个季度大约发布一个主要的 Electron 版本,我们现在与 Chromium 的发布节奏保持一致。超越 Chromium 稳定版本始终是我们的目标,我们正在朝着这个目标迈进。

我们很乐意像 Node.jsChromium 那样承诺未来的日期,但我们尚未达到那个阶段。我们对未来达到长期时间表感到乐观。

考虑到这一点,我们正在迈出第一步,公开发布 v5.0.0 的发布计划。你可以在这里找到它。

为了帮助我们测试 Beta 版本并进行稳定化,请考虑加入我们的应用程序反馈计划

Electron 4.0.0

·6 分钟阅读

Electron 团队很高兴地宣布,Electron 4 的稳定版本现已发布!你可以从 electronjs.org 或通过 npm 安装它,使用 npm install electron@latest。此版本包含许多升级、修复和新功能,我们迫不及待地想看看你用它们构建什么。阅读更多关于此版本的详细信息,并请在探索过程中分享你的反馈!


新功能?

Electron 的大部分功能由 Chromium、Node.js 和 V8 提供,它们是构成 Electron 的核心组件。因此,Electron 团队的一个关键目标是尽可能跟上这些项目的变化,让构建 Electron 应用程序的开发人员能够访问新的 Web 和 JavaScript 功能。为此,Electron 4 包含了这些组件的主要版本更新;Electron v4.0.0 包括 Chromium 69.0.3497.106,Node 10.11.0 和 V8 6.9.427.24

此外,Electron 4 还包括对特定于 Electron 的 API 的更改。你可以在下面找到 Electron 4 中主要更改的摘要;有关更改的完整列表,请查看Electron v4.0.0 发布说明

禁用 remote 模块

现在你可以出于安全原因禁用 remote 模块。该模块可以为 BrowserWindowwebview 标签禁用

// BrowserWindow
new BrowserWindow({
webPreferences: {
enableRemoteModule: false
}
})

// webview tag
<webview src="http://www.google.com/" enableremotemodule="false"></webview>

有关更多信息,请参阅 BrowserWindow<webview> 标签文档。

过滤 remote.require() / remote.getGlobal() 请求

如果你不想完全禁用渲染进程或 webview 中的 remote 模块,但希望对可以通过 remote.require 要求的模块进行额外控制,则此功能非常有用。

当通过渲染进程中的 remote.require 请求模块时,会在 app 模块上引发一个 remote-require 事件。你可以在事件(第一个参数)上调用 event.preventDefault() 以阻止模块被加载。WebContents 实例,其中发生 require 作为第二个参数传递,模块名称作为第三个参数传递。相同的事件也会在 WebContents 实例上发出,但在这种情况下,唯一参数是事件和模块名称。在这两种情况下,你可以通过设置 event.returnValue 的值来返回自定义值。

// Control `remote.require` from all WebContents:
app.on('remote-require', function (event, webContents, requestedModuleName) {
// ...
});

// Control `remote.require` from a specific WebContents instance:
browserWin.webContents.on(
'remote-require',
function (event, requestedModuleName) {
// ...
},
);

以类似的方式,当调用 remote.getGlobal(name) 时,会引发一个 remote-get-global 事件。这与 remote-require 事件的工作方式相同:调用 preventDefault() 以防止全局变量被返回,并设置 event.returnValue 以返回自定义值。

// Control `remote.getGlobal` from all WebContents:
app.on(
'remote-get-global',
function (event, webContents, requrestedGlobalName) {
// ...
},
);

// Control `remote.getGlobal` from a specific WebContents instance:
browserWin.webContents.on(
'remote-get-global',
function (event, requestedGlobalName) {
// ...
},
);

有关更多信息,请参阅以下文档

JavaScript 访问关于面板

在 macOS 上,你现在可以调用 app.showAboutPanel() 以编程方式显示关于面板,就像单击通过 {role: 'about'} 创建的菜单项一样。有关更多信息,请参阅showAboutPanel 文档

控制 WebContents 背景节流

WebContents 实例现在有一个方法 setBackgroundThrottling(allowed),用于在页面后台运行时启用或禁用定时器和动画的节流。

let win = new BrowserWindow(...)
win.webContents.setBackgroundThrottling(enableBackgroundThrottling)

有关更多信息,请参阅setBackgroundThrottling 文档

重大更改

不再支持 macOS 10.9

Chromium 不再支持 macOS 10.9(OS X Mavericks),因此Electron 4.0 及更高版本也不再支持它

单实例锁定

以前,要使你的应用程序成为单实例应用程序(确保你的应用程序在任何给定时间只运行一个实例),你可以使用 app.makeSingleInstance() 方法。从 Electron 4.0 开始,你必须改用 app.requestSingleInstanceLock()。此方法的返回值指示你的应用程序的此实例是否成功获取了锁。如果它未能获取锁,你可以假设你的应用程序的另一个实例已经在运行并持有锁,并立即退出。

有关使用 requestSingleInstanceLock() 的示例以及有关各种平台上细微行为的信息,请参阅 app.requestSingleInstanceLock() 和相关方法的文档以及second-instance 事件

win_delay_load_hook

当为 Windows 构建原生模块时,模块的 binding.gyp 中的 win_delay_load_hook 变量必须为 true(这是默认值)。如果此钩子不存在,则原生模块将无法在 Windows 上加载,并显示类似 Cannot find module 的错误消息。有关更多信息,请参阅原生模块指南

弃用

以下重大更改计划在 Electron 5.0 中进行,因此在 Electron 4.0 中已被弃用。

nativeWindowOpen 打开的窗口禁用 Node.js 集成

从 Electron 5.0 开始,使用 nativeWindowOpen 选项打开的子窗口将始终禁用 Node.js 集成。

webPreferences 默认值

当使用 webPreferences 选项集创建一个新的 BrowserWindow 时,以下 webPreferences 选项的默认值已被弃用,转而使用下面列出的新默认值

属性已弃用的默认值新默认值
contextIsolationfalsetrue
nodeIntegrationtruefalse
webviewTag如果设置了 nodeIntegration,则为 nodeIntegration 的值,否则为 truefalse

请注意:当前存在一个已知错误 (#9736),如果 contextIsolation 开启,则会阻止 webview 标签正常工作。请密切关注 GitHub 问题以获取最新信息!

Electron 安全文档中了解更多关于上下文隔离、Node 集成和 webview 标签的信息。

Electron 4.0 仍将使用当前的默认值,但如果您没有为它们传递显式值,您将会看到弃用警告。为了使您的应用程序为 Electron 5.0 做好准备,请为这些选项使用显式值。请参阅 BrowserWindow 文档,了解有关每个选项的详细信息。

webContents.findInPage(text[, options])

medialCapitalAsWordStartwordStart 选项已被弃用,因为它们已在上游被删除。

应用反馈计划

我们在 Electron 3.0 开发期间建立的应用反馈计划取得了成功,因此我们在 4.0 的开发过程中也继续沿用了该计划。我们非常感谢 Atlassian、Discord、MS Teams、OpenFin、Slack、Symphony、WhatsApp 以及其他项目成员在 4.0 beta 测试期间的参与。要了解有关应用反馈计划的更多信息并参与未来的 beta 测试,请查看我们关于该计划的博客文章

下一步

在短期内,您可以期望团队继续专注于跟进构成 Electron 的主要组件(包括 Chromium、Node 和 V8)的开发。尽管我们不承诺发布日期,但我们的计划是大约每季度发布带有这些组件新版本的 Electron 新主要版本。请参阅我们的版本控制文档,了解有关 Electron 中版本控制的更多详细信息。

有关 Electron 即将发布的版本中计划的重大更改的信息,请参阅我们的计划重大更改文档

SQLite 漏洞修复

·一分钟阅读

已发现一个影响基于 SQLite 或 Chromium 的软件(包括所有版本的 Electron)的远程代码执行漏洞,名为“麦哲伦”。


范围

使用 Web SQL 的 Electron 应用程序会受到影响。

缓解

受影响的应用程序应停止使用 Web SQL 或升级到已修补的 Electron 版本。

我们发布了新版本的 Electron,其中包括此漏洞的修复程序

目前没有在野外发现此漏洞的报告;但是,我们强烈建议受影响的应用程序进行缓解。

更多信息

此漏洞由腾讯 Blade 团队发现,他们已发布一篇讨论该漏洞的博客文章

要了解有关保持 Electron 应用程序安全的最佳实践的更多信息,请参阅我们的安全教程

如果您希望报告 Electron 中的漏洞,请发送电子邮件至 [email protected]

Electron 应用反馈计划

·3 分钟阅读

Electron 正在努力使其发布周期更快、更稳定。为了实现这一目标,我们为大型 Electron 应用程序启动了应用反馈计划,以测试我们的 beta 版本并向我们报告特定于应用程序的问题。这有助于我们优先处理能让应用程序更快升级到下一个稳定版本的工作。

编辑 (2020-05-21):此计划已停止。


谁可以加入?

我们的应用程序加入此计划的标准和期望包括以下几项

  • 在 beta 测试期间测试您的应用程序 10,000+ 用户小时
  • 指定一个联系人,每周签到以讨论您应用程序的 Electron 错误和应用程序阻止程序
  • 您同意遵守 Electron 的行为准则
  • 您愿意分享下一个问题中列出的以下信息

我的 Electron 应用程序必须分享哪些信息?

  • 您的应用程序运行任何 beta 版本时的总用户小时数
  • 您的应用程序正在测试的 Electron 版本(例如,4.0.0-beta.3)
  • 任何阻止您的应用程序升级到正在进行 beta 测试的发布系列的错误

用户小时数

我们理解并非每个人都能分享准确的用户数量,但是更好的数据可以帮助我们确定特定版本的稳定性。我们要求应用程序承诺测试至少一定的用户小时数,目前在整个 beta 测试周期中为 10,000 小时。

  • 10 用户小时可以是 10 个人测试一个小时,或者一个人测试 10 个小时
  • 您可以将测试分配在各个 beta 版本之间,例如在 3.0.0-beta.2 上测试 5,000 用户小时,然后在 3.0.0-beta.5 上测试 5,000 用户小时。越多越好,但我们理解某些应用程序无法测试每个 beta 版本
  • CI 或 QA 小时不计入总数;但是,内部版本会计入

我的 Electron 应用程序为什么要加入?

您的应用程序的错误将被跟踪并进入核心 Electron 团队的雷达。您的反馈有助于 Electron 团队了解新 beta 版本的运行情况以及需要完成的工作。

我应用程序的信息是否会公开分享?谁可以看到这些信息?

不,您应用程序的信息不会与公众分享。信息保存在一个私有的 GitHub 存储库中,只有应用反馈计划的成员和Electron 管理机构才能查看。所有成员都同意遵守 Electron 的行为准则

注册

我们目前接受有限数量的注册。如果您有兴趣并能够满足上述要求,请填写此表格