跨平台不是"能不能跑",而是"用哪条技术路线换哪种确定性"。
选错框架的代价:某团队用 Electron 做笔记应用,上线后用户反馈"启动 5 秒,内存 500MB"。重构用了 3 个月。如果一开始选 Tauri 或 Wails,这个坑完全可以避免。
一、先搞懂底层逻辑:UI 是怎么画到屏幕上的
不同的"画法"决定了框架的基因,也决定了它擅长什么、不擅长什么。
1.1 四种技术路线
路线一:自绘渲染(Self-rendering)
框架自己实现渲染引擎,拿到系统给的"画布",一笔一画把 UI 画出来。
类比:买一块空白画布,用自己的颜料和画笔画画。风格完全由你决定,跟画布品牌没关系。
┌─────────────────────────────────────┐
│ 你的应用代码 │
├─────────────────────────────────────┤
│ 框架的渲染引擎 │ ← 这一层是框架自己实现的
├─────────────────────────────────────┤
│ 系统图形 API (Metal/Vulkan/GL) │
├─────────────────────────────────────┤
│ GPU │
└─────────────────────────────────────┘
| 优势 | 劣势 |
|---|---|
| 跨端一致性极强 | 包体更大(要打包渲染引擎) |
| 动效表现好(60fps/120fps) | 与系统"格格不入"(iOS 橡皮筋、Android Material You 需额外适配) |
| 可控性高 | 无障碍支持需额外工作 |
代表:Flutter、Qt Quick、GPUI、Dioxus(Blitz 模式)、Slint
路线二:原生控件映射(Native Bridging)
框架把你写的代码"翻译"成原生控件调用。你写 <Button>,框架帮你调用 iOS 的 UIButton 或 Android 的 MaterialButton。
类比:你是导演,给演员(原生控件)下指令。iOS 演员演得像 iOS,Android 演员演得像 Android。
┌─────────────────────────────────────┐
│ 你的应用代码 │
├─────────────────────────────────────┤
│ 框架的桥接层 (Bridge) │ ← 翻译 + 通信
├─────────────────────────────────────┤
│ 原生控件 (UIKit / Android Views) │
├─────────────────────────────────────┤
│ 系统 │
└─────────────────────────────────────┘
| 优势 | 劣势 |
|---|---|
| 原生体验(用的就是原生控件) | 跨端一致性差(同一代码不同平台长得不一样) |
| 系统功能集成方便 | 有"桥接"成本(JS 和原生通信需序列化/反序列化) |
| 无障碍支持天然继承 | 复杂动效难做 |
代表:React Native、.NET MAUI、Uno Platform、NativeScript、Lynx、Valdi
路线三:WebView / Chromium 方案
用 Web 技术栈写 UI,通过 WebView 或内嵌 Chromium 渲染。
类比:在应用里开了一个"浏览器窗口",你的 UI 实际上是一个网页。
┌─────────────────────────────────────┐
│ 你的 Web 应用 (HTML/CSS/JS) │
├─────────────────────────────────────┤
│ WebView / Chromium / 系统浏览器 │
├────────────────┬────────────────────┤
│ 后端进程 │ 系统 API 调用 │
│ (Node/Rust/Go) │ │
└────────────────┴────────────────────┘
| 优势 | 劣势 |
|---|---|
| 前端团队无缝上手 | 资源占用(Chromium 吃内存) |
| 生态巨大(npm 百万包) | 启动慢(要初始化浏览器引擎) |
| 开发效率高(热更新、DevTools) | "不够原生"(滚动、右键菜单需额外打磨) |
代表:Electron、Tauri、Wails、Electrobun
路线四:逻辑共享优先(Shared Logic First)
只共享业务逻辑和数据层,UI 各平台自己写。
类比:后厨(业务逻辑)是统一的,但前台装修(UI)各店不同。
┌──────────────────────────────────────────────────┐
│ 共享层 (Kotlin) │
│ 网络、数据库、业务逻辑、状态管理 │
├─────────────────┬────────────────┬───────────────┤
│ Android UI │ iOS UI │ Desktop UI │
│ (Compose) │ (SwiftUI) │ (Compose) │
└─────────────────┴────────────────┴───────────────┘
| 优势 | 劣势 |
|---|---|
| 原生体验最佳 | UI 要写多份(除非用 Compose Multiplatform) |
| 渐进式迁移 | 团队需掌握多平台 UI 开发 |
| 风险可控 | 共享层边界需仔细设计 |
代表:Kotlin Multiplatform (KMP)
1.2 路线选择决策树
你的核心诉求是什么?
│
┌─────────────────┼─────────────────┐
▼ ▼ ▼
跨端一致性 原生体验 开发效率
视觉完全统一 系统深度集成 快速上线
│ │ │
▼ ▼ ▼
自绘渲染 原生映射 WebView 方案
Flutter/ RN/MAUI/Uno/ Electron/Tauri/
Slint/Qt/GPUI NativeScript/KMP Wails/Dioxus
二、按语言生态分组:你团队写什么,就选什么赛道
选框架的第一刀不是"哪个框架好",而是"你团队用什么语言"。语言决定了你能高效使用的框架范围,也决定了学习曲线的起点。
2.1 JavaScript / TypeScript 赛道
这是最大的赛道——前端开发者天然能进入的框架最多,但细分方向差异极大。
| 框架 | 技术路线 | 定位 | 平台 | 生产就绪 |
|---|---|---|---|---|
| React Native | 原生映射 | React 写原生移动应用 | 移动端 | ★★★★☆ |
| Electron | WebView(Chromium) | Web 技术做桌面应用的事实标准 | 桌面 | ★★★★★ |
| Tauri | WebView(系统) | Electron 的轻量替代,Rust 后端 | 全平台 | ★★★★☆ |
| Wails | WebView(系统) | Go 后端 + 前端 UI 的桌面方案 | 桌面 | ★★★★☆ |
| NativeScript | 原生映射 | Vue/Angular 写原生移动应用 | 移动端 | ★★★☆☆ |
| Electrobun | WebView(系统) | 用 Bun 替 Node.js 的 Electron 变体 | 桌面 | ★★☆☆☆ |
| Lynx | 原生映射+自绘混合 | 字节跳动的高性能移动方案 | 移动端 | ★★☆☆☆ |
三组关键对决:
① React Native vs NativeScript:React 还是 Vue?
| 维度 | React Native | NativeScript |
|---|---|---|
| 框架绑定 | React | Vue / Angular / Vanilla |
| 原生访问方式 | 通过桥接层 | 直接访问原生 API(无桥接) |
| 生态规模 | 极大 | 较小 |
| 典型用户 | Facebook/Instagram、Shopify、Discord | SAP 企业应用 |
一句话:React 团队无脑选 RN;Vue/Angular 团队选 NativeScript。
② Electron vs Tauri vs Wails:桌面应用怎么选?
| 维度 | Electron | Tauri | Wails |
|---|---|---|---|
| 渲染引擎 | 内嵌 Chromium | 系统 WebView | 系统 WebView |
| 后端语言 | Node.js | Rust | Go |
| 空项目包体 | ~150MB | ~3-10MB | ~5-15MB |
| 空项目内存 | ~80-150MB | ~15-30MB | ~20-40MB |
| 启动速度 | 慢 | 快 | 快 |
| 安全模型 | 需手动配置 | 默认 CSP + 最小权限 | 类 Tauri |
| 移动端 | 无 | Tauri 2 已支持 | 实验性 |
| 学习曲线 | 极低(纯前端) | 中(需 Rust 基础) | 低-中(Go 易上手) |
一句话:不碰 Rust/Go → Electron;愿意学 Rust → Tauri;Go 团队 → Wails。
③ Lynx:RN 的挑战者?
字节跳动 2025 年开源,双线程架构(UI 线程 + JS 线程),原生映射与自绘混合渲染。对 RN 桥接性能不满意的团队可以关注,但目前生态尚早。
2.2 Dart 赛道
Flutter——Dart 几乎只有一个选择,但这个选择足够强。
| 维度 | 说明 |
|---|---|
| 语言 | Dart(语法类似 Java/JS 混合体,AOT 编译) |
| 渲染 | Skia → 正在迁移到 Impeller(iOS 已默认启用) |
| 架构 | Widget 树 + 声明式 UI |
| 空项目包体 | ~4-5MB |
| 空项目内存 | ~30-50MB |
| 平台 | Android / iOS / Web / Windows / macOS / Linux |
Flutter 的核心优势:跨端一致性——因为渲染引擎自己画,不依赖系统控件,同一份代码在所有平台视觉完全统一。
Flutter 的核心代价:与系统"格格不入"——iOS 的橡皮筋效果、Android 的 Material You 动态取色、系统级无障碍,都需要额外适配。
真实案例:Google Pay(全球支付应用,Flutter 重写后开发效率提升 70%)、阿里闲鱼(首页 Flutter 实现)、BMW 车载信息娱乐系统
常见坑:热重载偶尔失效需热重启;--split-debug-info + --obfuscate 可减包体 ~30%;iOS 审核需确保 Info.plist 权限说明清晰
2.3 C# 赛道
两个框架,一个微软官方、一个社区先行者,核心区别在于 WebAssembly 支持。
| 维度 | .NET MAUI | Uno Platform |
|---|---|---|
| 发布时间 | 2022 | 2018 |
| API 来源 | Xamarin.Forms 演进 | WinUI / UWP |
| WebAssembly | 不支持 | 支持(核心差异点) |
| Linux 支持 | 有限 | 通过 Skia 支持 |
| 渲染模式 | 原生控件映射 | 三种可选:Skia 自绘 / 原生映射 / WebAssembly |
| 典型场景 | 企业内部应用(Azure/O365 集成) | 需 WASM + 更广平台覆盖 |
一句话:不需要 WASM → MAUI;需要 WASM 或更广平台 → Uno。
2.4 C++ 赛道
Qt——30 年历史的工业级方案,嵌入式和桌面的"老大哥"。
| 维度 | 说明 |
|---|---|
| 语言 | C++(核心)+ QML(声明式 UI) |
| 渲染 | RHI(支持 Vulkan/Metal/D3D/OpenGL) |
| 架构 | 信号槽机制 + 属性绑定 |
| 许可证 | 开源版(LGPL/GPL)免费但有限制;商业版 ~$300-500/月/人 |
真实案例:特斯拉 Model S/X 早期车载系统、达芬奇手术机器人控制界面、Autodesk Maya 部分 UI、VirtualBox 管理界面
适合:工业软件、医疗设备、汽车 HMI、嵌入式系统——这些领域对稳定性和确定性要求远高于开发效率
不适合:快速原型验证、小团队短周期项目、纯移动端消费级应用
2.5 Kotlin 赛道
Kotlin Multiplatform (KMP)——不共享 UI,只共享逻辑,"最小侵入"的跨平台方案。
| 维度 | 说明 |
|---|---|
| 语言 | Kotlin |
| 共享层 | 网络、数据库、业务逻辑、状态管理 |
| UI 层 | 各平台原生(Android Compose / iOS SwiftUI / Desktop Compose) |
核心价值:渐进式迁移——你可以从 Android 项目开始,一点点把逻辑抽到共享层,iOS 端仍然写原生 SwiftUI。不像其他框架要求"全有或全无"。
真实案例:Netflix(部分共享逻辑)、VMware(企业应用)、 Philips(医疗设备软件)
不适合:需要 UI 也跨平台共享的团队(虽然 Compose Multiplatform 在补这块短板,但 iOS 端仍是 Alpha)
2.6 Rust 赛道
Rust 赛道是最热闹的新战场——三个框架各切一个角度。
| 框架 | 定位 | 渲染方式 | 目标平台 | 生产就绪 |
|---|---|---|---|---|
| Tauri | Electron 的轻量替代 | 系统 WebView | 全平台 | ★★★★☆ |
| Dioxus | Rust 全栈 UI(类 React 语法) | 桌面默认 WebView,可选 Blitz 自绘 | 全平台 | ★★★☆☆ |
| GPUI | 为 Zed 编辑器而生的 GPU 加速框架 | 自绘(Metal 优先) | macOS 优先 | ★★☆☆☆ |
三者怎么选:
- 前端团队 + Rust 后端 → Tauri(前端照写 HTML/CSS/JS,Rust 只管后端)
- 想用 Rust 统一前后端 → Dioxus(类 React 组件+Hooks 语法,一套 Rust 跑全平台)
- 追求极致渲染性能 → GPUI(GPU 直绘,但 macOS 优先,Linux 实验性,生态极小)
2.7 Go 赛道
Wails——Go 团队做桌面应用的唯一主流选择。Go 后端 + 前端 UI + 系统 WebView,定位就是"Go 版 Tauri"。
与 Tauri 的取舍:Rust 更安全更极致,Go 更简单更易上手。后端逻辑重的应用(数据库工具、网络代理、CLI 包装器)天然适合 Go。
2.8 嵌入式专用赛道
Slint——极小包体 + 低资源消耗的嵌入式 UI 方案。
| 维度 | 说明 |
|---|---|
| 语言 | .slint 标记语言 + Rust/C++/JS 绑定 |
| 渲染 | 自绘(Skia/FemtoVG/软件渲染) |
| 空项目包体 | ~0.5-3MB |
| 空项目内存 | ~1-10MB |
与 Qt 的取舍:Qt 生态大但重,Slint 极轻但组件少。MCU 和资源受限的嵌入式场景选 Slint;需要完整组件库和工具链的工业场景选 Qt。
三、真实案例图谱
案例比参数更能说明"谁在用、用来做什么、效果如何"。
3.1 移动端案例
| 应用 | 框架 | 场景 | 效果 |
|---|---|---|---|
| Google Pay | Flutter | 全球支付应用,品牌一致性要求高 | 重写后开发效率提升 70% |
| 阿里闲鱼 | Flutter | 二手交易首页,重交互 | 首页用 Flutter 实现,双端一致 |
| BMW 车载 | Flutter | 车载信息娱乐系统 | 跨车型统一 UI |
| Facebook/Instagram | React Native | 社交应用部分页面 | 复用 React 生态 |
| Shopify | React Native | 商家管理应用 | 中等复杂度,RN 够用 |
| Discord | React Native | 移动端部分功能 | 原生体验 + 前端效率 |
3.2 桌面端案例
| 应用 | 框架 | 场景 | 效果 |
|---|---|---|---|
| VS Code | Electron | 代码编辑器 | 证明 Electron 可以做高性能应用(内存 300-800MB) |
| Slack | Electron | 团队协作 | Web 技术快速交付 |
| Figma 桌面端 | Electron | 设计工具 | 重度 Canvas 渲染 |
| DBX | Tauri 2 | 数据库管理工具 | 安装包 ~15MB,启动快 |
| Zed | GPUI | 代码编辑器 | GPU 加速渲染,极致启动速度 |
3.3 工业 / 嵌入式案例
| 应用 | 框架 | 场景 | 效果 |
|---|---|---|---|
| 特斯拉 Model S/X 早期 | Qt | 车载系统 | 工业级稳定性 |
| 达芬奇手术机器人 | Qt | 控制界面 | 医疗级可靠性 |
| Autodesk Maya | Qt | 部分 UI | 复杂 3D 交互 |
| Netflix | KMP | 共享业务逻辑 | 渐进式迁移,iOS 仍写原生 |
3.4 案例启示
- Flutter 在品牌型应用和车载系统中反复出现——视觉一致性是它的杀手锏
- Electron 的成功案例证明了"Web 技术也能做出专业应用",但代价是内存——VS Code 吃 800MB 也被接受,但你的应用未必有这个底气
- Tauri 正在从开发者工具切入(DBX 等数据库管理工具),轻量是它的入场券
- KMP 的典型案例不是"全应用跨平台",而是"关键逻辑共享"——更务实的中间路线
- Qt 的案例几乎都在工业和医疗——这些领域不需要时髦,需要稳定运行 10 年
四、核心指标矩阵
4.1 包体与资源
| 框架 | 空项目包体 | 空项目内存 | 启动速度 | 技术路线 |
|---|---|---|---|---|
| Slint | ~0.5-3MB | ~1-10MB | 极快 | 自绘 |
| Tauri | ~3-10MB | ~15-30MB | 快 | WebView |
| Flutter | ~4-5MB | ~30-50MB | 快 | 自绘 |
| React Native | ~3-5MB | ~35-60MB | 中 | 原生映射 |
| Wails | ~5-15MB | ~20-40MB | 快 | WebView |
| Dioxus | ~3-15MB | ~15-40MB | 快 | WebView/自绘 |
| GPUI | ~5-10MB | ~20-40MB | 快 | 自绘 |
| Qt | ~10-30MB | ~20-50MB | 快 | 自绘 |
| .NET MAUI | ~10-20MB | ~40-80MB | 中 | 原生映射 |
| Electron | ~150MB | ~80-150MB | 慢 | WebView(Chromium) |
4.2 平台覆盖
| 框架 | Android | iOS | Web | Windows | macOS | Linux | 嵌入式 |
|---|---|---|---|---|---|---|---|
| Flutter | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ○ |
| Tauri | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✗ |
| Qt | ✓ | ✓ | ○ | ✓ | ✓ | ✓ | ✓ |
| KMP | ✓ | ✓ | ○ | ✓ | ✓ | ✓ | ✗ |
| Dioxus | ✓ | ○ | ✓ | ✓ | ✓ | ✓ | ○ |
| Slint | ○ | ○ | ✓ | ✓ | ✓ | ✓ | ✓ |
| React Native | ✓ | ✓ | ○ | ○ | ○ | ○ | ✗ |
| .NET MAUI | ✓ | ✓ | ✗ | ✓ | ✓ | ○ | ✗ |
| Wails | ○ | ○ | ✗ | ✓ | ✓ | ✓ | ✗ |
| Electron | ✗ | ✗ | ✓ | ✓ | ✓ | ✓ | ✗ |
| GPUI | ✗ | ✗ | ✗ | ✗ | ✓ | ○ | ✗ |
4.3 学习曲线与生态
| 框架 | 学习曲线 | 生态规模 | 生产就绪 | 语言 |
|---|---|---|---|---|
| Electron | 极低 | 极大 | ★★★★★ | JS/TS |
| React Native | 低 | 极大 | ★★★★☆ | JS/TS |
| Wails | 低-中 | 中 | ★★★★☆ | Go + JS/TS |
| Flutter | 中 | 大 | ★★★★★ | Dart |
| Tauri | 中(Rust 门槛) | 中 | ★★★★☆ | Rust + JS/TS |
| KMP | 中 | 中 | ★★★★☆ | Kotlin |
| .NET MAUI | 中 | 大 | ★★★☆☆ | C# |
| Slint | 中 | 小 | ★★★☆☆ | Rust/C++/JS |
| Qt | 高 | 大 | ★★★★★ | C++/QML |
| Dioxus | 高 | 小 | ★★★☆☆ | Rust |
| GPUI | 高 | 极小 | ★★☆☆☆ | Rust |
五、快速决策表
| 你的场景 | 推荐框架 | 理由 |
|---|---|---|
| 移动端为主,视觉一致性优先 | Flutter | 自绘渲染,跨端一致性最强 |
| React 团队,移动端为主 | React Native | React 生态直接复用,原生体验好 |
| Vue/Angular 团队,移动端 | NativeScript | 直接用 Vue/Angular 写原生应用 |
| 桌面工具,前端团队 | Tauri | 轻量(3-10MB),Rust 安全,系统 WebView |
| 桌面工具,Go 团队 | Wails | Go 后端 + 前端 UI,易上手 |
| 桌面工具,前端团队,不碰 Rust | Electron | 生态最大,但包体和内存大 |
| 工业/嵌入式,功能完备 | Qt | 工业级稳定性,组件库齐全 |
| 工业/嵌入式,资源极度受限 | Slint | 极小包体(0.5-3MB),确定性性能 |
| Android 优先,想渐进迁移 | KMP | 只共享逻辑,UI 原生,风险可控 |
| C# 团队,企业应用 | .NET MAUI | 微软生态集成好 |
| C# 团队,需 WebAssembly | Uno Platform | 唯一支持 WASM 的 C# 方案 |
| Rust 全栈,前端用 Web | Tauri | Rust 后端 + 前端自由 |
| Rust 全栈,UI 也想用 Rust | Dioxus | 类 React 语法,一套 Rust 跑全平台 |
| 追求极致 GPU 渲染性能 | GPUI | GPU 直绘,但生态极小 |
六、选型的底层逻辑
6.1 没有银弹,只有取舍
你不可能同时获得:
跨端一致性 + 原生体验 + 小包体 + 低学习成本
自绘渲染 → 一致性 ↑,原生体验 ↓
原生映射 → 原生体验 ↑,一致性 ↓
WebView → 开发效率 ↑,性能 ↓
逻辑共享 → 原生体验 ↑,UI 开发量 ↑
6.2 选型的三个维度
- 团队语言:选团队最熟的语言,学习曲线比框架差异更致命
- 目标平台:移动优先 vs 桌面优先 vs 全平台,直接砍掉一半选项
- 核心约束:包体敏感?启动速度?原生体验?一致性?——最不能妥协的那条决定路线
6.3 新框架的"值得试水"阈值
| 框架 | 状态 | 建议 |
|---|---|---|
| Tauri | 已过阈值 | 生产可用,尤其桌面工具场景 |
| Wails | 已过阈值 | Go 团队的桌面首选 |
| Slint | 嵌入式已可 | 嵌入式场景可生产使用,通用场景慎用 |
| Dioxus | 未过阈值 | Rust 爱好者可试,生产环境需谨慎 |
| Lynx / Electrobun / GPUI | 早期 | 观望,等 1.0 |
总结
跨平台框架的选择本质上是在回答一个问题:你愿意用哪种确定性,换哪种不确定性?
- 选 Flutter:确定性是跨端一致性,不确定性是 Dart 生态和系统深度集成
- 选 React Native:确定性是 React 生态和原生体验,不确定性是桥接性能和新架构迁移
- 选 Tauri:确定性是轻量和安全,不确定性是 Rust 学习曲线和 WebView 兼容
- 选 Electron:确定性是前端生态和开发效率,不确定性是资源占用和用户体验
- 选 KMP:确定性是原生体验和渐进迁移,不确定性是 UI 写多份的维护成本
- 选 Qt:确定性是工业级稳定性,不确定性是学习曲线和许可证成本
没有最好的框架,只有最适合你当前约束的框架。
先想清楚你最不能妥协的那一条,再按决策树往下走。技术路线定了,框架的选择往往水到渠成。
评论
0