一、前言
前面一些章节我们主要学习了窗口的基本使用。
在此基础上,其实你就已经能够开始开发一些简单的“浏览器应用”了。
之所以将其称为“浏览器应用”,是因为到目前为止,我们依旧只能写网页开发写的那些东西而已。
比如,一个最基本的软件应该可以在页面上通过点击按钮或者其它交互方式,达到删除、读取、修改文件的能力吧?
但目前为止我们是做不到的这一点的,因为你现在依旧只能在页面中写网页开发的那点东西,也就是css
、html
、js
,其中的js
也只有最基本的网页API可以让你调用。
为了能够做到这一点,我们就需要了解Electron
关于主进程与渲染进程的关系。
二、主进程与渲染进程
虽然听名字感觉很高大上,但实际上就是两种划分了使用权限的进程而已,如果不知道进程是什么,可以参考这篇文章:进程与线程。
其中的主进程,其实指的就是我们前面写的那个入口文件,main.js
或者index.js
,这取决于你配置文件中main
填的什么。
而渲染进程,其实就是我们的页面,也就是你创建窗口时,执行窗口内容的其实就是一个进程,只不过被命名了渲染进程,因为它就是用来渲染界面的。
而两者的区别就在于,在主进程中,也就是入口文件中,你拥有最高权限,可以访问任意内容,比如你就可以在该进程中对电脑磁盘上的文件数据做任意的操作。
而在渲染进程中,你就只能使用基本浏览器提供的API(html页面文件中引入js代码),操作页面,而无法直接操作电脑文件。
按照官方说法,这是为了安全,因为正如前面我们所看到的,加载页面非常简单,直接在主进程中调用一个loadFile
函数就行了,甚至还可以加载网页(loadURL
)。
而这就会导致渲染进程中的代码很可能不可控。
像
vscode
这种支持插件的软件,是需要将其它开发者开发的代码加载到本程序的,如果有恶意程序员滥用这种权限,就会造成非常严重的数据安全问题。
所以总结来说就是:主进程拥有所有权限,而渲染进程只拥有操作页面的权限。
三、进程通信
但正如前面所说,我们的界面是在渲染进程中的。
而我们想要实现通过点击按钮来增删文件,用单一进程是肯定无法实现的:
- 你的点击按钮事件是发生在渲染进程中的,而渲染进程没有操作文件的权限。
- 主进程虽然有操作文件的权限,但没办法绘制界面让你用,也就是主进程监听不到用户的行为。
对于这个问题,官方给出的解决方案就是进程间通信:
- 渲染进程监听用户在界面上的行为。
- 如果用户想要操作本地文件等高权限的行为,那么渲染进程就通知主进程一声。
- 主进程监听到渲染进程的信息,就去执行,再将结果返回给渲染进程。
- 渲染进程得到结果,再将结果提示给用户。
也就是稍稍绕了一个弯而已,但为了安全,这种行为也是必要的。
为什么这样就安全了呢?
因为事件的处理程序是需要作者提前写好的,也就是在入口文件中,你需要提前写好你想要处理哪些来自渲染进程的事件,包括如何处理,都是你自己说了算。
即使加载了第三方的渲染进程代码进来,能调用的也只有你暴露出来的方法而已。
所以归根结底,这样做的目的是将程序的安全问题完全交给开发作者而已,并不是就绝对安全了。
比如,你在主进程中主动暴露出来了一个叫做delete
的删除事件处理消息,并且加载了一个恶意程序,它可能就会疯狂调用你暴露出来的这个接口,将用户电脑上的数据全部删除干净,这就是最严重的安全漏洞!
进程通信的简称为IPC
(Inter-Process Communication
缩写,官网以及一些博客中很常见)。
四、基本使用
官方文档可以点击这里查看。
简单来说就是,主进程可以使用一个叫做ipcMain
的模块,而渲染进程可以使用一个叫做ipcRenderer
的模块,来实现两者之间的通信。
为了方便,最好新建一个专门执行渲染进程代码的文件:
还是前面的那个项目,只是在该文件中新建了一个叫做render.js
的文件,并且在该页面文件(index.html
)中引入了它而已:
<button id="test">test</button>
<script src="./render.js"></script>
这是前端开发的基础知识,这里不再过多赘述。
然后当我们主进程中创建窗口、并加载这个页面之后,由于render.js
文件被引入到了该文件之中,所以这个文件就会在渲染进程中被执行。
同时为了后面能让渲染进程发送消息给主进程,我们还创建一个按钮test
。
其目的就是,当我们按下这个按钮时,渲染进程向主进程发送一个请求,然后主进程再给渲染进程一个回应。
首先是渲染进程向主进程发送消息的过程,按理来说,我们可能就会像下面这样写代码:
但这样是错误的,原因也是前面提到过的,渲染进程只能访问浏览器本身提供的api,它没有权限访问nodejs
模块,包括我们这里的electron
模块,因为它同样也是一个我们下载下来的node模块。
这个时候怎么办?怎么感觉有点无解呀!
而这就是前面预处理脚本preload.js
发挥作用的时候了,它同样处于渲染进程内,但给了它更多的权限。比如它就可以直接访问到node
模块。
所以一般来说,它的目的就是向渲染进程暴露接口的。