V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
powertoolsteam
V2EX  ›  推广

初探 Electron,从入门到实践

  •  
  •   powertoolsteam · 2019-08-29 14:00:24 +08:00 · 1387 次点击
    这是一个创建于 1674 天前的主题,其中的信息可能已经有所发展或是发生改变。

    讲师简介: 刘涛 —— GrapeCity SpreadJS 项目组资深开发工程师,在前端开发领域耕耘多年,热衷于研究前沿技术,专注于以实践方式提升开发效率。


    本期分享,我们将从“初探 Electron ”开始,通过线上直播,深入解读 Electron 的入门技巧以及实践应用。

    线上直播地址: http://live.vhall.com/878864086

    在开始学习 Electron 之前,您一定有这样的困惑:Electron 是什么? Electron 能做什么?许多伟大的公司使用 Electron 框架的原因又是什么?

    带着这些问题和疑惑,通过本文的介绍以及讲师的技术分享,可助您全面地认识 Electron 这门新兴的技术,迅速找到其入门途径,并理解 Electron 为何被称为当下开发桌面 App 的最佳选择。

    初探 Electron

    一、Electron 是什么?(为何称之为“跨平台桌面浏览器”)

    前端开发的魅力,在于开发者随时要面临全新技术的挑战!

    曾几何时,作为前端开发者的你可曾想过:如何利用 HTML、CSS 和 JavaScript 构建跨平台的桌面应用程序?借助 Electron,这项工作将比你想象的更加简单。

    Electron 作为一个使用新兴技术(包括 JavaScript,HTML 和 CSS )创建桌面应用程序的框架,其负责处理硬件,开发者可以更专注于应用程序的核心并从底层更改其设计。

    Electron 设计之初便充分结合了当今最好的 Web 技术,作为一个跨平台的“集成框架”,它可以轻松地与 Mac、Windows 和 Linux 兼容。而所谓的“集成框架”也就是它将“ Chromium ”和“ Node.js ”很好的集成在了一起,并明确分工,Electron 负责硬件部分,“ Chromium ”和“ Node.js ”负责界面与逻辑,大家井井有条,共同构成了一个成本低廉却十分高效的解决方案,在快速交付上甚至比 Native 还要快速。

    Electron 发展里程碑

    • 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 商店。

    简而言之,Electron JS 是一个运行时框架,它允许用户使用 HTML5、CSS 和 JavaScript 创建桌面套件应用程序,而大部分应用程序都是由两种非常受欢迎的技术混合而成:Node.js 和 Chromium。因此,您编写的任何 Web 应用程序都可以在 Electron JS 上正常运行。

    Electron 的内置功能包括:

    • 自动更新 - 使应用程序能够自动更新、升级
    • 本机菜单和通知 - 创建本机应用程序菜单和上下文菜单
    • 应用程序崩溃报告 - 您可以将崩溃报告提交给远程服务器
    • 调试和分析 - Chromium 的内容模块可以发现性能瓶颈和运行缓慢的原因。此外,您也可以在应用中使用自己喜欢的 Chrome 开发者工具
    • Windows 安装程序 -您可以快速而简单创建安装包

    二、Electron 可以用来做什么?(哪些场景需要使用 Electron )

    以 Windows 平台应用开发为例,大部分人首先会想到使用成熟的开发方案,如 QT(C++)、WPF(C#) 等。但面临以下几种使用场景,这些方案将显得捉襟见肘:

    • 公司要设计一个全新的 APP, 但技术人员大部分由前端开发构成
    • 公司原本就有在线的 Web 应用,但是想让该应用能够在桌面端直接打开(离线状态下也可使用),并增加一些与系统交互的功能

    以我的亲身经历为例:

    SpreadJS项目中,我们需要将基于 web 版的表格编辑器封装成 APP 使用,同时增加文件操作的能力,如导入导出 excel、导入 PDF 等,而 SpreadJS 是一个纯前端的表格控件,开发人员全部由前端开发组成,对 C++和 C#并不熟悉,如果投入过大的时间精力用来学习,整个项目的技术管理和项目管理将变得无法控制。除此之外,鉴于项目本身对应用的业务逻辑要求并不高,只是套一个具有浏览器属性的运行环境即可,因此,单独为此配置 C++、C# 开发人员将无形中提升更多项目成本。

    为此,我们引入了 Electron 框架:现有的前端开发人员能在不学习其他语言的情况下,直接搞定上述需求,这就是 Electron 为我们带来的价值。

    三、为什么选择 Electron ?( Electron 的出现为前端开发者谋得了一份好差事)

    可以这么说,Electron 这个框架让网路里流传很广的一句话不再是玩笑:“不要和老夫说什么 C++、Java,老夫行走江湖就一把 JS,遇到需求撸起袖子就是干”。Electron 可以帮助前端开发者在不需要学习其他语言和技能的情况下,快速开发跨平台桌面应用。

    Electron 的出现将蚕食很大一部分桌面客户端领域的市场份额,鉴于它的跨平台特性,在不同系统之间仅需少量的优化工作。可想而知,这个成本到底有多低。

    在开发的体验上,Electron 是基于"Chromium"和"Node.js"的,所以几乎所有的 Node.js 模块都可以在 Electron 上运行,并很容易使用“ npm ”搭积木的方式快速交付一个产品。

    四、使用 Electron 框架的大型应用成功案例

    1. SpreadJS 纯前端表格控件

      SpreadJS 是一款基于 HTML5 的纯前端电子表格控件,以“高速低耗、高度类似 Excel、可无限扩展”为产品特色,提供移动跨平台和浏览器支持,同时满足 .NET 、Java、App 等应用程序中的 Web Excel 组件开发、数据填报、在线文档、图表公式联动、类 Excel UI 设计等业务场景,在数据可视化、Excel 导入导出、公式引用、数据绑定、框架集成等场景下无需大量代码开发和测试,极大降低了企业研发成本和项目交付风险。

    2. WebTorrent

      WebTorrent,作为第一个在浏览器中运行的 torrent 客户端,是一个完全由 JavaScript 编写并使用 WebRTC 进行点对点传输的客户端应用。无需任何插件,扩展或安装,WebTorrent 将用户链接到分散的浏览器到浏览器网络,以确保有效的文件传输。

      WebTorrent 使用 Electron 框架开发,使其尽可能轻量、无广告且开源。此外,使用 Electron 还有助于流式传输,并充当混合客户端,将应用程序连接到所有流行 BitTorrent 和 WebTorrent 网络。

    3. WordPress

      WordPress 桌面是一个使用了 Electron 和 React 作为框架的桌面应用程序,提供无缝的跨平台体验,允许用户专注于他们的内容和设计,而不会被任何浏览器标签所分心。

    4. Slack

      Slack 采用了 Electron 框架构建,鉴于其高性能表现和无框架外观,将带来与浏览器完全不同的体验方式。对于寻求更集中的工作空间的团队来说,Slack Desktop 绝对是最适合的应用程序之一。

      虽然 Slack Desktop 融合了很多技术,但大多数资源文件和代码都是远程加载的,它们结合了 Chromium 的渲染引擎和 Node.js 运行时和模块系统。

    5. WhatsApp

      WhatsApp 作为下载量最高的 Messenger 应用程序,也是基于 Electron 框架构建的。Electron 帮助 WhatsApp 开发人员以低廉的成本完成了几乎所有工作,并通过更加简化和创新的技术,为用户带来全新的桌面体验方式。

    Electron 架构实现

    Electron 基本文件结构

    Electron 有一个基本的文件结构,类似于我们在创建网页时使用的文件结构:

    electron-quick-start

    • index.html 这是一个 HTML5 网页,目的用于提供画布( canvas )
    • main.js 创建窗口并处理系统事件
    • package.json 是我们应用程序的启动脚本。它将在主进程中运行,并包含有关应用程序的所有信息
    • render.js 处理应用程序的渲染过程

    Electron 的架构主要分为两部分:主进程和渲染进程

    回顾以往的 web 开发,我们的代码,无论是 HTML、CSS 还是 Javascript,都是运行在浏览器沙盒中的,我们无法越过浏览器的权限访问系统本身的资源,代码的能力被限制在了浏览器中。浏览器之所以这么做,是为了安全的考虑。设想一下,我们在使用浏览器的时候,会打开各式各样不同来源的网站,如果 JavaScript 代码有能力访问并操作本地操作系统的资源,那将是多么可怕的事情。

    假设:你在某天不小心打开了一个恶意的网站,可能你存储在硬盘上的文件就被偷走了(都用不着去修电脑)。

    但我们要开发的是桌面应用程序,如果无法访问到本地的资源肯定是不行的。Electron 将 nodejs 巧妙的融合了进来,让 nodejs 作为整个程序的管家。管家拥有较高的权限,可以访问和操作本地资源,使用原本在浏览器中不提供的高级 API。同时管家也管理着渲染进程窗口的创建和销毁。所以,我们将这个管家称之为主进程。在使用 Electron 开发的程序中,会使用 main.js 作为程序的主入口,该文件内代码执行的内容,就是主进程中执行的内容。

    主进程

    主进程控制应用程序的生命周期。Electron 用来运行 package.json 的 main 脚本的进程被称为主进程。 在主进程中运行的脚本通过创建 web 页面来展示用户界面。它内置了完整的 Node.js API,主要用于打开对话框以及创建渲染进程。此外,主进程还负责处理与其他操作系统交互、启动和退出应用程序。

    主进程就像是应用程序的管家,负责管理整个应用程序的生命周期以及所有渲染进程的创建。 按照惯例,主进程位于名为 main.js 的文件中,你可以通过在 package.json 文件中修改配置属性来更改主进程文件。

    比如,我们可以打开 package.json 并更改配置属性:

    “ main ”: “ main.js ”, =》“ main ”: “ mainTest.js ”,

    请注意,Electron 有且只有一个主进程。且主进程销毁时,所有渲染进程也将一并销毁。在 chrome 浏览器的默认策略下,每一个 tab 都是独立的进程,Electron 也正是利用了这一策略。

    渲染进程

    渲染进程是应用程序中的浏览器窗口。与主进程不同,Electron 可以有许多渲染进程,且每个进程都是独立的。由于 Electron 使用了 Chromium 来展示 web 页面,所以 Chromium 的多进程架构也被使用到。 每个 Electron 中的 web 页面运行在它自己的渲染进程中。

    正是因为每个渲染进程都是独立的,因此一个崩溃不会影响另外一个,这些要归功于 Chromium 的多进程架构。

    如何保持进程通信?

    即便 Electron 中的所有进程同时存在并保持独立运行,但他们仍然需要以某种方式进行沟通,尤其是在他们负责不同任务的时候。

    为了保持进程通信,Electron 有一个进程间通信系统( IPC 也就是内部进程通信)。您可以使用 IPC 在主进程和渲染进程之间传递信息。

    // 在主进程中
    global.sharedObject = {
    someProperty: 'default value'
    }Copy
    // 在第一个页面中
    require('electron').remote.getGlobal('sharedObject').someProperty= 'new value'Copy
    // 在第二个页面中
    console.log(require('electron').remote.getGlobal('sharedObject').someProperty)
    

    Electron 进程通信的实现方式:

    • 主进程使用 BrowserWindow 实例创建页面。每个 BrowserWindow 实例都在自己的渲染进程里运行页面。 当一个 BrowserWindow 实例被销毁后,相应的渲染进程也会被终止。
    • 主进程管理所有的 web 页面和它们对应的渲染进程。 每个渲染进程都是独立的,它只关心它所运行的 web 页面。
    • 在页面中调用与 GUI 相关的原生 API 是不被允许的,因为在 web 页面里操作原生的 GUI 资源是非常危险的,而且容易造成资源泄露。 如果你想在 web 页面里使

    用 GUI 操作,其对应的渲染进程必须与主进程进行通讯,请求主进程进行相关的 GUI 操作。

    说句题外话:在两个网页(渲染进程)间共享数据最简单的方法是使用浏览器中已经实现的 HTML5 API。 其中比较好的方案是用 Storage API,localStorage,sessionStorage 或者 IndexedDB,但这些不是今天的主题。

    如何构建 Electron 系统架构?

    为了降低构建整个 Chromium 带来的复杂度,Electron 通过 libchromiumcontent 来访问 Chromium 的 Content API。libchromiumcontent 是一个独立的、引入了 Chromium Content 模块及其所有依赖的共享库。用户不需要一个强劲的机器来构建 Electron。

    Electron 只用了 Chromium 的渲染库而不是其全部组件。这使得升 Chromium 更加容易,但也意味着 Electron 缺少了 Google Chrome 里的一些浏览器相关的特性。

    打包

    原来打包步骤略微繁琐,如今由于社区发展,产生了很多优秀的打包工具,让我们可以不用关注很多细节,(比如 asar )

    // 在主进程中
    global.sharedObject = {
    someProperty: 'default value'
    }Copy
    // 在第一个页面中
    require('electron').remote.getGlobal('sharedObject').someProperty= 'new value'Copy
    // 在第二个页面中
    console.log(require('electron').remote.getGlobal('sharedObject').someProperty)
    
    main 端
    ipcMain.on('readFile', (event, { filePath })=> {
    content content = fs.readFileSync(filePath,'utf-8');
    event.sender.send('readFileSuccess', { content});
    });
    
    renderer 端
    ipcRenderer.on('readFileSuccess', (event, {content }) => {
    console.log(`content: ${content}`);
    });
    ipcRender.send('readFile', {
    filePath: '/path/to/file',
    });
    

    我们仅需做的 :将 app 的目录结构整理好,提供对应的资源,如 icon 等,然后使用工具制作镜像即可将资源打包成为各个平台下的 APP 应用。

    打包工具的选择

    通常情况下,我们选择 Electron-builder (跨平台支持性较好,上手成本低)

    Electron 快速上手实践

    这里我们将以 SpreadJS 的一个应用为例,展示如何将 Web 应用转换为 Electron 桌面应用,在线观看地址: http://live.vhall.com/878864086

    注意事项:

    • 打包的信息都在 package.json 中配置,build 字段
    • Electron-builder 使用 nsis 将我们的文件夹制作成 exe,(NullsoftScriptable Install System) nsis 本身也是非常复杂和可值得研究的一门技术,在这里我们只要简单使用它提供的参数即可

    备注

    • Electron 目前不支持安卓和 ios (官宣)(所以和手机端的混合应用开发不相关)
    • app.makeSingleInstanceapi 实现程序互斥(即,同一时间只有一个主程序,不支持开启多个)
    • 跨域:在 BrowserWindow 中的 webPreferences 中设置 webSecurity: false 即可(但实际上非常不安全,官方有解释)
    • 数据库:和 node 本身处理数据库相差无几
    • 生命周期:正常流程会触发的生命周期如下
      • will-finish-launching:当应用程序完成基础的启动的时候被触发
      • web-contents-created:webContents 被创建完成
      • browser-window-created:BrowserWindow 被创建完成
      • ready:当 Electron 完成初始化时被触发
      • remote-require: 引入 remote 时被调用
      • before-quit: 在应用程序开始关闭窗口之前触发
      • will-quit:当所有窗口都已关闭并且应用程序将退出时发出
      • quit: 在应用程序退出时发出
      • window-all-closed:当所有的窗口都被关闭时触发
      • 这里要注意如果是进程杀死退出的所有都不触发,如果是 cmd+Q 或者开发者使用 app.quit()退出的
      • window-all-closed 是不会被触发的,基本操作一般在 ready 中处理
    • 进程相关:
      • gpu-process-crashed: 当 gpu 进程崩溃或被杀时触发。
    • 其他:
      • browser-window-focus: 在 browserWindow 获得焦点时发出
      • browser-window-blur:在 browserWindow 失去焦点时发出

    Electron 打包配置

    "build": {
    "appId": "your.id", // appid
    "productName": "程序名称",// 程序名称
    "files": [ // 打包需要的不过滤的文件
    "build/**/*",
    "main.js",
    "node_modules/**/*"
    ],
    "directories": {
    "output": "./dist-out", // 打包输出的目录
    "app": "./", // package 所在路径
    "buildResources": "assets"
    },
    "nsis": {
    "oneClick": false, // 是否需要点击安装,自动更新需要关掉
    "allowToChangeInstallationDirectory":true, //是否能够选择安装路径
    "perMachine": true // 是否需要辅助安装页面
    },
    "win": {
    "target": [
    {
    "target": "nsis", // 输出目录的方式
    "arch": [ // 输出的配置 ia32 或者 x64/x86
    "x64"
    }
    ],
    "publish": [ // 自动更新的配置
    {
    "provider": "generic", // 自己配置更新的服务器要选 generic
    "url":"http://127.0.0.1:8080/updata/" //更新配置的路径
    }
    }
    }
    

    以上就是本次 Chat 《初探 Electron,从入门到实践》的主要内容,关于 Electron 的架构层、实现层、白屏解决方案、打包方式等更多技术点,我们会在葡萄城公开课上,由刘涛为大家一一分享,欢迎大家前来学习观看: http://live.vhall.com/878864086

    目前尚无回复
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   5360 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 24ms · UTC 08:02 · PVG 16:02 · LAX 01:02 · JFK 04:02
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.