关于即时通讯:IM跨平台技术学习二Electron初体验快速开始跨进程通信打包踩坑等

5次阅读

共计 8105 个字符,预计需要花费 21 分钟才能阅读完成。

本文由蘑菇街前端技术团队分享,原题“Electron 从零到一”,有订正和改变。

1、引言

在上篇《疾速理解新一代跨平台桌面技术——Electron》,咱们曾经对 Electron 跨端框架有了根本的意识。

本篇将带你简略上手 Electron 框架开发跨平台桌面端,内容包含一个疾速开始例子、跨过程通信原理、打包和散发、以及一些典型的技术踩坑等。心愿能带给你启发。

学习交换:

  • 挪动端 IM 开发入门文章:《新手入门一篇就够:从零开发挪动端 IM》
  • 开源 IM 框架源码:https://github.com/JackJiang2011/MobileIMSDK(备用地址点此)

(本文已同步公布于:http://www.52im.net/thread-4039-1-1.html)

2、系列文章

本文是系列文章中的第 2 篇,本系列总目录如下:

《IM 跨平台技术学习(一):疾速理解新一代跨平台桌面技术——Electron》
《IM 跨平台技术学习(二):Electron 初体验(疾速开始、跨过程通信、打包、踩坑等)》(* 本文)
《IM 跨平台技术学习(三):vivo 的 Electron 具体技术栈选型、踩坑总结等》(稍后公布..)
《IM 跨平台技术学习(四):蘑菇街基于 Electron 开发 IM 客户端的技术实际》(稍后公布..)
《IM 跨平台技术学习(五):融云基于 Electron 的 IM 跨平台 SDK 革新实际总结》(稍后公布..)
《IM 跨平台技术学习(六):网易云信基于 Electron 的 IM 音讯全文检索技术实际》(稍后公布..)

3、Electron 简介

Electron 是一个赋力前端进行跨平台开发的框架,让开发人员应用 JavaScript、HTML 和 CSS 等前端技术构建跨平台的桌面利用。

Electron 通过将 Chromium(所有类 Chrome 的浏览器都是基于这个开源工程而来)和 Node.js 合并到同一个运行时环境中(见下图),并将其打包为 Mac,Windows 和 Linux 零碎下的利用,而开发人员只需关注前端代码的开发。

▲ 上图援用自《疾速理解新一代跨平台桌面技术——Electron》

Chromium、Node.js、Native API 这三者的作用别离是:

1)Chromium:为 Electron 提供了弱小的 UI 能力,能够不思考传统浏览器兼容性的状况下,利用弱小的 Web 生态来开发界面;
2)Node.js:让 Electron 有了底层的操作能力(比方文件的读写,甚至是集成 C ++ 等等操作),并能够应用大量开源的 npm 包来实现开发需要。
3)Native API:Native API 让 Electron 有了跨平台和桌面端的原生能力(比如说它有对立的原生界面,窗口、托盘、音讯告诉这些)。
Electron 就是通过这三者的奇妙组合,让咱们开发跨平台利用变的非常高效。

实质上就是 chromium(chrome 开源版本)浏览器,有最新的货色都会在 chromium 测试,所以 electron 能够体验最新的 api,这也是益处之一。

无关 Electron 的根本介绍等,这里就不再赘述,如果您还未曾理解,能够先浏览本文的上篇。

4、疾速开始

4.1 材料筹备
Electron 官网提供了一个名为 electron-quick-start 的我的项目,能够 clone 下来当成模版应用,本文应用 create-react-app 来一步一步学习。

其它重要的 Electron 开发资源:

1)Electron 官网:https://electronjs.org;
2)Electron Github:https://github.com/electron;
3)Electron 开发手册:https://www.electronjs.org/zh…。
4.2 创立一个 react 我的项目

# 装置 create-react-app 命令, 如果已将装置请疏忽

npm install -g create-react-app

# 创立 electron-react 我的项目

create-react-app electron-react

# 启动我的项目

cd electron-react && npm start

4.3 配置 Electron 环境
1)在 public 文件夹下新建 index.html,轻易写点内容:

...

<div>hello world</div>

...

2)接下来创立 electron 主线程文件(public/main.js),倡议写在 public 门路上面:

const{app, BrowserWindow} = require('electron')

