基于Web的跨平台桌面应用开发

栏目:义务教育  时间:2023-03-27
手机版

  Tech

  导读

  本文主要介绍了目前比较流行,常用的桌面应用开发技术及其架构,并以实战的方式去对比,读者可以了解到 Electron 和 Tauri 的优势及劣势,以及桌面应用开发的趋势。

  01

  前言

  在今年的敏捷团队建设中,我通过Suite执行器实现了一键自动化单元测试。Juint除了Suite执行器还有哪些执行器呢?由此我的Runner探索之旅开始了!

  近些年来,跨平台跨端一直是比较热门的话题,Write once, run anywhere一直是开发者所期望的,跨平台方案的优势十分明显,对于开发者而言,可以做到一次开发、多端复用,一套代码就能够运行在不同设备上,这在很大程度上能够降低研发成本,同时能够在产品效能上做到快速验证和快速上线。如今跨端跨平台的优秀技术方案也比较多:

  移动端:React Native,Flutter,Weex;

  小程序端:Taro,Uniapp;

  桌面端:NW.js,Electron,Flutter for desktop,Tauri,Wails。

  。。

  02

  什么是跨平台

  理解,首先 MCube 会依据模板缓存状态判断是否需要网络获取最新模板,当获取到模板后进行模板加载,加载阶段会将产物转换为视图树的结构,转换完成后将通过表达式引擎解析表达式并取得正确的值,通过事件解析引擎解析用户自定义事件并完成事件的绑定,完成解析赋值以及事件绑定后进行视图的渲染,最终将目标页面展示到屏幕。

  泛指编程语言、软件或硬件设备可以在多种操作系统或不同硬件架构的电脑上运作。一般来说,有这几种场景,分别是跨设备平台(如 PC 端和移动端),跨操作系统,(移动端中分Android,IOS,PC端中分 Windows,macOS,Linux),国内的小程序(微信,京东,百度,支付宝,字节跳动等等)。

  03

  跨平台的技术方案

  理解,首先 MCube 会依据模板缓存状态判断是否需要网络获取最新模板,当获取到模板后进行模板加载,加载阶段会将产物转换为视图树的结构,转换完成后将通过表达式引擎解析表达式并取得正确的值,通过事件解析引擎解析用户自定义事件并完成事件的绑定,完成解析赋值以及事件绑定后进行视图的渲染,最终将目标页面展示到屏幕。

  跨平台编程不是一件容易的事情,这是由于在不同平台之间,有许多小而复杂的差异,这都需要考虑周全,目前已经有了较多成熟的跨平台技术方案,能够减小开发者的开发成本及跨平台的难易程度。

  NW.js

  Electron

  Flutter for Desktop

  Tauri

  Wails

  

  图1 NW.js 官网描述

  3.1NW.js

  官网:https://nwjs.io/

  GitHub:https://github.com/nwjs/nw.js

  语言:Nodejs + 前端任意框架

  代表项目:微信小程序 IDE,京东小程序 IDE

  NW.js(node-webkit )是一个基于 Chromium 和 Node.js 的 Web 运行环境,可直接在 DOM 中调用 Node.js 模块,并可使用任何现有的 Web 技术来编写本地应用。

  

  图2 Electron 官网描述

  3.2Electron

  官网:https://www.electronjs.org/

  GitHub:https://github.com/electron/electron

  语言:Nodejs + 前端任意框架

  代表项目:VSCode,百度小程序 IDE,京 ME,Facebook Message,

  Electron 的前身叫做 Atom-Shell,本来是 GitHub 发布开源编辑器 Atom 时一并发布的副产物,但是后来这个副产物的影响力远远的超过了 Atom 本身,于是便改名为一个独立专案,也就是现在的 Electron。Electron 的本质很简单,就是 Chromium + Node.js 的组合,两者之间通过 IPC 通讯。

  类似于 NW.js,表面上,它们似乎非常相似,但是这两个项目有本质上的区别,使得 Electron 和 NW.js 成为两个完全独立的产品:

  应用入口不同,NW.js 主入口是一个 HTML,Electron 中是 JavaScript,可操作性更强;

  Node 集成方式不同,在 NW.js 中网页中的 Node 需要通过给 Chromium 打补丁来实现,Electron 则是通过各个平台的消息循环与 libuv 的循环集成,避免了直接在 Chromium 上做改动;

  支持的功能数量上有明显的差距,Electron 有着较大的社区及社区活跃度,大量成熟的 npm 功能模块。

  

  图3 Tauri 官网描述

  3.3Tauri

  官网:https://tauri.app/

  GitHub:https://github.com/tauri-apps/tauri

  语言:Rust + 前端任意框架

  代表项目:仅有少量开源应用

  Tauri 是 2021年 JavaScript 明星项目的最受欢迎项目中排名第5,在 stateofjs 2021 中 满意度和关注度排名第1, 由于 Vite,esbuild,swc,Rome 等工具的大火,让基于 Go、Rust 的高效率构建类工具进入爆发期,加上 Bundleless 的构建体验,让 Rust、Go 成为前端开发者的又一扇门。由于 Tauri 的 Rust 背景,加上构建产物小,内存占用低,还是值得长期关注的。

  

  图4 Tauri 在 JavaScript 明星项目和 stateofjs 中的排名

  题外话:Rust 前景还是非常不错的,如 Linux内核接纳 Rust,deno采用 Rust,微软拥抱Rust,fuchsia 的 Rust 代码占比超50%,Apple 在底层 all-in rust,连续6年的 stackoverflow 最受欢迎语言,但学习门槛较高。

  

  图5 Wails 官网描述

  3.4Wails

  官网:https://wails.io/

  GitHub:https://github.com/wailsapp/wails

  语言:Go + 前端任意框架

  Wails 是一个可让您使用 Go 和 Web 技术编写桌面应用的项目。可以将其看作为 Go 的快并且轻量的 Electron 替代品;可以使用 Go 的灵活性和强大功能,结合丰富的现代前端,轻松的构建应用程序。与 Tauri 类似,Windows 上使用的是 Webview2。

  

  图6 Flutter 官网描述

  3.5Flutter for Desktop

  官网:https://flutter.dev/multi-platform/desktop

  GitHub:https://github.com/flutter/flutter

  语言:Dart

  从渲染原理看 Flutter 是 skia 自绘性能优于 Electron,但需要考虑下稳定性和生态。

  04

  跨平台的架构原理

  理解,首先 MCube 会依据模板缓存状态判断是否需要网络获取最新模板,当获取到模板后进行模板加载,加载阶段会将产物转换为视图树的结构,转换完成后将通过表达式引擎解析表达式并取得正确的值,通过事件解析引擎解析用户自定义事件并完成事件的绑定,完成解析赋值以及事件绑定后进行视图的渲染,最终将目

  本节将讨论使用较多的 Electron 和较有前景的 Tauri 的架构原理。

  

  图7 Electron 架构组成

  通过 Web 技术写 UI,赋予了底层能力,达到跨平台的能力及体验。

  4.1Chromium 多进程架构

  大多数现代 Web 浏览器都为多进程架构,主要有浏览器主进程、渲染进程、插件进程、网络进程、GPU 进程,Chromium 也是如此。

  IPC = Inter-Process Communication 进程间通信

  

  图8 Chromium 架构图

  Chromium 是 Chrome 的开源版,同时也是一个浏览器。

  主进程的 RenderProcessHost 和渲染进程的 RenderProcess 负责处理 IPC 事件;

  渲染进程的 RenderView,页面的展示会在这里基于 Webkit 排版出来;

  ResourceDispatcher 处理资源请求,当页面需要请求资源时,通过 ResourceDispather 创建一个请求 ID 转发到 IPC,在 Browser 进程中处理后返回。

  4.2Electron 架构

  

  图9 Election 架构图

  在每个进程中暴露了 Native API(Main Native API,Renderer Native API)

  引入 Node.js

  Web 技术实现 UI

  4.3Electron 进程模型

  Electron 继承了来自 Chromium 的多进程架构,这使得此框架在架构上非常相似于一个现代的网页浏览器。

  为何采用多进程架构?

  网页浏览器是个极其复杂的应用程序。除了显示网页内容的主要能力之外,它还有许多次要的职责,例如:管理众多窗口 ( 或 标签页 ) 和加载第三方扩展。

  在早期,浏览器通常使用单个进程来处理这些功能。这种模式虽然能减小打开每个标签页的开销,但也同时意味着一个网站的崩溃或无响应会影响到整个浏览器。

  为了解决这个问题,Chrome 团队决定让每个标签页在自己的进程中渲染, 从而限制一个网页上的有误或恶意代码可能导致的对整个应用程序造成的伤害,然后用单个浏览器进程控制这些标签页进程,以及整个应用程序的生命周期。

  

  图10 多进程架构

  Electron 也是如此,作为应用开发者,控制着两种类型的进程,主进程和渲染进程:主进程负责应用程序窗口管理,应用程序的生命周期,原生API等;渲染进程负责UI的展示,这部分可以选择任意前端框架 Vue、React、Svelte、Preact。

  4.4Tauri 进程模型

  Tauri 采用了一种类似 Electron 和大多数现代Web浏览器那样的多进程架构。包括主进程和 WebView进程,单个主进程管理一个或多个 WebView 进程。

  

  图11 Tauri 进程模型

  4.5进程间通信

  Electron 的进程通信:渲染器进程 -> 主进程

  (双向)ipcRenderer.invoke 与 ipcMain.handle 搭配使用来完成

  (单向)ipcRenderer.send API 发送消息,然后使用 ipcMain.on API 接收

  大多数现代 Web 浏览器都为多进程架构,主要有浏览器主进程、渲染进程、插件进程、网络进程、GPU 进程,Chromium 也是如此。

  05

  实战-导航启动工具

  理解,首先 MCube 会依据模板缓存状态判断是否需要网络获取最新模板,当获取到模板后进行模板加载,加载阶段会将产物转换为视图树的结构,转换完成后将通过表达式引擎解析表达式并取得正确的值,通过事件解析引擎解析用户自定义事件并完成事件的绑定,完成解析赋值以及事件绑定后进行视图的渲染,最终将目标页面展示到屏幕。

  为了对比 Electron 和 Tauri 差异性可以分别用 Electron 和 Tauri 做一个简单的应用,导航启动器,类似 Alfred,Spotlight。

  5.1功能描述

  首先来描述下这个应用的功能,启动应用后,通过快捷键 Ctrl/Command + K 唤起应用界面 - 一个输入框,在输入框输入关键词 git 会展示 git 相关的系统名称列表,选择后回车即可打开 github.com,相当于另类的书签。

  5.2设计思路

  

  图12 导航启动工具流程图

  5.3项目结构及实现

  Electron 使用的是 Electron React Boilerplate 脚手架,使用 webpack 构建 UI 部分;Tauri 是使用官方的脚手架工具 - create-tauri-app,内置了 Vite,在前端框架上选了 React。

  

  图13 Electron 与 Tauri 项目结构图

  这个导航启动器主要涉及的功能点有:

  1. 整个应用不展示关闭,最小化,最大化的按钮及整个菜单栏(menuBar),无边框窗口;

  2. 视觉上整个应用是一个输入框,应用窗口的高度是根据网页内容的高度自适应;

  3. 注册全局快捷键,显示应用,隐藏应用;

  4. 监听按键,并使用默认浏览器打开链接。

  5.3.1 功能点一

  Electron 通过对主窗口初始化时修改配置,frame 设置成 false 可实现无边框窗口。

  

  图14 Election 配置

  在 Tauri 中,实现无边框窗口有 3 种方式:通过 tauri.conf.json 配置,通过 Tauri 提供的 JS API - @tauri-apps/api,通过 Rust 原生修改 window;这里我们选用在 tauri.config.json 中配置。

  

  图15 Tauri 配置

  5.3.2 功能点二

  其输入框部分均由 React 实现,主要的差异在窗体根据内容高度动态调整窗体的高度,根据 document.body.offsetHeight 的高度设置 mainWindow 的高度;在 Electron 中,可以在渲染进程中发 IPC 通知主进程去修改,主进程监听到消息后进行高度修改。

  

  图16 Electron IPC 通信修改

  在 Tauri 中,相对比较方便,对于常用的功能都封装了 JS API,也就是前面提到的 @tauri-apps/api,直接导入方法调用即可。

  

  图17 Tauri 在渲染进程修改

  5.3.3 功能点三

  注册全局快捷键,控制 mainWindow 的显示和隐藏。在 Electron 中,首先定义 registerGlobalShortcut 方法,在 app 启动后注册快捷键,主要是在主进程中操作。

  

  图18 Election 注册快捷键

  在 Tauri 中,得益于 JS API 的便利性,在渲染进程中就可以注册,因此只需要在 React 生命周期中执行注册。

  

  图19 Tauri 注册快捷键

  5.3.4 功能点四

  为了方便演示,将直接对 document.body 进行 onkeydown 监听,上下光标选择对应的选项,回车或点击使用默认浏览器打开对应的链接,这里两者的实现很相似。

  

  图20 Electron 与 Tauri 打开 URL

  至此,主要功能已经完成,下一步将进入打包多平台的应用方式。

  5.4应用打包

  Electron 中比较常见的有两种打包,electron-packager 和 electron-builder,electron-builder 的生态更好,这里选择 electron-builder。

  

  图21 Electron 打包

  Tauri 中则是内置在 cli 的打包方案,执行 yarn tauri build 即可。

  表1 同一应用对比,相同 React 版本,未使用 UI 框架

  

  

  图22 内存占用对比图

  

  图23 Tauri 官方对比图

  5.4应用更新

  两者都有对应的解决方案,具体内容可以查看官方文档。

  06

  总结

  理解,首先 MCube 会依据模板缓存状态判断是否需要网络获取最新模板,当获取到模板后进行模板加载,加载阶段会将产物转换为视图树的结构,转换完成后将通过表达式引擎解析表达式并取得正确的值,通过事件解析引擎解析用户自定义事件并完成事件的绑定,完成解析赋值以及事件绑定后进行视图的渲染,最终将目标页面展示到屏幕。

  1. NW.js 的时代已经过去,考虑 NW.js 的可以优先 Electron。

  2. Tauri 表现不错,前景较好。它解决了 Electron 现有的很多问题,带来了简单便捷的开发体验,也期待 Tauri 的 roadmap 中集成 Deno 作为应用的后端处理,这样就可以继续使用 JavaScript/TypeScrupt 来实现应用后端逻辑,新项目可以考虑使用,但是还有一些问题需要改进以及 Rust 的学习曲线曲折,有一定的学习成本。

  3. Electron 目前仍是最多的选择,得益于自身庞大的社区,丰富的功能及工程实践,但性能优化这部分比较考验开发者。

  打造SAAS化服务的会员徽章体系,可以作为标准的产品化方案统一对外输出。结合现有平台的通用能力,实现会员行为全路径覆盖,并能结合企业自身业务特点,规划相应的会员精准营销活动,提升会员忠诚度和业务的持续增长。

  底层能力:维护用户基础数据、行为数据建模、用户画像分析、精准营销策略的制定

  ?功能支撑:会员成长体系、等级计算策略、权益体系、营销底层能力支持

  ?用户活跃:会员关怀、用户触达、活跃活动、业务线交叉获客、拉新促活

上一篇:原创从小就给孩子上各种培训班你后悔了吗?
下一篇:因为张译追的《他是谁》,结果被混乱不堪的剧情劝退了

最近更新义务教育