48 KiB
前端技术路线评估: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 流水线 | 原生支持 | — | 结构性错配 |
| 鸿蒙 | 社区分支,落后一段时间 | 支持 | 支持更完整(这一项 uni-app x 更强) |
| 首版成本 | 基准 | — | ±10% 以内,基本持平 |
三条路线总览。uni-app(传统版)几格标"—",是因为它在"界面本质上是网页"这一条上就已经不适合本项目,后续章节重点放在 Flutter 与 uni-app x 的对比。每一行的依据见第 1–5 章,外部数据来源见附录 A。
1 市面上的跨端方案
1.1 目前可选的技术栈
先把台面上的选项摆全,再谈取舍:
| 方案 | 出品方 | 语言 | 首次发布 | 现状 |
|---|---|---|---|---|
| 原生双端 | Google / Apple | Kotlin · Swift | — | 平台官方方案,能力无上限 |
| Flutter | 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"。
这带来两个结构性结果:
- 界面完全脱离系统控件的差异 —— 同一套设计规范在 Android 和 iOS 上落地的结果逐像素一致。
- 原生能力靠标准插件机制直接对接 —— 每个能力封装成独立插件包,接口用官方工具从一份定义文件生成 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,不是游戏,也不是有复杂动效的消费级产品。
拿性能说事经不起追问,我们不把它算进结论。 列在这里只是让对比完整。
真正和体验相关、且在本项目真实存在的差异是视觉一致性:这个 App 要把六套来源不同、不同团队不同时期做的小程序整合成一个东西。整合最大的隐性风险不是功能缺失,而是同一个业务概念在不同页面上叫法不同、长得不同、操作方式也不同——用户会觉得"这还是六个东西,只是塞进了同一个壳子"。Flutter 逐像素自绘,同一套设计规范落地结果完全一致;uni-app x 用系统控件,安卓的按钮和苹果的按钮本来就不一样,要抹平需要额外工作。
3.6 小结
| 本项目的关键维度 | Flutter | uni-app x | 差异是否决定性 |
|---|---|---|---|
| 嵌入 F6 网页 + 双向通道 | 通道由 App 侧建立,F6 零改动 | 需 F6 引入 DCloud 的 JS 文件 | 是 |
| 十几项原生能力 | 三端强类型生成,支持 CLI | UTS 插件,只能经 HBuilderX | 是 |
| Bugly + 神策 | 神策有官方发布包 | 神策需单独索取;Bugly 无官方支持 | 较强 |
| 19 模块的工程边界 | 编译期物理强制 | 靠规范与评审 | 中等 |
| 视觉一致性 | 逐像素一致 | 需额外抹平 | 中等 |
| 渲染性能 | 够用 | 够用 | 否 |
六个维度的逐条对照。最后一行特意列出,是为了说明我们没有把不构成差异的项算进结论里。
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 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.4 这一章对本项目意味着什么
生态不是"锦上添花"的加分项,它决定三件很实际的事:
- 遇到问题能不能自己解决 —— 引擎开源你能读能修,闭源你只能等工单。
- 五年后还有没有人维护 —— 8 倍的提交量差距 + 三代方案换代史,指向两种不同的平台连续性。
- 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 官方文档。
这里要把话说准,不能说"做不到"——做得到,但代价是三层的:
- 你最终仍然要打开 Xcode、用 Swift 写原生扩展。 "一套代码跨端"的承诺在这里就断了。
- 在此之上还要额外绕一遍 DCloud 的打包体系——配
ios-extension.json、处理描述文件、在云端打包和离线打包之间做取舍。这是标准原生开发里不存在的额外一层。 - 而官方给出的那条"离线打包"退路,本身就是 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 等扩展 | 标准原生开发 | 需 Xcode 写原生 + 额外绕打包体系 + 落在受限壳工程里 |
| 构建是否经第三方云 | 否,全在自有流水线 | 云端打包方式下需要 |
工程链路对比。倒数第一行对有正式安全评审流程的企业是需要走流程回答的问题,不是一句"没事的"能带过的技术细节。
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 的三点
这一节不能省。一份只说对方缺点的评估,在技术评审面前站不住。
① 鸿蒙支持目前确实更完整。 UTS 可编译成鸿蒙的 ArkTS,渲染模式已覆盖鸿蒙;Flutter 的鸿蒙支持走社区维护分支,进度落后官方稳定版一段时间。鸿蒙不在本项目首版范围内,我们的 Flutter 版本基线刻意停在 3.44.9 而没追最新版,就是为后续接鸿蒙留兼容窗口。但如果鸿蒙将来变成硬需求,这一条对 uni-app x 有利,应当如实计入。
② 小程序与 H5 的复用能力是真实存在的。 将来若又有"同一套业务同时发 App 和小程序"的需求,它的价值会立刻显现。本项目用不上,但这是它客观的长处。
③ Vue 技术栈上手快,国内人才池更大。 团队组建和后续换人确实更容易。需要提醒的是,uni-app 岗位在市场上常和"Vue / 小程序 / H5 / 前端"捆绑,招到的人不一定有移动端原生经验——对一个原生能力密集的项目,这一点要考虑。
6.6 如果最终选择 uni-app x,需要先落实的六项前提
如果业务方权衡后仍倾向 uni-app x,以下六项应在开工前落实——它们会让这个选择的真实成本变得可见:
- F6 书面同意在其页面中引入
uni.webview.js,并承诺配合联调排期。 - 神策提供与我方后端版本匹配的 uni-app x SDK,并明确后续支持与升级责任。
- Bugly 的 UTS 封装完成并验证,含 iOS 侧的崩溃符号化。
- DCloud 明确 CLI / CI 的可行路径;如果没有,我方需接受构建链路中存在人工用 HBuilderX 出包的环节,并据此调整发布流程。
- 确认云端打包与离线打包的取舍:是否会用加密付费插件,是否有需要离线打包的扩展需求,两者互斥时以哪个为准。并明确知悉:即使走离线打包,原生工程仍是围着 DCloud 闭源二进制的壳工程,运行时行为不可改。
- 接受首版拿不到多端复用收益——那六个小程序正在被这个项目关掉。
前四项任何一项落不实,都应重新评估选型。
6.7 最终结论
综合本项目的实际约束——架构路线的适配性、F6 集成、原生能力密度、指定的两个 SDK、既有的工程流水线、生态开放程度、以及五年周期内的能力天花板——
我们推荐 Flutter。
附录 A 数据与事实来源
本文档中所有关于 uni-app / uni-app x 的技术判断,均来自 DCloud 官方文档或对应厂商官方文档;社区数据取自 GitHub 公开接口。便于客户方自行复核。核验日期:2026-08-25。
| 结论 | 来源 |
|---|---|
| 主仓库 star / fork / 提交数等社区数据 | GitHub REST API:flutter/flutter、dcloudio/uni-app |
网页向 App 发消息需引入 uni.webview.1.5.5.js;App 向网页走 evalJS() |
uni-app x — web-view 组件 |
| UTS 插件只支持通过 HBuilderX 创建和使用,不支持 CLI | uni-app x — UTS 插件 |
| 付费插件授权绑定 appid + 包名;加密 UTS 插件只支持云端打包 | uni-app x — 插件发布与授权 |
iOS 小组件需 Xcode 做 .appex + UTS 插件携带 + ios-extension.json |
uni-app x — UTS 插件(iOS Extension 章节) |
Siri 快捷指令仅靠 UTS 插件无法实现,需离线打包 + AppShortcutsProvider |
uni-app x — UTS for iOS |
| 云端打包与离线打包的能力差异 | uni-app x — 云打包 |
离线 SDK 以编译好的 AAR 交付(lib.5plus.base-release.aar、uniapp-v8-release.aar、utsplugin-release.aar 等,不含源码);自定义 Application 须继承 DCloudApplication、默认 MainActivity 须移除;「App离线SDK不支持Kotlin」 |
DCloud — App 离线打包(Android) |
| uni-app x 有独立的原生 SDK(分 Android / iOS / 鸿蒙版);"仅支持VDOM模式,蒸汽(Vapor)模式的SDK还未发版";包体增量 iOS 约 8.7 MB、Android arm64-v8a 约 8.1 MB | uni-app x — 原生 SDK / 渐进式集成 |
| 云打包计费:每次 2 元;60MB 以下免费,超出按档加收 | uni-app — 云端打包 |
| uni-app x 组件与 API 大部分 Apache-2.0 开源;Runtime / SDK 知识产权归 DCloud | uni-app x 是什么、uni-app 使用许可协议 |
| uni-app x 不支持传统 uni-app 的原生插件;旧插件停止新增上架 | uni-app x 是什么 |
| nvue 基于修改过的 Weex 渲染引擎 | uni-app — nvue 介绍 |
| nvue 与 5+ 的官方维护于 2024 年停止,建议迁移 uni-app x | uni-app x 是什么 |
| Apache Weex 于 2021-05-14 从孵化器退役,仓库 2021-06-03 归档 | Apache Incubator — Weex 状态页、apache/incubator-weex |
| 神策 uni-app x SDK 不在插件市场,需联系技术顾问索取 | 神策分析 — uni-app x 集成文档 |
| Flutter 官方 agent skills 与 MCP server | Flutter — Agent skills、Dart and Flutter MCP server |
| Flutter Skills 发布公告(2026-05-06) | Introducing Skills for Dart and 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 主体之外的附加组件,比如桌面小组件、分享面板、语音助手指令 |
| 符号化 | 崩溃报告里原本是一串看不懂的地址,还原成"哪个文件哪一行出错"的过程 |
| MCP | 一种标准协议,让 AI 编程助手能读懂某个框架的专有知识 |
| Agent Skills | 打包好的一组指令,教 AI 编程助手按某个框架的最佳实践干活 |
术语对照表。