// 创立全局变量并在上面援用,防止被 GC

let win

function createWindow () {

    // 创立浏览器窗口并设置宽高

    win = newBrowserWindow({width: 800, height: 600})

    // 加载页面

    win.loadFile('./index.html')

    // 关上开发者工具

    win.webContents.openDevTools()

    // 增加 window 敞开触发事件

    win.on('closed', () => {win = null// 勾销援用})

}

// 初始化后 调用函数

app.on('ready', createWindow) 

// 当全副窗口敞开时退出。app.on('window-all-closed', () => {

   // 在 macOS 上,除非用户用 Cmd + Q 确定地退出,// 否则绝大部分利用及其菜单栏会放弃激活。if(process.platform !== 'darwin') {app.quit()

   }

})

app.on('activate', () => {

// 在 macOS 上,当单击 dock 图标并且没有其余窗口关上时,// 通常在应用程序中从新创立一个窗口。if(win === null) {createWindow()

    }

})

3)接着再批改 package.json 中的 main 字段对应的门路, 并增加 start 命令:

{

    ...

    "main": "main.js",

    "scripts": "electron ."

}

4)执行 npm start,就会弹出如下运行界面:

以上就是我简略写的一个页面,大家也能够写一写本人感兴趣的货色。

真如下面演示的这样,一个简略的 Electron 跨平台桌面利用就开发好了,真的 so easy!

5、过程详解

5.1 根本认知
Electron 架构和 Chromium 架构相似,也是具备 1 个主过程和多个渲染过程(如下图所示)。

然而也有区别:

1)在各个过程中裸露了 Native API,提供了 Native 能力;
2)引入了 Node.js,所以能够应用 Node 的能力;
3)然而渲染过程应用 node 须要配置。
能够简略的了解为:Electron 为 web 我的项目套上了 Node.js 环境的壳,使得咱们能够调用 Node.js 的丰盛的 API。这样咱们能够用 JavaScript 来写桌面利用,拓展很多咱们在 web 端不能做的事件。

上面这张图,技术原理更容易了解一点:

5.2 主过程的次要特点
Electron 运行 package.json 的 main 脚本的过程被称为主过程(主过程只有一个)。波及到具体代码的解说,将在下一节中开展,本节就不作过多论述了。

Electron 主过程的具体职责:

1)主过程连贯着操作系统和渲染过程,能够把她看做页面和计算机沟通的桥梁;
2)过程间通信、窗口治理
3)全局通用服务;
4)一些只能或适宜在主过程做的事件(例如浏览器下载、全局快捷键解决、托盘、session);
5)保护一些必要的全局状态。
5.3 渲染过程的次要特点
渲染过程就是咱们所相熟前端环境了,只是载体扭转了,从浏览器变成了 window.

留神:出于平安思考,渲染过程是不能间接拜访本地资源的,因而都须要在主过程实现。

Electron 渲染过程次要特点:

1)Electron 应用了 Chromium 来展现 web 页面,所以 Chromium 的多过程架构也被应用到;
2)每个 web 页面运行在它本人的渲染过程中(每个渲染过程都是互相独立的,并且只关怀他们本人的网页);
3)应用 BrowserWindow 类开启一个渲染过程并将这个实例运行在该过程中,当一个 BrowserWindow 实例被销毁后,相应的渲染过程也会被终止;
4)渲染过程中不能调用原生资源,然而渲染过程中同样蕴含 Node.js 环境,所以能够引入 Node.js。
5.4 主过程与渲染过程的关系
主过程与渲染过程的关系次要是这样:

1)主过程应用 BrowserWindow 实例创立网页;
2)每个 BrowserWindow 实例都在本人的渲染过程里运行着一个网页(当一个 BrowserWindow 实例被销毁后,相应的渲染过程也会被终止);
3)主过程治理所有页面和与之对应的渲染过程;
4)因为在网页里治理原生 GUI 资源是十分危险而且容易造成资源泄露,所以在网页面调用 GUI 相干的 APIs 是不被容许的(如果你想在网页里应用 GUI 操作,其对应的渲染过程必须与主过程进行通信,申请主过程进行相干的 GUI 操作)。
具体关系如下图所示:

把它们设想成这样:

