1898 words
9 minutes
MiraMate客户端开发:跨平台技术选型的探索与抉择

在启动我的个人项目 MiraMate 客户端的开发时,我面临着一个核心挑战:作为一名学生,同时也是独立开发者,精力实在有限,因此我希望尽可能使用一个能够同时适配桌面端和移动端的跨平台解决方案。这篇文章记录了我在未知领域的探索、技术选型过程中的抉择、遇到的障碍以及最终的解决思路。

最初的设想:一套代码,三个平台#

在最开始的 MiraMate v1 中我曾简单地开发过一个基于 Electron 的 Windows 客户端,但随着 MiraMate 后端重构,我打算放弃这个版本,将客户端也进行更完备的计划和重构。

我的目标非常明确:开发一款聊天应用,需要覆盖 Windows、Android(以及可能的 iOS 端)。为了避免维护多套独立的代码带来的麻烦和更多的时间精力需求,我把选择重点放在跨平台框架上。

考虑到我对 Web 前端技术栈更为熟悉,并且这类技术迁移成本较低,我首先锁定了 WebView 类型的方案。

WebView 是一种天生的跨平台应用技术,在现在的主流应用中不论是直接以 WebView 为主体进行应用开发还是把它作为一个应用组件都相当常见。

WebView 本质是一个容器接口,其实现依赖具体的浏览器内核,其功能是将网页渲染引擎(Web Rendering Engine)和 js 运行环境嵌入到原生应用中,允许应用实例化一个浏览器内核实例,执行 js 代码并处理网络请求,并将渲染结果绘制在应用程序的视图层中。 直接基于 WebView 做应用本质上是将浏览器内核作为操作系统的虚拟机,将 web 标准作为跨平台指令集,由于 web 生态非常强大,能够很容易地实现绝大多数常用功能。

使用 WebView 的应用程序的流程是运行在浏览器内核上的 web 代码处理应用逻辑并处理网络通信,并通过进程间通信(IPC)主要是 JSBridge 来与操作系统上的原生代码(Java/Kotlin/Obj-C/Swift)实现原生应用功能,不过这种运行逻辑也注定其性能存在比较明显的瓶颈,不如原生应用或像 Flutter 这样有优化的原生适配层的框架。

早期的 WebView 应用以及当前桌面端 WebView 普遍存在的一个问题是体积过大,原因在于打包应用时需要将完整的浏览器内核及 node.js 运行时打包进应用程序,然而现在 Android 系统 WebView 已经非常成熟,系统中自带完整浏览器内核及运行环境,现在的 WebView 框架通常就是一个“空壳”+“桥接代码”,相比其他自带原生渲染和代码运行时的跨平台框架如 flutter,WebView 应用体积反而要小的多。

对于一个功能相对简单的聊天应用来说,WebView 带来的些许性能损耗是完全可以接受的。

在一番调研后,我发现了 Capacitor 这个框架。它提供的特性非常有吸引力:

  • 封装了统一的 API 来调用 Android 和 iOS 的原生功能。
  • 更重要的是,它拥有一个名为 electron-capacitor 的社区插件。

electron-capacitor 插件看起来是一个很理想的方案,它有望让我用同一套代码构建出 Windows、Android 和 iOS 三个平台的应用。这对我来说,意味着可以极大地提升开发效率。

紧接着,我确定了具体的技术栈:Vue3 + Vite + TypeScript。尽管当时我对 Vue 和 TypeScript 并不算精通,但 Vue 的易上手和 TypeScript 的类型安全优势给了我更多的安全感,借助工具我相信使用他们进行开发并不是非常的困难。

第一个障碍:被废弃的插件#

万事俱备,我开始着手搭建开发环境。然而,第一个障碍很快就出现了。

我尝试创建一个新的 Capacitor 项目,并集成 electron-capacitor 插件。由于对这套技术栈不熟悉,我一边学习一边实践,花费了数小时进行尝试。然而,在安装 electron-capacitor 插件的环节,我遇到了一个难以解决的错误。

在屡次碰壁后,我决定去它的 GitHub 仓库一探究竟,结果发现:

这个项目在两年前就已经停止了更新。

这很可能意味着它已经无法与当前新版本的 Capacitor 及其他依赖兼容。因此,这个“一套代码通吃”的方案是行不通了。我不得不放弃最初的设想。

改变航向:解耦与分治#

尽管最初的计划无法实现,但开发还得继续。我迅速调整了规划:

  • 桌面端 (Windows): 使用纯 Electron 开发。
  • 移动端 (Android/iOS): 使用 Capacitor 开发。

幸运的是,我之前有过一些 Electron 的开发经验,这为后续的桌面端开发提供了一定帮助。

为了尽可能地减少重复工作量,我制定了一个核心策略:在代码层面彻底解耦 UI/UX 层和核心逻辑层

在这样的模式下,项目的开发变为了三个部分:移动端和桌面端的 UI/UX 适配,核心逻辑的编写,处理 capacitor 和 Electron 对原生功能的对接。大部分核心逻辑代码都可以直接复用,我只需要为移动端重新设计和实现 UI/UX 部分,编写少量针对两个框架的代码,显著减少跨平台开发工作量。

从使用 Capacitor 的过程中我发现:在移动端跨平台开发上,Capacitor 做的非常不错,绝大部分常用的原生功能都已经整合到了框架中,只需要使用官方插件或依赖即可轻松调用实现,而且代码相对简单易懂,可以说几乎把所有开发都集中在了 TS 代码中,只要不是有特定需求的功能,只需很简单的操作即可完成跨平台开发的全流程工作。

另一个插曲:ESM 的配置细节#

在进行 Electron 开发的过程中,我又遇到了一个小问题,这个问题是我对 ts 的现代化开发不熟悉导致的。为了代码的现代化和更好的浏览器环境兼容性,我打算全面采用 ESM (ECMAScript Modules) 语法。

然而,我发现在 Electron 的主进程(main)和预加载脚本(preload)中,ESM 模块就是无法正常工作。经过几个小时的排查,我最终在 Electron 的官方文档中找到了答案:

在 Electron 中,如果主进程和预加载脚本要使用 ESM,其文件扩展名必须.mjs

而 vite 自动编译出的文件拓展名是.js,这个小插曲也再次提醒我,仔细阅读官方文档的重要性。

虽然 MiraMate 的开发之路开局遇到了一些波折,但这些经历让我对技术选型、项目规划和风险评估有了更深刻的理解。开发本身就是一个不断遇到问题、解决问题的过程,而每一次解决问题的过程,都是宝贵的学习机会。

最终客户端完成界面

MiraMate客户端开发:跨平台技术选型的探索与抉择
https://contrue.top/posts/miramateclientdev/
Author
contrueCT
Published at
2025-08-16
License
CC BY-NC-SA 4.0