782 lines
61 KiB
Markdown
782 lines
61 KiB
Markdown
# 前端技术路线评估:Flutter / uni-app / uni-app x
|
||
|
||
| 项目 | 内容 |
|
||
| --- | --- |
|
||
| 文档名称 | Continental Retail APP 前端技术路线评估 |
|
||
| 文档版本 | V1.0 |
|
||
| 编制时间 | 2026 年 08 月 |
|
||
| 评估对象 | Flutter · uni-app · uni-app x |
|
||
| 评估结论 | **推荐 Flutter** |
|
||
| 外部数据核验日期 | 2026-08-25(来源见附录 A) |
|
||
|
||
文档控制信息
|
||
|
||
---
|
||
|
||
## 0 结论摘要
|
||
|
||
**推荐 Flutter。**
|
||
|
||
这不是"哪个框架更时髦"的偏好问题。四条理由,每一条都可以查证:
|
||
|
||
**第一,架构路线不同,能力上限就不同。** 跨端方案历史上分四条路线,uni-app 走的是"网页套壳",uni-app x 走的是"编译到系统控件",Flutter 走的是"自绘引擎"。这三条路线各有适用场景——**uni-app 系是为"一套代码同时发小程序 + H5 + App"设计的,而这个项目的目标恰恰是把六套小程序关掉,首版只发 Android 和 iOS。** 我们要付它的代价,收不到它的好处。
|
||
|
||
**第二,这个项目的原生能力密度非常高。** 扫码、VIN 识别、车牌识别、相机、相册、上传进度、定位、权限、弱网离线暂存、崩溃上报、埋点——这些不是画页面,是跟两个操作系统打交道。**这部分工作量不会因为换框架而减少一件。**
|
||
|
||
**第三,生态不在一个量级,而且开放程度的差别在"开到哪一层"。** Flutter 主仓库 **91,171 次提交**,uni-app 主仓库 **11,216 次**,约 8 倍差距;fork 数 31,002 对 3,709,同样约 8 倍。更关键的是:Flutter 从渲染引擎到框架层全部 BSD 开源;uni-app x 的组件和 API 虽然也是 Apache-2.0 开源,**但真正决定 App 能力上限的 Runtime、SDK 和 HBuilderX 是 DCloud 自有知识产权,闭源,没有公开的提交历史。**
|
||
|
||
**第四,构建链路和扩展能力受限,而"离线打包"这条退路并不是真正的退路。** 想用加密的付费插件,就只能云端打包;想做 Siri 快捷指令这类扩展,官方要求离线打包——**这两个要求互斥。** 更关键的是:离线打包给到的并不是一个可以随便改的原生工程,而是**围着 DCloud 闭源二进制(一组编译好的 AAR)搭起来的壳**,官方文档要求自定义 `Application` 必须继承 `DCloudApplication`,且写明「App离线SDK不支持Kotlin」。**你只能在壳外面加东西,改不了壳里面的东西。**
|
||
|
||
**成本结论:首版投入两条路线基本持平,差异在 ±10% 以内。**
|
||
|
||
真正的差异不在首版人天,在**五年后**:需求持续增长、要接更多系统级能力时,一条路线的天花板是自己的工程能力,另一条的天花板是厂商插件市场里有没有人卖这个功能。
|
||
|
||
| 维度 | Flutter | uni-app | uni-app x |
|
||
| --- | --- | --- | --- |
|
||
| 架构路线 | 自绘引擎 | 网页套壳(WebView) | 编译到系统控件 |
|
||
| 为谁设计 | 需要跨端一致性的独立 App | 小程序为主、App 为辅 | 小程序团队想做 App |
|
||
| 界面一致性 | 两端逐像素一致 | 受各家 WebView 内核影响 | 用系统控件,两端有差异 |
|
||
| 嵌 F6 网页 | 通道由 App 侧建立,**F6 零改动** | 同右 | **需 F6 引入 DCloud 的 JS 文件** |
|
||
| 原生能力开发 | Pigeon 生成三端强类型代码,支持 CLI | 原生插件(已停止新增上架) | UTS 插件,**只能经 HBuilderX,不支持 CLI** |
|
||
| 开源程度 | 引擎 + 框架全开源(BSD) | 框架层开源(Apache-2.0) | 框架层开源,**Runtime / SDK 闭源** |
|
||
| 主仓库提交数 | **91,171** | **11,216** | 同左(含在 uni-app 仓库分支) |
|
||
| 原生工程归谁 | **自己的工程**,Flutter 挂进去 | DCloud 的壳工程 | **DCloud 的壳工程**,核心是闭源 AAR |
|
||
| App 扩展能力 | 标准原生开发,无额外规则 | 受限 | **小组件需 Xcode 做 .appex;Siri 需离线打包** |
|
||
| 接入现有 GitLab 流水线 | 原生支持 | — | 结构性错配 |
|
||
| 鸿蒙 | 社区分支(3.41 已发布,3.44 预计 9 月) | 支持 | **一等公民**(这一项 uni-app x 更强) |
|
||
| 包体与内存 | 约多 10MB / 35MB | — | **更小**(这一项 uni-app x 更优,但本项目无包体 KPI) |
|
||
| 首版成本 | 基准 | — | **±10% 以内,基本持平** |
|
||
|
||
三条路线总览。uni-app(传统版)几格标"—",是因为它在"界面本质上是网页"这一条上就已经不适合本项目,后续章节重点放在 Flutter 与 uni-app x 的对比。每一行的依据见第 1–5 章,外部数据来源见附录 A。
|
||
|
||
**表中"包体与内存""鸿蒙"两行是 uni-app x 占优的项,我们主动列出。** DCloud 官方另有一页专门对比 Flutter,客户方检索时大概率会看到——**我们已把那一页逐条核验,结果见[附录 C](#附录-c-对-dcloud-官方对比材料的核验)。**
|
||
|
||
---
|
||
|
||
## 1 市面上的跨端方案
|
||
|
||
### 1.1 目前可选的技术栈
|
||
|
||
先把台面上的选项摆全,再谈取舍:
|
||
|
||
| 方案 | 出品方 | 语言 | 首次发布 | 现状 |
|
||
| --- | --- | --- | --- | --- |
|
||
| **原生双端** | Google / Apple | Kotlin · Swift | — | 平台官方方案,能力无上限 |
|
||
| **Flutter** | Google | Dart | 2017(1.0 于 2018 年底) | 跨端主流方案,生态最大 |
|
||
| **React Native** | Meta | JavaScript / TypeScript | 2015 | 成熟,适合已有 React 团队 |
|
||
| **uni-app** | DCloud | Vue + JS | 2018 | 国内多端方案,小程序场景占优 |
|
||
| **uni-app x** | DCloud | UTS + UVue | 2023 | uni-app 的原生渲染重构版 |
|
||
| **Taro** | 京东 | React / Vue | 2018 | 重心在多家小程序平台 |
|
||
| **Kotlin Multiplatform** | JetBrains | Kotlin | 2020 | 逻辑层共享强,UI 层生态尚浅 |
|
||
| **.NET MAUI** | Microsoft | C# | 2022 | 微软栈企业适用,国内生态薄 |
|
||
| **原生 + H5 混合** | — | 任意 | — | 老牌做法,性能与体验受限 |
|
||
|
||
市面上主要的跨端方案。前五个是本次讨论真正需要展开的。
|
||
|
||
### 1.2 归纳:其实只有四条架构路线
|
||
|
||
上面九个方案,剥掉品牌和语言的差异,底层只有四条路线。**理解了这四条,就能理解为什么不同方案的能力上限不一样:**
|
||
|
||
```
|
||
① 原生双端(Native)
|
||
Android 工程师 ──写一遍──▶ Kotlin ──▶ 安卓系统的按钮 / 列表 / 输入框
|
||
iOS 工程师 ──写一遍──▶ Swift ──▶ 苹果系统的按钮 / 列表 / 输入框
|
||
→ 两套代码、两套人,但系统给什么就能用什么,没有天花板
|
||
|
||
② 网页套壳(uni-app、原生 + H5 混合)
|
||
一套 Vue 代码 ──▶ JavaScript ──▶ 系统自带的浏览器组件 ──▶ 渲染成网页
|
||
→ 一套代码,但用户看到的本质上是个网页;
|
||
要用系统能力,得靠"插件"从网页世界打一个洞出去
|
||
|
||
③ 编译到系统控件(uni-app x、React Native)
|
||
一套代码 ──编译──▶ Kotlin ──▶ 安卓系统的原生控件
|
||
──编译──▶ Swift ──▶ 苹果系统的原生控件
|
||
→ 一套代码,用户看到的是真正的原生控件。
|
||
代价:中间那本"翻译词典"必须够全,
|
||
词典里没有的东西就做不出来,得自己去补词条
|
||
|
||
④ 自绘引擎(Flutter)
|
||
一套 Dart 代码 ──▶ Flutter 自带引擎,自己画出每一个像素 ──▶ 屏幕
|
||
→ 一套代码,不用系统的任何控件,两端画出来完全一样
|
||
```
|
||
|
||
用装修打比方:
|
||
|
||
- **① 原生双端**:请两个装修队分别装两套房子。质量最好,花两份钱,而且两边多半装得不太一样。
|
||
- **② 网页套壳**:在两套房子里各贴一层一模一样的壁纸。快、便宜,但墙还是人家的墙——墙有多平,壁纸就有多平。
|
||
- **③ 编译到系统控件**:拿同一张图纸,翻译成两家各自的材料清单,再让两个装修队照做。比贴壁纸结实得多。**但图纸上画了个东西、翻译词典里没这个词,就做不出来。**
|
||
- **④ 自绘引擎**:自己带整套施工队和材料进场,从水泥开始砌。不管进的是哪套房子,装出来完全一样。
|
||
|
||
### 1.3 四条路线的能力上限不一样
|
||
|
||
这是本章最重要的一句话,也是后面所有结论的地基:
|
||
|
||
| 路线 | 界面一致性 | 系统能力的获取方式 | 能力天花板由谁决定 |
|
||
| --- | --- | --- | --- |
|
||
| ① 原生 | 差(两端天然不同) | 直接调 | **无天花板** |
|
||
| ② 网页套壳 | 差(受内核影响) | 靠插件从网页打洞出去 | **插件生态有没有人做** |
|
||
| ③ 编译到控件 | 中(用系统控件) | 靠"翻译词典" + 插件 | **词典覆盖度 + 插件生态** |
|
||
| ④ 自绘引擎 | **最好(逐像素一致)** | 自己写原生插件直接调 | **自己的工程能力** |
|
||
|
||
四条路线的对比。最后一列是本项目最该关注的:**②③ 的天花板在别人手里,④ 的天花板在自己手里。**
|
||
|
||
一个五年周期的业务系统,需求只会越加越多。天花板在谁手里,是个战略问题,不是技术偏好。
|
||
|
||
---
|
||
|
||
## 2 Flutter 与 uni-app / uni-app x 的对比
|
||
|
||
上一章讲了四条路线。这一章说清楚这三个具体方案分别是哪条路线、为谁设计、适合什么。
|
||
|
||
### 2.1 uni-app:第 ② 条路线,为小程序团队设计
|
||
|
||
**它是什么**:用 Vue 写代码,在 App 端跑在系统自带的浏览器组件里。
|
||
|
||
**它为谁设计**:DCloud 的出发点非常明确——让**已经在做微信小程序的前端团队**,用同一套 Vue 代码顺便发一个 App 和一个 H5。
|
||
|
||
**它适合什么场景**:主战场是小程序、App 只是顺带的项目。比如一个商城,微信小程序是主入口,App 只是给老客户的一个补充。这类项目 uni-app 的价值非常大。
|
||
|
||
**它不适合什么**:App 是主战场、且需要大量系统能力的项目。因为界面本质上是网页,要用相机、要扫码、要后台上传,都得靠插件从网页世界打洞出去。
|
||
|
||
### 2.2 uni-app x:第 ③ 条路线,是 uni-app 的重构版
|
||
|
||
**它是什么**:用一门叫 UTS 的新语言写,编译成安卓的 Kotlin、苹果的 Swift、鸿蒙的 ArkTS,渲染用真正的系统原生控件。
|
||
|
||
**必须澄清一点:uni-app 和 uni-app x 不是同一个东西的两个版本,是两套不同的技术底座。** 它们共享品牌、共享 IDE、共享很多写法,但底层是重写的。一个直接证据:**uni-app x 不支持传统 uni-app 的原生插件,而那批旧原生插件已经停止接受新增上架。** 即使在 DCloud 自家体系内做版本迁移,插件也要重写。
|
||
|
||
**设计思想值得肯定**:UTS 直接编译成 Kotlin 和 Swift,比"字符串方法名 + 弱类型参数"的传统桥接方式要优雅得多。**这一点应该如实承认。**
|
||
|
||
**它为谁设计**:还是那批小程序团队,只是这次要把 App 端做得更像原生。
|
||
|
||
**它的约束在哪**:见 1.3 那张表的第 ③ 行——能力天花板取决于"翻译词典"的覆盖度和插件生态。词典里没有的、插件市场上没人卖的,就得自己用 UTS 补,而补这件事又受工具链约束(第 5 章)。
|
||
|
||
### 2.3 Flutter:第 ④ 条路线,为独立 App 设计
|
||
|
||
**它是什么**:Dart 代码提前编译成机器码,界面由 Flutter 自带的引擎逐像素绘制,不使用系统的任何控件。
|
||
|
||
**它为谁设计**:出发点就是**做一个正经的 App**,而不是"顺便也发一个 App"。
|
||
|
||
**这带来两个结构性结果**:
|
||
|
||
1. **界面完全脱离系统控件的差异** —— 同一套设计规范在 Android 和 iOS 上落地的结果逐像素一致。
|
||
2. **原生能力靠标准插件机制直接对接** —— 每个能力封装成独立插件包,接口用官方工具从一份定义文件生成 Dart / Kotlin / Swift 三端强类型代码,改了接口忘记同步实现,**编译期就报错**。要什么能力就自己写,不用等插件市场。
|
||
|
||
### 2.4 三者的定位对照
|
||
|
||
| | uni-app | uni-app x | Flutter |
|
||
| --- | --- | --- | --- |
|
||
| 架构路线 | ② 网页套壳 | ③ 编译到系统控件 | ④ 自绘引擎 |
|
||
| 原始设计目标 | 小程序团队顺便发 App | 小程序团队把 App 做好一点 | 做一个独立的正经 App |
|
||
| 主平台 | 小程序 / H5 | 小程序 / H5 / App | **App** |
|
||
| 界面一致性 | 弱 | 中 | **强** |
|
||
| 系统能力获取 | 插件打洞 | UTS 插件 + 翻译词典 | **自写原生插件,直接调** |
|
||
| 能力天花板 | 插件生态 | 词典 + 插件生态 | **自己的工程能力** |
|
||
| 适合本项目吗 | 否 | 部分适合 | **适合** |
|
||
|
||
三个方案的定位差异。最后一行的判断依据在第 3 章。
|
||
|
||
### 2.5 架构层面的结论
|
||
|
||
**这个项目要做的是一个独立 App,不是一个小程序的附属品。**
|
||
|
||
它的目标是把六套微信小程序整合掉、关停,首版只发 Android 和 iOS,不发小程序、不发 H5、不发鸿蒙。也就是说:
|
||
|
||
> **uni-app 系最值钱的能力——"一套代码同时发小程序、H5 和 App"——在这个项目里没有买家。**
|
||
|
||
我们要承担它为了多端兼容而付出的所有架构代价(能力天花板受制于插件生态、工具链绑定、构建方式受限),却收不到它最大的那份好处。
|
||
|
||
**单从架构选型的角度,在这个项目上 Flutter 已经胜出。** 后面三章是把这个结论落到具体的业务需求、生态数据和工程链路上。
|
||
|
||
---
|
||
|
||
## 3 技术评估:结合本项目的业务需求
|
||
|
||
> 这一章写给技术评审。
|
||
|
||
### 3.1 嵌入 F6 网页与双向通道 —— 本项目最高风险项
|
||
|
||
这个 App 里最核心的几条业务链路——报价开单、施工查车、结算收银,以及整个提醒模块——是把 F6 的网页嵌进 App 里承载的。这些网页需要调用 App 的能力(扫码、拍照、相册、带进度的上传、拨号、获取登录态与门店上下文、原生弹窗、跳转原生页等,共 13 项能力、15 个方法),App 也要能反向通知网页。
|
||
|
||
```
|
||
【Flutter 方案】F6 页面不需要任何改动
|
||
────────────────────────────────────────────────
|
||
F6 的网页
|
||
│ window.ContiBridge.call('scan', { mode: 'barcode' })
|
||
│ ▲
|
||
│ └── 这段胶水代码,由 App 在页面加载完成时自动注入
|
||
▼
|
||
单一双向通道(JavaScript Channel)
|
||
│
|
||
▼
|
||
App 的 WebView 容器 ──▶ 原生扫码 / 相机 / 上传
|
||
|
||
一条通道,双向,收发同一套协议:{ id, method, params }
|
||
|
||
|
||
【uni-app x 方案】F6 页面必须先引入 DCloud 的 JS 文件
|
||
────────────────────────────────────────────────
|
||
F6 的网页
|
||
│ ⚠ 必须先引入:<script src="uni.webview.1.5.5.js">
|
||
│ uni.webView.postMessage({ data: {...} })
|
||
▼
|
||
<web-view @message> (网页 → App,单向)
|
||
|
||
uni.createWebViewContext(id).evalJS("...") (App → 网页,另一条单向通道)
|
||
|
||
两条独立的单向通道,方向不对称
|
||
```
|
||
|
||
**事实**(DCloud 官方 `web-view` 组件文档原文):网页要向 App 发消息,需要**"在网页中引入 uni.webview.1.5.5.js"**,再调 `uni.webView.postMessage()`;App 向网页发消息走 `evalJS()`,本质是执行一段 JavaScript 字符串。
|
||
|
||
**推论**:这意味着 **F6 这家第三方厂商,需要修改他们的页面,引入 DCloud 提供的 JS 文件**。Flutter 方案下胶水代码由我们在 App 侧注入,**F6 一行都不用改**。
|
||
|
||
F6 是这个项目里影响面最大的外部依赖——销售全链路、整个提醒模块、以及非马牌商品的采购供货都压在它上面。**在这条链路上再叠一个"需要对方配合改造"的前置条件,是排期风险,不是技术偏好。**
|
||
|
||
两点补充,避免结论被过度解读:
|
||
|
||
- 这不是说 uni-app x 做不出 JSBridge。做得出,但要在两条不对称的单向通道之上,自己封装请求 ID、超时、就绪信号、错误处理、方法白名单这一整套;Flutter 的单一双向通道天然就是这个形状。
|
||
- `evalJS()` 传大量数据要额外处理序列化和转义,上传进度这类高频事件走这条路需谨慎设计。
|
||
|
||
### 3.2 原生能力密度:本项目的决定性变量
|
||
|
||
| 能力 | 用在哪 |
|
||
| --- | --- |
|
||
| 扫码(条码 / 二维码) | 扫码入库、扫码查件、商品与库位 |
|
||
| VIN 识别 | 条码形式 + 印刷字符 OCR,端上完成 |
|
||
| 车牌识别 | 拍照上传走云端 OCR,需先压图 |
|
||
| 相机 | 检测报告、装车视频、鉴定证据 |
|
||
| 相册多选 | 证据上传、营业执照 |
|
||
| 文件上传(带进度) | 大文件、弱网场景 |
|
||
| 图片压缩 | 上传前必须压,否则弱网传不动 |
|
||
| 拨号 | 客服、门店联系 |
|
||
| 定位 | 扫码入库以地图定位为准 |
|
||
| 运行时权限申请 | 相机、相册、定位,含拒绝后的引导 |
|
||
| 弱网离线暂存与幂等重传 | 断网本地存,恢复后批量提交且不重复 |
|
||
| 崩溃上报原生桥 | Bugly 只有原生 SDK |
|
||
| 埋点 SDK 接入 | 神策 |
|
||
| 安卓物理返回键拦截 | 嵌网页时不拦截会导致填一半的表单丢失 |
|
||
| WebView 文件选择器 | 网页里的 `<input type="file">` |
|
||
| iOS 隐私清单 | 苹果强制要求,没有直接被拒 |
|
||
|
||
本项目需要的原生能力清单。门店场景(地下车库、仓库、施工区)网络条件差,而恰恰是这些场景要传大文件——弱网相关的几项不是可选项。
|
||
|
||
**这张表是全文成本结论的支柱。** 它说明这个项目的工作量重心本来就压在原生能力和系统集成上,"画页面快不快"能省下的比例有限。而上面每一项,在 uni-app x 下都是一个要自己写、自己维护、自己在两端分别验证的 UTS 插件——**数量不会因为换框架而减少一件。**
|
||
|
||
**Flutter 侧**:扫码这一个原生实现,同时服务 App 内的扫码页和嵌入网页的通道调用,**一份实现两个调用方**,不需要复制两套。
|
||
|
||
**uni-app x 侧**:UTS 插件的设计思想更优雅,但**按官方文档,UTS 插件目前只支持通过 HBuilderX 创建和使用,不支持通过命令行使用**——后果见第 5 章。
|
||
|
||
### 3.3 崩溃上报与埋点
|
||
|
||
业务方指定了两个工具:崩溃用**腾讯 Bugly**,错误明细和埋点用**神策**。账号现成、合规口径已过,这个前提不因技术选型而改变。
|
||
|
||
| | Flutter | uni-app x |
|
||
| --- | --- | --- |
|
||
| **神策** | 官方发布的插件,在公开包管理平台上,有认证发布者、有版本号 | **不在插件市场**。官方说明因缺少 UTS 的压缩混淆方案暂未提供市场包,需**联系技术顾问索取 zip 源码包**;另有后端版本下限要求 |
|
||
| **Bugly** | 只有原生 SDK,需自建原生桥(几十行 Kotlin/Swift) | 未见官方支持,需完全自行用 UTS 封装 |
|
||
|
||
两个指定 SDK 的支持成熟度对比。
|
||
|
||
**两边都有工作量**,差别是 Flutter 侧有一项是公开发布、可版本化管理、有官方发布者背书的现成包;uni-app x 侧两项都是定制的,且其中一项脱离了公开的市场分发渠道——后续升级、问题追溯、责任归属都要靠人对人沟通,而不是查版本记录。
|
||
|
||
对一个要跑五年的系统,**"崩溃上报本身不能再出问题"** 是硬要求。
|
||
|
||
### 3.4 十九个模块并行开发时,边界怎么守住
|
||
|
||
这个项目 19 个业务模块、近三百条需求,会有多人并行开发很长时间。工程上最容易出问题的不是某个功能写不出来,而是**模块边界慢慢烂掉**——A 模块图省事直接引用了 B 模块的内部类,半年后想改 B 就动不了了。
|
||
|
||
**Flutter 方案**:用 Melos 组织 monorepo,21 个包按职责拆开(基础设施层 / 业务模块层 / 原生能力层),依赖规则由 Dart 的包机制**在编译期物理强制**——业务模块 A 根本 import 不到业务模块 B 的任何符号,不靠代码规范或口头约束。想复用组件,只能提到公共层。
|
||
|
||
**uni-app x 侧**同样可以做工程化拆分,但约束强度依赖团队自觉和评审纪律,缺少编译期的物理阻断。
|
||
|
||
这一条在项目初期看不出价值,在第二年会。
|
||
|
||
### 3.5 渲染性能、包体与内存(明确标注:非决定项)
|
||
|
||
Flutter 用自绘引擎、Dart 提前编译成机器码;uni-app x 编译成原生控件调用。**两者在这个项目上都够用**——这是一个以表单、列表、报表为主的业务 App,不是游戏,也不是有复杂动效的消费级产品。
|
||
|
||
**拿性能说事经不起追问,我们不把它算进结论。** 列在这里只是让对比完整。
|
||
|
||
**包体与内存这两项,Flutter 确实更高,我们主动列出。** DCloud 官方对比页给出的实测是:安装包 18M 对 8.5M、内存占用约 138MB 对 103MB。**这两个数字我们认为是可信的**——自绘引擎要把渲染引擎打进包里,这是路线本身的代价,不是实现问题。
|
||
|
||
但它在本项目不构成决策变量:这是一个**门店员工使用的内部业务 App**,通过企业分发和应用商店安装,不参与消费级 App 的下载转化竞争,没有包体 KPI,也没有"多 10MB 就少一批用户"的场景。设备是门店配发的作业终端,35MB 内存差异在现代机型上不产生可感知影响。
|
||
|
||
需要一并说明的是,**uni-app x 走离线 / 嵌入这条路同样有包体增量**:按 DCloud 官方数字,iOS 约 8.7 MB、Android(仅 arm64-v8a)约 8.1 MB。这项对比的完整核验见[附录 C](#附录-c-对-dcloud-官方对比材料的核验)。
|
||
|
||
真正和体验相关、且在本项目真实存在的差异是**视觉一致性**:这个 App 要把六套来源不同、不同团队不同时期做的小程序整合成一个东西。整合最大的隐性风险不是功能缺失,而是同一个业务概念在不同页面上叫法不同、长得不同、操作方式也不同——用户会觉得"这还是六个东西,只是塞进了同一个壳子"。Flutter 逐像素自绘,同一套设计规范落地结果完全一致;uni-app x 用系统控件,安卓的按钮和苹果的按钮本来就不一样,要抹平需要额外工作。
|
||
|
||
### 3.6 小结
|
||
|
||
| 本项目的关键维度 | Flutter | uni-app x | 差异是否决定性 |
|
||
| --- | --- | --- | --- |
|
||
| 嵌入 F6 网页 + 双向通道 | 通道由 App 侧建立,F6 零改动 | 需 F6 引入 DCloud 的 JS 文件 | **是** |
|
||
| 十几项原生能力 | 三端强类型生成,支持 CLI | UTS 插件,只能经 HBuilderX | **是** |
|
||
| Bugly + 神策 | 神策有官方发布包 | 神策需单独索取;Bugly 无官方支持 | 较强 |
|
||
| 19 模块的工程边界 | 编译期物理强制 | 靠规范与评审 | 中等 |
|
||
| 视觉一致性 | 逐像素一致 | 需额外抹平 | 中等 |
|
||
| 渲染性能 | 够用 | 够用 | **否** |
|
||
| 包体与内存 | 约多 10MB / 35MB | 更小 | **否**(内部业务 App,无包体 KPI) |
|
||
|
||
七个维度的逐条对照。最后两行特意列出,是为了说明我们没有把不构成差异的项算进结论里,也没有回避对方占优的项。
|
||
|
||
---
|
||
|
||
## 4 生态、社区、落地规模与 AI 工具链
|
||
|
||
这一章比大多数人以为的重要。**技术栈的生命力不看今天能做什么,看社区每天往里投入多少。**
|
||
|
||
### 4.1 开源程度:关键在"开到哪一层"
|
||
|
||
先澄清一个容易说错的点:**uni-app x 不是闭源的。** 它的组件和 API 大部分以 Apache-2.0 协议开源,在 `dcloudio/uni-app` 仓库的 `uni-app-x` 分支里。
|
||
|
||
**但开源的层次不一样,这才是要害:**
|
||
|
||
| | Flutter | uni-app x |
|
||
| --- | --- | --- |
|
||
| 框架层(组件、API) | 开源(BSD-3-Clause) | 开源(Apache-2.0) |
|
||
| **渲染引擎 / Runtime** | **开源**,在主仓库内 | **闭源**,DCloud 自有知识产权 |
|
||
| **原生 SDK** | 不适用(原生层完全由项目自己掌握) | **闭源** |
|
||
| **开发工具(IDE)** | 无绑定,任意编辑器 + 官方 CLI | **HBuilderX,闭源,且插件开发离不开它** |
|
||
|
||
开源层次对比。DCloud 的许可协议明确写明:内嵌的 Runtime 或 SDK 知识产权仍归 DCloud 所有。
|
||
|
||
**这意味着什么:** 当你遇到一个渲染层或运行时的 bug,Flutter 侧你可以读引擎源码、定位、提 issue、必要时自己 fork 修;uni-app x 侧你只能提工单等厂商。对一个五年周期的核心业务系统,这是两种完全不同的风险敞口。
|
||
|
||
### 4.2 社区活跃度:实测数据
|
||
|
||
| 指标 | Flutter | uni-app | 倍数 |
|
||
| --- | --- | --- | --- |
|
||
| 主仓库提交数(默认分支) | **91,171** | **11,216** | **约 8.1 倍** |
|
||
| Fork 数 | **31,002** | **3,709** | **约 8.4 倍** |
|
||
| Star 数 | 178,643 | 41,600 | 约 4.3 倍 |
|
||
| 仓库创建时间 | 2015-03 | 2018-07 | — |
|
||
| 开源协议 | BSD-3-Clause | Apache-2.0 | — |
|
||
|
||
GitHub 实测数据,核验于 2026-08-25,取自 `flutter/flutter` 与 `dcloudio/uni-app`。
|
||
|
||
**口径要说明白,不做诛心解读:** star 数反映的是全球开源关注度,不等于国内商业项目的落地数量。uni-app 在国内企业应用、商城、政企项目里的落地量非常大,这一点数据体现不出来。
|
||
|
||
**但有一条差异是数据也遮不住的:** Flutter 的 91,171 次提交**包含了渲染引擎在内的全栈**;DCloud 的 11,216 次提交是**框架层的**,而真正决定 App 能力上限的 Runtime 和原生 SDK **闭源、没有任何公开的提交历史**。
|
||
|
||
也就是说,真实的工程投入差距**比 8 倍这个数字看起来还要大**——因为对方最核心的那部分,外界根本看不到,也无法参与。
|
||
|
||
**另一个可查证的信号是平台连续性。** DCloud 在 App 端已经换过三代方案:5+ 应用 → nvue(基于修改过的 Weex 渲染引擎,而 Apache Weex 已于 2021 年 5 月退役、6 月仓库归档)→ uni-app x。DCloud 官方文档已说明 **nvue 和 5+ 的官方维护在 2024 年停止,建议迁移到 uni-app x**。
|
||
|
||
对比 Flutter:2015 年至今同一条主线持续演进,没有让用户推倒重来过。**这是"平台连续性"的差异,会直接变成五年后的迁移成本。**
|
||
|
||
### 4.3 谁在用:可查证的落地规模
|
||
|
||
提交数说明的是"投入",落地案例说明的是"验证"。这里只列**厂商官方渠道公开发布、可点开核对**的,不引用二手传闻。
|
||
|
||
**字节跳动是目前公开信息中规模最大的 Flutter 使用方**(数据来自 Flutter 官方中文站的开发者故事,2026-06-22 更新):
|
||
|
||
- **90 多款 Flutter 应用**在线上运行
|
||
- **800 多名 Flutter 开发者**,并设有专职的 Flutter Infra 基建团队
|
||
- 点名的产品包括:抖音火山版、飞书 Lark、Coze、小荷健康、幸福里、Lemon8,以及技术社区 **掘金**
|
||
|
||
原文对收益的表述是:**「与原生双端开发相比,Flutter 为我们的团队节省了大约 1/3 的开发时间」**。
|
||
|
||
> **这个 1/3 必须标清口径:它的对照组是"原生双端",不是 uni-app。** 拿它去论证"Flutter 比 uni-app x 省 1/3"是错的,我们不这么用。本文档的成本结论仍然是第 6.1 节那句——**首版两条路线基本持平**。这里引用它只说明一件事:一个有能力自研全套基建的团队,在做过 90 多个 App 之后仍然选择继续投入 Flutter。
|
||
|
||
顺带一提:**这份评估里引用的技术社区"掘金",它自己的 App 就是 Flutter 写的。**
|
||
|
||
**uni-app x 侧,我们未检索到同等量级的公开大厂落地案例。** 这里写"未检索到"而不是"没有"——DCloud 官方公布的是 uni-app 全系的开发者与应用总量,那个数字很大,但它统计的主体是小程序和 H5,无法单独拆出"用 uni-app x 做的独立 App"有多少、规模多大。**口径不可比的数字我们不拿来对比。**
|
||
|
||
### 4.4 AI 工具链:开放生态 vs 厂商内置
|
||
|
||
这是这次特别关注的一项。**先说清楚:两边都有官方 AI 工具,不能说 uni-app x 没有。**
|
||
|
||
| | Flutter / Dart | uni-app x |
|
||
| --- | --- | --- |
|
||
| 官方 skills | `flutter/agent-plugins`、`dart-lang/skills`,**独立开源仓库** | 内置在官方 `uni-agent` 助手中 |
|
||
| 官方 MCP 服务 | Dart & Flutter MCP server | `uni-app-x-mcp` |
|
||
| 能用在哪些工具上 | Claude Code、Codex、Cursor、Antigravity 等,**装到哪个 agent 都行** | 主要围绕自家生态与少数几个工具 |
|
||
| 安装方式 | `npx skills add flutter/agent-plugins --skill '*'`,**一行命令** | 随官方助手提供 |
|
||
| 能否自己改 / 自己加 | **可以,仓库开源,可 fork 可 PR** | 受限于官方提供 |
|
||
|
||
双方 AI 工具链对比。Flutter 的 skills 是**任务粒度**的,官方文档与 2026-05-06 的发布公告合计已列出十项以上,覆盖生成单元测试、生成集成测试、统计测试覆盖率、配置多语言、构建响应式布局、配置声明式路由、实现 JSON 序列化、解析包依赖冲突、修复静态分析错误、使用模式匹配等,仓库持续新增。
|
||
|
||
**两个真实的差别:**
|
||
|
||
**① 开放 vs 内置。** Flutter 的 skills 是独立开源仓库,一行命令装进任意 AI 编程工具,团队可以 fork 它、按自己的规范改它、往里加自己项目的 skill。uni-app x 的 AI 能力主要绑在官方助手和自家 IDE 里——**这和第 5 章要讲的工具链绑定是同一个问题的两面。**
|
||
|
||
**② 语料深度。** AI 生成代码的准确率和这门语言在公开代码里的沉淀量强相关:
|
||
|
||
- **Dart / Flutter**:近十年公开代码沉淀在 GitHub 上,全球范围,各种项目形态都有。
|
||
- **UTS / UVue**:新语言,语料以中文官方文档为主,体量小得多。而且插件市场的付费插件是**加密分发**的——这些代码根本不会进入任何公开语料。
|
||
|
||
**这一条对 2026 年的实际开发效率有直接影响。** 同一个开发者,用 AI 辅助写 Flutter 和写 UTS,产出质量和返工率不是一回事。
|
||
|
||
### 4.5 这一章对本项目意味着什么
|
||
|
||
生态不是"锦上添花"的加分项,它决定四件很实际的事:
|
||
|
||
1. **遇到问题能不能自己解决** —— 引擎开源你能读能修,闭源你只能等工单。
|
||
2. **五年后还有没有人维护** —— 8 倍的提交量差距 + 三代方案换代史,指向两种不同的平台连续性。
|
||
3. **有没有人趟过同样规模的路** —— 90 多款线上应用、800 多名开发者的实践,意味着我们会遇到的坑大概率已经有人踩过并写下来了。
|
||
4. **AI 辅助的效率** —— 直接落在代码量最大的那两块工作上。
|
||
|
||
---
|
||
|
||
## 5 构建、发布与可扩展性
|
||
|
||
这一章是 uni-app 系限制最集中的地方,也是最容易在项目中后期才暴露出来的地方。
|
||
|
||
### 5.1 我们已经定下来的工程链路
|
||
|
||
- GitLab CI/CD 流水线,带 lint、格式化、测试的卡点
|
||
- dev / uat / prod 三套环境构建
|
||
- iOS 由一台远程 Mac 出包,后续注册成流水线的构建节点
|
||
- 内测分发:安卓走托管的 OTA 分发页,iOS 走 TestFlight
|
||
|
||
这套链路的核心诉求是**全自动、可追溯、可复现**:任何一个版本,都能从一次 git 提交自动构建出来,不依赖任何人的本机环境。
|
||
|
||
### 5.2 插件工具链绑定图形化 IDE
|
||
|
||
按 DCloud 官方文档原文:
|
||
|
||
> **"目前仅支持通过HBuilder X 创建和使用UTS插件,不支持通过cli的方式使用UTS插件"**
|
||
|
||
**一个绑定图形化 IDE 的插件工具链,和一条要求全自动的流水线,是结构性错配。** 这不是"配置一下就好"——它意味着构建链路里存在一个必须有人打开 IDE 点按钮的环节。
|
||
|
||
普通的 uni-app x 页面本身可以自动化打包,问题集中在原生插件这一环。而由 3.2 节可知,**这个项目的原生插件不是一两个,是十几个。**
|
||
|
||
### 5.3 云端打包与离线打包:两条路各有硬约束
|
||
|
||
uni-app x 提供两种出包方式:
|
||
|
||
| | 云端打包 | 离线打包 |
|
||
| --- | --- | --- |
|
||
| 构建在哪 | DCloud 的云端服务 | 自己的 Android Studio / Xcode |
|
||
| 原生工程可定制范围 | 无 | **只能改外壳,改不了内核**(见下) |
|
||
| 能否用加密的付费插件 | **是** | **否** |
|
||
| 计费 | 每次 2 元;60MB 以下不额外收费,超出按档加收 | 免费 |
|
||
|
||
两种出包方式的约束对比。第二行最容易被误读,下面单独展开。
|
||
|
||
#### "离线打包 = 原生工程完全可控"是一个误解
|
||
|
||
离线打包确实会给你一个 Android Studio / Xcode 工程,**但这个工程的核心是 DCloud 已经编译好的闭源二进制。** 按官方文档,Android 侧要引入的是一组 AAR:`lib.5plus.base-release.aar`、`uniapp-v8-release.aar`、`utsplugin-release.aar` 等,**没有源码**。
|
||
|
||
| 你能改的(外壳) | 你改不了的(内核) |
|
||
| --- | --- |
|
||
| 包名、版本号、图标、启动图 | 页面怎么渲染 |
|
||
| Gradle 依赖、ABI、SDK 版本 | 页面容器与生命周期 |
|
||
| AndroidManifest / Info.plist 权限项 | UTS 与原生之间的通信机制 |
|
||
| 在壳外面加自己的原生模块、加 App Extension | 运行时的任何行为 |
|
||
|
||
离线打包的可改 / 不可改边界。右列全部封装在编译好的二进制里,不提供源码,也没有修改入口。
|
||
|
||
**而且连这个"外壳"本身都是被规定死的**,以下两条都是官方文档原文:
|
||
|
||
- **自定义的 `Application` 必须继承 `DCloudApplication`**,新建工程默认的 `MainActivity` 节点必须移除 —— 换句话说,**宿主工程的入口不归你,归它**。你不是"把 uni-app 集成进自己的 App",是"在它的 App 里放自己的东西"。
|
||
- **「App离线SDK不支持Kotlin」** —— 2026 年一个安卓工程不支持 Kotlin,意味着你自己要补的那部分原生代码得退回去用 Java 写。
|
||
|
||
**uni-app x 用的还不是上面这套**,它有独立的一套原生 SDK。按官方文档,该 SDK 当前**"仅支持VDOM模式,蒸汽(Vapor)模式的SDK还未发版"**——**也就是说,走离线 / 嵌入这条路,拿不到它最新的那套渲染模式。** 集成后的包体增量:iOS 约 8.7 MB,Android(仅 arm64-v8a)约 8.1 MB。
|
||
|
||
> **所以准确的说法不是"离线打包可以定制",而是:你拿到的是一个必须围着闭源运行时搭起来的壳工程——能在壳外面加东西,不能改壳里面的东西。** 一旦需求落在"改壳里面",这条路就是死的,且没有第二个人能帮你改,因为源码不公开。
|
||
|
||
对照 Flutter:原生侧就是一个标准的、完整的 Android / iOS 工程,`Application`、`Activity`、`AppDelegate` 全部是自己的代码,Flutter 以模块形式挂进去,而不是反过来。要写 Kotlin 写 Kotlin,要写 Swift 写 Swift,没有第二套规则。
|
||
|
||
#### 一个二选一的死结
|
||
|
||
**回到上面那张表里的两个"否":**
|
||
|
||
- 官方文档明确:**"uts加密插件只支持云端传统打包,不支持离线打包、也不支持安心打包"**
|
||
- 而下一节会看到,一些 App 扩展能力(如 Siri 快捷指令)**官方建议的实现路径要求离线打包**
|
||
|
||
**推论:如果项目既用到了加密的付费插件,又需要做需要离线打包才能实现的扩展能力,这两个要求互斥,无解。** 到那时的选择只剩下:放弃扩展能力,或者花钱重新买一套非加密授权(如果厂商提供的话),或者整体迁走。
|
||
|
||
另外两条商务上的绑定,也都来自官方文档:
|
||
|
||
- 付费插件的授权**绑定唯一的 appid 和包名**,官方原文:「如购买者更换了这 2 个信息中的一个,需要重新购买授权」
|
||
- 试用版只能用于自定义基座,**不能用于正式发布**
|
||
|
||
**补充一条口径,避免夸大:** 云端打包每次 2 元、最高档也就每次几十元,**相对项目总投入完全可以忽略,这个数字不值得拿来做文章。** 这一节的问题不是钱,是构建方式被约束住之后带来的连锁限制。
|
||
|
||
### 5.4 App 扩展能力的天花板
|
||
|
||
这是最容易被低估的一块。**App 的形态远不止"页面 + 接口"**,一个用五年的 App 迟早会碰到这些需求:
|
||
|
||
- 手机桌面小组件 / 锁屏小组件(门店当日待办、库存预警一眼可见)
|
||
- 接入系统语音助手(Siri 快捷指令、App Intents)
|
||
- 系统级的多媒体推送、本地进度通知(比如上传进度显示在通知栏)
|
||
- 分享扩展、通知服务扩展等各类 App Extension
|
||
|
||
对照 uni-app x 官方文档的现状:
|
||
|
||
| 扩展能力 | uni-app x 现状 |
|
||
| --- | --- |
|
||
| iOS 桌面小组件 | **没有内置 API**。需在 Xcode 里用 SwiftUI + WidgetKit 做成 `.appex`,放进 UTS 插件的 `app-ios/Plugins/`,再配 `nativeResources/ios/ios-extension.json` 和描述文件;HBuilderX 4.61+ 的云端打包才支持携带 |
|
||
| Siri 快捷指令 / App Intents | **仅靠 UTS 插件无法实现**。官方建议:离线打包的原生工程里实现 `AppShortcutsProvider`,再用 UTS 插件衔接业务逻辑 |
|
||
| 其它 App Extension | 非内置能力,走上面同一条路径 |
|
||
|
||
uni-app x 的扩展能力现状,取自 DCloud 官方文档。
|
||
|
||
#### 安卓侧同样如此:一个桌面小组件的真实交付清单
|
||
|
||
上表是 iOS 侧,容易被理解成"苹果比较特殊"。**实际上安卓侧是一样的。** 下面这份清单来自社区一篇 2026-05 的 UTS 插件实战教程(**注明:这是社区一手实战记录,不是官方文档**),做的就是一个安卓桌面待办小组件,最终要交付的东西是:
|
||
|
||
| 交付物 | 内容 |
|
||
| --- | --- |
|
||
| **三个 Kotlin 文件** | `TodoWidgetNative.kt`(业务)、`TodoWidgetProvider.kt`(`AppWidgetProvider`)、`TodoListRemoteViewsService.kt`(列表数据源) |
|
||
| **AndroidManifest 注册** | receiver 声明 + service 声明,service 需带 `BIND_REMOTEVIEWS` 权限 |
|
||
| **三个 XML 布局** | 小组件主布局、列表项布局、空态布局 |
|
||
| **UTS 桥接层** | `interface.uts` + `index.uts`,且导出类型"必须使用 `type` 而非 `interface`" |
|
||
|
||
一个安卓桌面小组件在 uni-app x 下的实际交付物。
|
||
|
||
**除了这些代码本身,工具链还额外强加了三条成本,这才是关键:**
|
||
|
||
- 原文写明:**「每次修改这些文件后必须重新制作自定义基座」**——也就是说,改一行 XML 布局都要重新走一遍自定义基座的制作流程;只有纯 UTS / UVue 的改动才走差量编译。**这在标准安卓开发里就是一次普通的增量编译。**
|
||
- **不能直接 import `R` 类**取资源 ID,要用 `getIdentifier()` 在运行时按字符串查找——编译期的类型检查在这里失效了。
|
||
- 出现 `index.kt` 找不到、`R$id.class` 冲突这类报错时,需要手动清掉 `unpackage/cache/` 再重来。
|
||
|
||
**落点:安卓侧同样要写 Kotlin、同样要碰 AndroidManifest 和 XML 布局。** 而且断了之后不是回到干净的原生开发——是回到原生开发,再加上一个"每改一次就重打基座"的循环。
|
||
|
||
**这里要把话说准,不能说"做不到"——做得到,但代价是三层的:**
|
||
|
||
1. **你最终仍然要打开 Xcode 写 Swift、打开 Android Studio 写 Kotlin。** "一套代码跨端"的承诺在这里就断了,而且是两端一起断。
|
||
2. **在此之上还要额外绕一遍 DCloud 的打包体系**——配 `ios-extension.json`、处理描述文件、每改一次原生文件重做一次自定义基座、在云端打包和离线打包之间做取舍。这是标准原生开发里不存在的额外一层。
|
||
3. **而官方给出的那条"离线打包"退路,本身就是 5.3 里那个受限的壳工程**——`Application` 得继承 `DCloudApplication`、传统离线 SDK 不支持 Kotlin、运行时闭源不可改。它不是一条干净的原生开发通道,只是一个开口更大一点的口子。
|
||
|
||
> 一句话概括:**你既要会 Swift 和 Kotlin,又要额外学一套 DCloud 的插件与打包规则,最后还只能在别人的壳外面加东西。**
|
||
|
||
相比之下,Flutter 项目的原生侧就是完整、开放、自己说了算的 Xcode 和 Android Studio 工程,做扩展就是标准的原生开发,没有第二套规则要学,也没有改不动的黑盒。
|
||
|
||
**这正好回到 1.3 节那张表的最后一列:能力天花板在谁手里。**
|
||
|
||
### 5.5 小结
|
||
|
||
| 工程维度 | Flutter | uni-app x |
|
||
| --- | --- | --- |
|
||
| 插件开发能否命令行化 | 能 | **不能,绑定 HBuilderX** |
|
||
| 接入现有 GitLab 流水线 | 原生支持 | 存在必须人工介入的环节 |
|
||
| 原生工程归谁 | **自己的工程**,Flutter 以模块挂进去 | **DCloud 的壳工程**,自己的东西放进去;`Application` 须继承 `DCloudApplication` |
|
||
| 运行时能否排查 / 修改 | 引擎开源,可读可改 | **闭源二进制(AAR),不可改** |
|
||
| 宿主原生代码语言 | Kotlin / Swift,无限制 | 官方原文:**「App离线SDK不支持Kotlin」** |
|
||
| 加密付费插件与离线打包 | 不适用 | **互斥** |
|
||
| 桌面小组件 / Siri 等扩展 | 标准原生开发 | **两端都要写原生**(Swift + Kotlin)+ 额外绕打包体系 + 每改一次原生文件重做自定义基座 |
|
||
| 构建是否经第三方云 | 否,全在自有流水线 | 云端打包方式下需要 |
|
||
|
||
工程链路对比。倒数第一行对有正式安全评审流程的企业是需要走流程回答的问题,不是一句"没事的"能带过的技术细节。
|
||
|
||
---
|
||
|
||
## 6 结论
|
||
|
||
### 6.1 成本:首版工时不会差很多
|
||
|
||
先把成本拆开,才能判断换框架到底影响哪一块:
|
||
|
||
| 成本构成 | 占比区间 | uni-app x 相对 Flutter |
|
||
| --- | --- | --- |
|
||
| **业务逻辑与外围系统集成、联调** | 约 45–55% | 基本无差异(跟框架无关) |
|
||
| **UI 实现** | 约 20–25% | 略省(Vue 熟悉度高) |
|
||
| **原生能力与桥接** | 约 10–15% | 明显更贵 |
|
||
| **工程、CI、发布、可观测** | 约 10–15% | 明显更贵 |
|
||
|
||
首版投入的成本构成与相对差异。占比区间是基于本项目形态的估算,不同团队会有出入,但量级关系是稳定的。
|
||
|
||
```
|
||
占比 uni-app x 的影响
|
||
────────────────────────────────
|
||
业务集成 45-55% ───── 无差异
|
||
UI 实现 20-25% ↓ 略省 ← 它的优势只作用在这一块
|
||
原生桥接 10-15% ↑ 更贵 ←┐
|
||
工程 CI 10-15% ↑ 更贵 ←┘ 它的额外成本作用在这两块
|
||
```
|
||
|
||
**uni-app x 的效率优势作用在占比第二小的那一块,而它的额外成本作用在另外两块。** 一加一减,**首版总投入差异在 ±10% 以内,可以认为基本持平。**
|
||
|
||
这句话给得干脆,不留模糊:**成本不是选择 Flutter 的理由,也不是选择 uni-app x 的理由。**
|
||
|
||
### 6.2 五年视角:这才是真正的差异
|
||
|
||
首版持平,但这个系统要跑五年,需求只会越加越多。**那就把时间轴拉长,两边各回看五年。**
|
||
|
||
**Flutter 这五年(2020 → 2026):**
|
||
|
||
从一个不被看好的新框架,长成跨端开发的主流选择。今天主仓库 178,643 star、31,002 fork、91,171 次提交,引擎到框架全部开源。同时它支持以模块形式嵌入已有的原生 App,意味着它既能做整个 App,也能作为某条业务流嵌进别人的 App 里——**这是一条向上兼容、路越走越宽的路线。**
|
||
|
||
需要说明的是,原生开发并没有消失,平台特性、系统扩展这些活仍然要写原生——**而这恰恰和本项目的情况吻合:我们本来就要写十几个原生插件。**
|
||
|
||
**DCloud 这五年:**
|
||
|
||
同一时期换了三代 App 方案——5+ 应用、nvue(基于修改过的 Apache Weex 引擎,而 Weex 本身已于 2021 年 5 月从 Apache 孵化器退役、6 月仓库归档),到现在的 uni-app x。**官方已说明 nvue 和 5+ 的维护在 2024 年停止,建议迁移到 uni-app x。**
|
||
|
||
**这不是攻击,这是可查证的平台连续性记录。** 一边是同一条主线持续演进十一年、没让用户推倒重来过;一边是每隔几年换一代底座、并要求存量项目迁移。**站在 2026 年选一个要用到 2031 年的技术栈,这条记录应该被正面评估。**
|
||
|
||
### 6.3 厂商投入与治理结构
|
||
|
||
| | Flutter | uni-app x |
|
||
| --- | --- | --- |
|
||
| 主导方 | Google + 全球开源社区 | DCloud 一家公司 |
|
||
| 可见的工程投入 | 91,171 次公开提交,含引擎 | 11,216 次公开提交,**Runtime/SDK 闭源无公开记录** |
|
||
| 极端情况下的退路 | BSD 开源,可自行 fork 维护 | **没有第二个可以接手的主体** |
|
||
|
||
治理结构对比。这是风险管理问题,不是产品好恶问题。
|
||
|
||
### 6.4 推荐 Flutter
|
||
|
||
四条理由收口:
|
||
|
||
**① 架构路线就决定了适用性。** uni-app 系是为"小程序 + H5 + App 多端复用"设计的,而这个项目正在关掉那六套小程序、首版只发两个平台。**它最值钱的能力在这里没有买家,我们只承担代价。**
|
||
|
||
**② 本项目原生能力密度高,这部分工作量不会因换框架而减少。** 十几项原生能力要逐个实现、逐个在两端验证。Flutter 在原生桥接、指定 SDK 接入、以及与既有流水线的契合度上都更成熟,而 uni-app x 的效率优势只作用在占比约两成的 UI 实现上。
|
||
|
||
**③ 生态与开放程度不在一个量级。** 8 倍的公开提交量差距,加上"Flutter 引擎开源、uni-app x Runtime 闭源"这个层次差异——决定了遇到底层问题时,一边能自己解决,一边只能等厂商。
|
||
|
||
**④ 能力天花板归属不同。** Flutter 的天花板是我们自己的工程能力;uni-app x 的天花板是厂商插件市场和打包体系。**五年周期里,这一条的复利效应最大。**
|
||
|
||
### 6.5 公平地说,uni-app x 强于 Flutter 的三点
|
||
|
||
这一节不能省。一份只说对方缺点的评估,在技术评审面前站不住。
|
||
|
||
**① 鸿蒙支持目前确实更完整。这一条要说得精确,分三层:**
|
||
|
||
- **对 uni-app x 有利的部分,如实写明:** UTS 可直接编译成鸿蒙的 ArkTS,鸿蒙在它这里是一等公民路径。而 Google 已经明确**不会在 Flutter 主线支持鸿蒙**——官方仓库里那条鸿蒙适配 issue(#150536)的处理结果是 **Closed as not planned**。这不是"还没做",是"不打算做"。
|
||
- **但差距在收窄:** 鸿蒙侧的 Flutter 适配由 OpenHarmony-SIG 的社区分支承接,**2026 年 1 月已成立 Flutter SIG 做治理**,按季度跟进主线版本;目前 **3.41 的鸿蒙版已发布,3.44 的鸿蒙版预计 2026 年 9 月**。它不是一个无人维护的野生 fork。
|
||
- **对本项目的具体含义:** 我们的版本基线正是 **Flutter 3.44.9**,对应的鸿蒙版下个月就到。**鸿蒙不在本项目首版范围内**,而我们刻意停在 3.44.9 没追最新版,本来就是为后续接鸿蒙留兼容窗口。所以这条差距在本项目的时间线内是可控的。
|
||
|
||
**结论仍然是:如果鸿蒙将来变成硬需求,uni-app x 在这一项上更省事,应当如实计入。** 只是它比"Flutter 做不了鸿蒙"要小得多。
|
||
|
||
**② 小程序与 H5 的复用能力是真实存在的。** 将来若又有"同一套业务同时发 App 和小程序"的需求,它的价值会立刻显现。本项目用不上,但这是它客观的长处。
|
||
|
||
**③ UTS 这门语言的设计思路是对的。** 它直接编译成 Kotlin 和 Swift,比传统那种"传一个字符串方法名 + 一包弱类型参数"的桥接方式干净得多,方向上是正确的。**我们对 uni-app x 的保留意见不在语言设计,在它外面那层工具链和打包体系**——第 4、5 章列的问题,没有一条是 UTS 语言本身造成的。
|
||
|
||
以上三点是**能力层面**的长处。另外还有三项 uni-app x 占优、但不属于能力范畴的:**包体更小、内存占用更低、支持热更新**——这三项连同 DCloud 官方对比材料的逐条核验一并放在[附录 C](#附录-c-对-dcloud-官方对比材料的核验)。
|
||
|
||
### 6.6 如果最终选择 uni-app x,需要先落实的六项前提
|
||
|
||
如果业务方权衡后仍倾向 uni-app x,以下六项应在开工前落实——它们会让这个选择的真实成本变得可见:
|
||
|
||
1. **F6 书面同意**在其页面中引入 `uni.webview.js`,并承诺配合联调排期。
|
||
2. **神策提供**与我方后端版本匹配的 uni-app x SDK,并明确后续支持与升级责任。
|
||
3. **Bugly 的 UTS 封装完成并验证**,含 iOS 侧的崩溃符号化。
|
||
4. **DCloud 明确 CLI / CI 的可行路径**;如果没有,我方需接受构建链路中存在人工用 HBuilderX 出包的环节,并据此调整发布流程。
|
||
5. **确认云端打包与离线打包的取舍**:是否会用加密付费插件,是否有需要离线打包的扩展需求,两者互斥时以哪个为准。**并明确知悉:即使走离线打包,原生工程仍是围着 DCloud 闭源二进制的壳工程,运行时行为不可改。**
|
||
6. **接受首版拿不到多端复用收益**——那六个小程序正在被这个项目关掉。
|
||
|
||
**前四项任何一项落不实,都应重新评估选型。**
|
||
|
||
### 6.7 最终结论
|
||
|
||
综合本项目的实际约束——架构路线的适配性、F6 集成、原生能力密度、指定的两个 SDK、既有的工程流水线、生态开放程度、以及五年周期内的能力天花板——
|
||
|
||
**我们推荐 Flutter。**
|
||
|
||
---
|
||
|
||
## 附录 A 数据与事实来源
|
||
|
||
本文档中所有关于 uni-app / uni-app x 的技术判断,**除单独标注者外,均来自 DCloud 官方文档或对应厂商官方文档**;社区数据取自 GitHub 公开接口。全文只有一处引用社区来源(5.4 节的安卓小组件交付清单),已在正文和下表中明确标注。便于客户方自行复核。核验日期:**2026-08-25**。
|
||
|
||
| 结论 | 来源 |
|
||
| --- | --- |
|
||
| 主仓库 star / fork / 提交数等社区数据 | GitHub REST API:[`flutter/flutter`](https://github.com/flutter/flutter)、[`dcloudio/uni-app`](https://github.com/dcloudio/uni-app) |
|
||
| 网页向 App 发消息需引入 `uni.webview.1.5.5.js`;App 向网页走 `evalJS()` | [uni-app x — web-view 组件](https://doc.dcloud.net.cn/uni-app-x/component/web-view.html) |
|
||
| UTS 插件只支持通过 HBuilderX 创建和使用,不支持 CLI | [uni-app x — UTS 插件](https://doc.dcloud.net.cn/uni-app-x/plugin/uts-plugin.html) |
|
||
| 付费插件授权绑定 appid + 包名;加密 UTS 插件只支持云端打包 | [uni-app x — 插件发布与授权](https://doc.dcloud.net.cn/uni-app-x/plugin/publish.html) |
|
||
| iOS 小组件需 Xcode 做 `.appex` + UTS 插件携带 + `ios-extension.json` | [uni-app x — UTS 插件(iOS Extension 章节)](https://github.com/dcloudio/uni-app/blob/uni-app-x/docs/plugin/uts-plugin.md) |
|
||
| Siri 快捷指令仅靠 UTS 插件无法实现,需离线打包 + `AppShortcutsProvider` | [uni-app x — UTS for iOS](https://doc.dcloud.net.cn/uni-app-x/plugin/uts-for-ios.html) |
|
||
| 云端打包与离线打包的能力差异 | [uni-app x — 云打包](https://uniapp.dcloud.net.cn/uni-app-x/tutorial/app-package.html) |
|
||
| 离线 SDK 以编译好的 AAR 交付(`lib.5plus.base-release.aar`、`uniapp-v8-release.aar`、`utsplugin-release.aar` 等,不含源码);自定义 `Application` 须继承 `DCloudApplication`、默认 `MainActivity` 须移除;**「App离线SDK不支持Kotlin」** | [DCloud — App 离线打包(Android)](https://nativesupport.dcloud.net.cn/AppDocs/usesdk/android.html) |
|
||
| uni-app x 有独立的原生 SDK(分 Android / iOS / 鸿蒙版);**"仅支持VDOM模式,蒸汽(Vapor)模式的SDK还未发版"**;包体增量 iOS 约 8.7 MB、Android arm64-v8a 约 8.1 MB | [uni-app x — 原生 SDK / 渐进式集成](https://doc.dcloud.net.cn/uni-app-x/native/) |
|
||
| 云打包计费:每次 2 元;60MB 以下免费,超出按档加收 | [uni-app — 云端打包](https://uniapp.dcloud.net.cn/dev/app/cloud-build.html) |
|
||
| uni-app x 组件与 API 大部分 Apache-2.0 开源;Runtime / SDK 知识产权归 DCloud | [uni-app x 是什么](https://uniapp.dcloud.net.cn/uni-app-x/readme)、[uni-app 使用许可协议](https://uniapp.dcloud.net.cn/license.html) |
|
||
| uni-app x 不支持传统 uni-app 的原生插件;旧插件停止新增上架 | [uni-app x 是什么](https://uniapp.dcloud.net.cn/uni-app-x/readme) |
|
||
| nvue 基于修改过的 Weex 渲染引擎 | [uni-app — nvue 介绍](https://uniapp.dcloud.io/nvue-outline) |
|
||
| nvue 与 5+ 的官方维护于 2024 年停止,建议迁移 uni-app x | [uni-app x 是什么](https://uniapp.dcloud.net.cn/uni-app-x/readme) |
|
||
| Apache Weex 于 2021-05-14 从孵化器退役,仓库 2021-06-03 归档 | [Apache Incubator — Weex 状态页](https://incubator.apache.org/projects/weex.html)、[apache/incubator-weex](https://github.com/apache/incubator-weex) |
|
||
| 神策 uni-app x SDK 不在插件市场,需联系技术顾问索取 | [神策分析 — uni-app x 集成文档](https://manual.sensorsdata.cn/sa/docs/XD3SLh7B/v0300) |
|
||
| Flutter 官方 agent skills 与 MCP server | [Flutter — Agent skills](https://docs.flutter.dev/ai/agent-skills)、[Dart and Flutter MCP server](https://docs.flutter.dev/ai/mcp-server) |
|
||
| Flutter Skills 发布公告(2026-05-06) | [Introducing Skills for Dart and Flutter](https://flutter.dev/blog/introducing-skills-for-dart-and-flutter) |
|
||
| DCloud 官方的 uni-app x 与 Flutter 对比(包体 18M / 8.5M、内存约 138MB / 103MB、仅覆盖 VDOM 模式、"需求墙尚有未完成项"等自陈边界) | [uni-app x — 跨平台技术选型](https://doc.dcloud.net.cn/uni-app-x/select.html) |
|
||
| 字节跳动 90+ 款 Flutter 应用、800+ Flutter 开发者、产品清单与"节省约 1/3 开发时间"(口径为对比原生双端) | [Flutter 中文文档 — 开发者故事 / 案例](https://docs.flutter.cn/resources/case-studies)(2026-06-22 更新) |
|
||
| 安卓桌面小组件在 uni-app x 下的交付清单:3 个 Kotlin 文件 + Manifest 注册 + 3 个 XML 布局 + UTS 桥接;「每次修改这些文件后必须重新制作自定义基座」;需用 `getIdentifier()` 取资源 ID **(社区来源,非官方文档)** | 掘金社区 UTS 插件桌面小组件实战教程,2026-05-31 |
|
||
| Google 明确不在 Flutter 主线支持鸿蒙(Closed as not planned);鸿蒙适配由 OpenHarmony-SIG 社区分支承接,2026-01 成立 Flutter SIG,3.41 鸿蒙版已发布、3.44 鸿蒙版预计 2026-09 | [flutter/flutter issue #150536](https://github.com/flutter/flutter/issues/150536)、[OpenHarmony-SIG / flutter_flutter](https://gitcode.com/openharmony-sig/flutter_flutter) |
|
||
|
||
外部来源清单。凡本文档中标注为"推论"的内容(如"F6 需要改造页面"、"加密插件与离线打包互斥"),均由上表中的事实推出,推理过程已在正文中写明。
|
||
|
||
---
|
||
|
||
## 附录 B 术语表
|
||
|
||
给非技术读者:
|
||
|
||
| 术语 | 通俗解释 |
|
||
| --- | --- |
|
||
| **原生(Native)** | 用 Android 和 iOS 各自官方的语言和工具开发,是"最正统"的做法 |
|
||
| **WebView** | 系统内置的浏览器组件。App 里嵌一个网页,就是靠它 |
|
||
| **JSBridge** | App 和它内嵌的网页之间的通话线路。网页想调手机的相机,得通过它 |
|
||
| **自绘引擎** | 不用系统自带的按钮和列表,自己从零画出每一个像素。Flutter 用的就是这个 |
|
||
| **Runtime(运行时)** | App 跑起来时在底下支撑它的那层引擎代码。它闭源,就意味着出了问题只能等厂商 |
|
||
| **UTS** | uni-app x 的编程语言,能编译成安卓的 Kotlin 和苹果的 Swift |
|
||
| **UVue** | uni-app x 的页面写法,基于 Vue |
|
||
| **nvue / 5+** | DCloud 上两代的 App 方案,官方维护已于 2024 年停止 |
|
||
| **Weex** | 阿里开源的跨端方案,nvue 的渲染引擎基础,已于 2021 年从 Apache 退役 |
|
||
| **Dart** | Flutter 的编程语言 |
|
||
| **Pigeon** | Flutter 官方工具。写一份接口定义,自动生成三种语言的对接代码,避免手写出错 |
|
||
| **HBuilderX** | DCloud 出品的开发工具(IDE),uni-app 系的插件开发目前离不开它 |
|
||
| **CLI(命令行)** | 不用打开图形界面,用命令直接执行。自动化流水线依赖这个 |
|
||
| **CI/CD(流水线)** | 代码提交后自动检查、自动构建、自动发布的机制 |
|
||
| **云端打包 / 离线打包** | 前者把构建交给厂商的服务器;后者在自己的电脑上构建,但拿到的工程核心仍是厂商编译好的二进制 |
|
||
| **AAR** | 安卓的二进制打包格式。拿到 AAR 只能调用它,看不到也改不了里面的代码 |
|
||
| **App Extension(扩展)** | App 主体之外的附加组件,比如桌面小组件、分享面板、语音助手指令 |
|
||
| **符号化** | 崩溃报告里原本是一串看不懂的地址,还原成"哪个文件哪一行出错"的过程 |
|
||
| **热更新** | 不经应用商店审核,直接把新版代码下发到用户手机上 |
|
||
| **VDOM / 蒸汽(Vapor)模式** | uni-app x 的两种渲染模式。后者更新,性能更好,但配套的原生 SDK 尚未发版 |
|
||
| **MCP** | 一种标准协议,让 AI 编程助手能读懂某个框架的专有知识 |
|
||
| **Agent Skills** | 打包好的一组指令,教 AI 编程助手按某个框架的最佳实践干活 |
|
||
|
||
术语对照表。
|
||
|
||
---
|
||
|
||
## 附录 C 对 DCloud 官方对比材料的核验
|
||
|
||
DCloud 官方文档里有一页专门做 uni-app x 与 Flutter 的对比(「跨平台技术选型」)。**客户方技术人员检索"uni-app x vs Flutter"时大概率会看到这一页,所以我们把它读完并逐条核验了。** 结果如下——凡属实的直接认,凡没有数据支撑的说明它没有数据支撑,不做反向解读。
|
||
|
||
| 对比页的论点 | 核验结果 | 对本项目的意义 |
|
||
| --- | --- | --- |
|
||
| Flutter 安装包更大(实测 **18M 对 8.5M**) | **属实。** 自绘引擎必须打进包里,这是路线本身的代价 | 差约 10MB。门店内部业务 App,企业分发、无包体 KPI,不构成决策变量。且 uni-app x 走离线 / 嵌入路径同样有增量:iOS 约 8.7 MB、Android arm64-v8a 约 8.1 MB(DCloud 官方数字) |
|
||
| Flutter 内存占用更高(实测 **约 138MB 对 103MB**) | **属实** | 差约 35MB。门店配发的作业终端,现代机型上不产生可感知影响 |
|
||
| 「dart与原生API的通信…通信损耗非常明显」 | **未附实测数据与测试条件**,属定性表述 | 本项目的原生调用(扫码、拍照、上传)是低频、事件驱动的,不在渲染热路径;且接口由 Pigeon 生成三端强类型代码,不是字符串方法名。**本项目真正吃紧的通信链路是嵌 F6 那条——恰恰是 uni-app x 更弱的地方,见 3.1** |
|
||
| 「原生渲染和flutter自渲染并存时,问题很多」 | **未附实测数据**,但原生与自绘混排确是业界已知难点,这个方向上的提醒是成立的 | 本项目唯一的混排点是 WebView,用的是 Flutter 官方团队维护的一等公民插件,不是第三方封装。混排面积小且可控 |
|
||
| 「dart生态…以及比较难用的嵌套写法」 | 生态一项与第 4 章的公开数据相反(公开提交量、大厂落地规模均为 Flutter 占优);**嵌套写法这条是真实体验问题**,深层嵌套的可读性确实不如模板语法 | 嵌套写法属编码习惯与工具问题:IDE 的结构提示、格式化与重构快捷键已覆盖,团队上手一两周即适应。**这一条我们不辩解,但它不影响能力上限** |
|
||
| 「热更新」 | **属实,且是对方一条真优势** | 单独说明,见下 |
|
||
|
||
对 DCloud 官方对比页各项论点的核验。
|
||
|
||
> **这份对比里给出实测数字的只有包体和内存两项,差距分别约 10MB 和 35MB;其余论点均为定性表述,未附测试条件或数据。**
|
||
>
|
||
> 我们认为这个事实本身值得客户方注意:**一家厂商在自己撰写的公开对比材料里,通常会把手上最有力的证据放上来——而这份材料里最有力的证据是安装包大小。** 这从侧面说明了两条路线的差距集中在哪些维度上:不在能力,在体积。
|
||
|
||
**同一页里,DCloud 也标注了这份对比的边界。我们认为这些自陈是客观的,一并列出:**
|
||
|
||
- 该测试**仅覆盖 VDOM 模式**,蒸汽(Vapor)模式不在对比范围内
|
||
- 官方原文提到其**「需求墙尚有未完成项」**
|
||
- Android 侧页面元素过多时仍会拖慢性能,复杂场景需改用 draw 方式实现
|
||
- 引入常用库之后,uni-app x 的包体同样会增长
|
||
|
||
**这几条说明上面那两个数字是有前提的**:它们是特定模式、特定测试工程下的结果,不宜直接外推到一个有十几项原生能力、要嵌第三方网页的真实业务 App 上。
|
||
|
||
### 补充一条对方的真实优势:热更新
|
||
|
||
**uni-app 支持热更新(wgt 方式),Flutter 不支持。这一条我们主动列出,不等对方提。**
|
||
|
||
对很多项目来说这是实打实的价值——线上出了问题不用等应用商店审核,直接下发修复。需要一并说明的是:
|
||
|
||
- 苹果的审核政策对"绕过商店下发可执行逻辑"长期处于灰色地带,规模化使用存在被下架的风险敞口
|
||
- 本项目的发版链路已经定了:**安卓走托管的 OTA 分发页,iOS 走 TestFlight + App Store**,都是正规链路
|
||
- 企业侧的安全与合规评审,通常也不倾向于接受"可以绕开商店直接下发代码"这种能力
|
||
|
||
**所以准确的说法是:这条优势客观存在,但在本项目已确定的发版模式下用不上。** 如果将来发版策略改变、热更新变成硬需求,这一条应当重新计入。
|
||
|
||
### 这一节的用途
|
||
|
||
写这一节不是为了驳倒谁,是为了让评审会上不出现"我在网上看到 DCloud 说 Flutter 怎样怎样"这种悬空的讨论。**对方的每一条论点,上面都有一个明确的答复:属实的认下来并说明影响,没有数据的指出它没有数据,对我们不利的(包体、内存、热更新、鸿蒙)主动列出。**
|
||
|
||
结论不因此改变——**这些差异全部落在本项目不敏感的维度上,而第 3 章那几条落在敏感维度上的差异,方向是相反的。**
|