即 Chrome(或其余浏览器)的每个标签页(tab)及其页面,就好比 Electron 中的一个独自渲染过程。即便敞开所有标签页,Chrome 仍然存在。这好比 Electron 的主过程,能关上新的窗口或敞开这个利用。就像下图这样。

6、从代码角度了解过程

6.1 主过程和渲染过程
先来看看 electron 我的项目根本目录构造:

app

└─public

    └─index.html--------------- 入口文件

├─main.js---------------------- 程序启动入口,主过程

├─ipc-------------------------- 过程间模块

├─appNetwork------------------- 利用通信模块

└─src-------------------------- 窗口治理,渲染过程

    ├─components--------------- 通用组件模块

    ├─store-------------------- 数据共享模块

    ├─statics------------------ 动态资源模块

    └─pages---------------------- 窗口业务模块

      ├─窗口 A ---------------- 窗口

      └─窗口 B ---------------- 窗口

如上所示:package.json 中的 main 字段对应的文件的过程是主过程。Electron 集成了 Chromium 来展现窗口界面,窗口中所看到的内容应用的都是 HTML 渲染进去的。

Chromium 自身是多过程渲染页面的架构(在默认状况下,Chromium 的默认策略是对每一个 tab 新开一个过程,以确保每个页面是独立且互不影响的,防止一个页面的解体导致全副页面无奈应用),所以 Electron 在展现窗口时,也会应用到 Chromium 的多过程架构。而这种多过程渲染架构在 Electron 中,也就被是渲染过程(render process)啦。

6.2 过程间通信
在 Electron 中,GUI 相干的模块(如 dialog,menu 等)仅在主过程可用,在渲染过程中不可用。

为了在渲染过程中应用它们,须要应用 ipc 模块向主过程发送音讯,上面是几种过程间通信的办法。

1)ipcMain & ipcRenderer:

从主过程到渲染过程的异步通信,也能够将音讯从主过程发送到渲染过程(参考文档)。

发送音讯时,事件名称为 channel。回复同步音讯时,须要设置 event.returnValue。

将异步音讯发送回发送方,能够应用 event.reply(…),这个辅助办法将主动解决来自渲染过程的音讯,然而 event.sender.send(…) 这个办法则始终将音讯发送给主过程。

上面是在渲染和主过程之间发送和解决音讯的一个例子:

// 在主过程中

const {ipcMain} = require('electron')

ipcMain.on('asynchronous-message', (event, arg) => {console.log(arg); // 输入 'ping'

    event.reply('asynchronous-reply', 'pong');

})

ipcMain.on('synchronous-message', (event, arg) => {console.log(arg) // 输入‘ping’event.returnValue = 'pong'

})

// 在渲染过程(网页)中

const {ipcRenderer} = require('electron')

console.log(ipcRenderer.sendSync('synchronous-message', 'ping')) // 输入 'pong'

ipcRenderer.on('asynchronous-reply', (event, arg) => {console.log(arg); // 输入 'pong'

})

ipcRenderer.send('asynchronous-message', 'ping')

2)remote 模块:

remote 为渲染过程和主过程通信提供了一种简略的办法。你能够调用 main 过程对象的办法,而不用显式发送过程间音讯。

例如:从渲染过程创立浏览器窗口

const {BrowserWindow} = require('electron').remote

let win = newBrowserWindow({width: 800, height: 600})

win.loadUrl('https://www.mogu.com')

留神:反过来,如果须要从主过程拜访渲染过程,能够应用 webContents.executeJavascript。

3)webContents:

即通过 channel 向渲染过程发送异步音讯,能够发送任意参数。在外部,参数会被序列化为 JSON,因而参数对象伤的函数和原型链不会被发送。

除了以上这些办法,也能够应用 localStorage、sessionStorage 等。

7、打包公布

开发实现后,还须要将利用打包成可执行文件,这一环节的坑还是学习 electron 到当初踩的最多的。

目前支流的打包工具有 electron-packager 和 electron-builder

7.1 electron-packager
1)装置依赖:

npm i electron-packager --save-dev

2)打包:

electron-packager --platform= --arch= [optional flags...]

也能够间接运行 npm run electron-packager 打包。

7.2 electron-builder
官网解释:

A complete solution to package and build a ready for distribution Electron, Proton Native or Muon app for macOS, Windows and Linux with“auto update”support out of the box.

简略的说:electron-builder 有比 electron-packager 更丰盛的性能,反对更多的平台,同时也反对了自动更新。除了这几点外,electron-builder 打出的包更为轻量,并且能够打包出不裸露源码的 setup 安装程序。

另外应用下来感觉比 electron-packager 的坑要少一点。

1)装置依赖:

npm i electron-builder --save-dev

2)打包(在我的项目的 package.json 文件中定义 build 字段):

{

    "build": {

        "appId": "com.xxx.app",

        "extends": null,

        "files": ["build/**/*"],

        "mac": {"icon": "icons/icon.icns"},

        "win": {

            "target": "nsis",

            "icon": "icons/icon.png"

        }

    }

}

这是最根底的配置,当然打包过程中可能会碰到其余的问题须要批改配置。通常 files 配置只写一个 build 文件夹是不够的,要依据我的项目构造和打包状况增加其余门路。

增加 scripts 命令

{

    "scripts": {"pack": "electron-builder"}

}

运行 npm run pack 打包。

打包实现后在 dist 目录下有可执行文件,关上后如果没有报错,则阐明打包胜利。

8、踩坑总结

我所遇到的大部分都是打包遇到的坑,以下列举几个典型的坑。

8.1 应用 electron-packager 打包报错

Generated checksum for"electron-v6.0.2-darwin-x64.zip"did not match expected checksum。

解决办法:node 版本升级到 8.x 以上就好。

8.2 关上打包生成的可执行文件报错

呈现这种问题可能有以下几个起因。

1)我的项目中可能间接拜访了本地门路, 浏览器为了平安思考不容许拜访。

2)package.json 中的 build 配置问题,如果 main.js 在一个很深的门路中,须要在上面独自增加 main.js 的门路:

"build": {

    ...

+   "public/main.js"

    ...

}

3)webpack 配置中的门路间接应用了 __dirname, 能够应用 remote 模块的 getAppPath 办法获得门路:

const remote = require('remote')

const app = remote.require('app')

console.log(app.getAppPath());

参考资料:https://github.com/electron/electron/issues/5107

8.3 dependencies & devDependencies
在 Electron 打包时,肯定要分清哪些是生产环境依赖,哪些是开发环境依赖,避免出现此类谬误:

8.4 对于打包慢的问题(npm & cnpm)
cnpm 装的各种 node_modules,这种形式下所有的包都是扁平化的装置,一下子 node_modules 开展就有十分多的文件,导致打包的过程十分慢。

然而如果该用 npm 来装置 node_modules 的话,所有的包都是树状构造,层级变深。然而打包速度会快很多(具体材料参见:electron 打包过了 2 小时都没好?)。

9、Electron 的优缺点

文章的最初,基于实际领会,总结一下 Electron 的优缺点。

Electron 长处很显著:

1)上手较简略:HTML、CSS、JS、Node、npm 包、UI 框架,不便高效,能很轻松的实现很难看的 UI;
2)可多端运行:能够疾速构建“跨平台”(Windows、MacOs、Linux)的桌面级利用;
3)开发工夫短:绝对其余跨平台计划(如:QT、GTK+ 等),更稳固、bug 少,毕竟只有浏览器外壳跑起来了就能够了(当然坑是少不了的);
4)兼容性问题:再也不必兼容多浏览器(只针对谷歌,但要兼容 mac、Linux)。
Electron 毛病也同样不言而喻:

1)安装包体积大:安装包体积略大(打包了 Chromium),至多蕴含了一个浏览器的体积,每装一个 app 就相当于装一个 chrome;
2)运行性能稍差:性能不如原生利用,Mac 零碎下丝滑一些,Window 零碎就有点丢帧;
3)内存占用较大:卡、启动慢,新开一个过程,起步价就是一个 NodeJS 的内存开销;
4)网页加载稍慢:loadURL 加载近程页面白屏工夫长(优化可采纳 VSCode 骨架屏)。

10、参考资料

[1] Electron 官网开发者手册

[2] Electron 初体验(疾速开始、跨过程通信、打包、踩坑等)

[3] Electron 根底入门 简单明了,看完啥都懂了

[4] 网易云信 Web 端 IM 的聊天音讯全文检索技术实际

(本文已同步公布于:http://www.52im.net/thread-4039-1-1.html)

正文完
 0