add tech selection h5 page v2
This commit is contained in:
+58
-88
@@ -9,16 +9,16 @@
|
||||
@import url('https://fonts.googleapis.com/css2?family=DM+Mono:wght@400;500&family=Noto+Sans+SC:wght@400;500;600;700;800&display=swap');
|
||||
|
||||
:root {
|
||||
--ink: #102d43;
|
||||
--muted: #587083;
|
||||
--paper: #f7f3ea;
|
||||
--paper-deep: #ebe4d4;
|
||||
--line: #cfd8d4;
|
||||
--orange: #ee7041;
|
||||
--teal: #007d78;
|
||||
--lime: #b9d551;
|
||||
--blue: #377fc7;
|
||||
--shadow: 0 22px 55px rgba(17, 39, 56, .15);
|
||||
--ink: #1b1b1b;
|
||||
--muted: #5f6368;
|
||||
--paper: #f7f7f8;
|
||||
--paper-deep: #e6e6e9;
|
||||
--line: #d4d4d8;
|
||||
--orange: #e20074;
|
||||
--teal: #1f1f1f;
|
||||
--lime: #e20074;
|
||||
--blue: #4b4b50;
|
||||
--shadow: 0 22px 55px rgba(27, 27, 27, .16);
|
||||
}
|
||||
|
||||
* { box-sizing: border-box; }
|
||||
@@ -78,8 +78,8 @@
|
||||
.page.lime { border-color: var(--lime); }
|
||||
@keyframes enter { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: translateY(0); } }
|
||||
.eyebrow { margin: 0 0 11px; color: var(--teal); font-family: "DM Mono", monospace; font-size: 12px; font-weight: 500; letter-spacing: .1em; text-transform: uppercase; }
|
||||
.orange .eyebrow { color: #bc4d25; }
|
||||
.blue .eyebrow { color: #2769aa; }
|
||||
.orange .eyebrow { color: #a00052; }
|
||||
.blue .eyebrow { color: #4b4b50; }
|
||||
h1, h2, h3, p { margin-top: 0; }
|
||||
h1 { max-width: 920px; margin-bottom: 18px; font-size: clamp(34px, 5vw, 62px); line-height: 1.12; letter-spacing: 0; }
|
||||
h2 { max-width: 760px; margin-bottom: 26px; font-size: clamp(28px, 4vw, 46px); line-height: 1.18; letter-spacing: 0; }
|
||||
@@ -92,7 +92,7 @@
|
||||
.decision strong { display: block; margin: 26px 0 12px; font-size: clamp(32px, 4.4vw, 55px); line-height: 1; }
|
||||
.decision p { max-width: 500px; margin-bottom: 0; color: #d6e2e8; line-height: 1.7; }
|
||||
.facts { display: grid; gap: 1px; background: var(--line); }
|
||||
.fact { padding: 17px 20px; background: #f1f4ec; }
|
||||
.fact { padding: 17px 20px; background: #ffffff; }
|
||||
.fact span { display: block; color: var(--muted); font-size: 12px; }
|
||||
.fact b { display: block; margin-top: 5px; font-family: "DM Mono", monospace; font-size: 20px; }
|
||||
.architecture { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); border-top: 1px solid var(--line); border-left: 1px solid var(--line); }
|
||||
@@ -110,16 +110,16 @@
|
||||
.callout { margin-top: 24px; padding: 18px 21px; border-left: 4px solid var(--orange); color: #3d5263; background: #fff0e8; line-height: 1.7; }
|
||||
.bridge { display: grid; grid-template-columns: 1fr 1fr; gap: 18px; }
|
||||
.bridge-way { padding: 21px; border: 1px solid var(--line); }
|
||||
.bridge-way.good { border-color: var(--teal); background: #eef8f4; }
|
||||
.bridge-way.risk { border-color: #edb49f; background: #fff5ef; }
|
||||
.bridge-way.good { border-color: var(--teal); background: #f3f3f4; }
|
||||
.bridge-way.risk { border-color: #e20074; background: #fff0f7; }
|
||||
.bridge-way h3 { display: flex; align-items: center; gap: 8px; }
|
||||
.tag { display: inline-block; padding: 2px 6px; color: white; background: var(--teal); font-family: "DM Mono", monospace; font-size: 11px; font-weight: 400; }
|
||||
.risk .tag { background: var(--orange); }
|
||||
.bridge-way p { margin-bottom: 0; color: #425b6c; font-size: 14px; line-height: 1.7; }
|
||||
.capabilities { display: grid; grid-template-columns: repeat(5, 1fr); gap: 8px; }
|
||||
.capability { min-height: 84px; padding: 14px; border-top: 3px solid var(--blue); background: #eef4fb; font-size: 14px; font-weight: 700; }
|
||||
.capability:nth-child(2n) { border-color: var(--orange); background: #fff0e8; }
|
||||
.capability:nth-child(3n) { border-color: var(--teal); background: #eaf6f1; }
|
||||
.capability { min-height: 84px; padding: 14px; border-top: 3px solid var(--blue); background: #f1f1f3; font-size: 14px; font-weight: 700; }
|
||||
.capability:nth-child(2n) { border-color: var(--orange); background: #fff0f7; }
|
||||
.capability:nth-child(3n) { border-color: var(--teal); background: #eeeeef; }
|
||||
.numbers { display: grid; grid-template-columns: 1.1fr .9fr .9fr; gap: 1px; background: var(--line); }
|
||||
.number { min-height: 175px; padding: 24px; background: #fffdf8; }
|
||||
.number b { display: block; color: var(--teal); font-family: "DM Mono", monospace; font-size: clamp(34px, 5vw, 61px); line-height: 1; }
|
||||
@@ -133,6 +133,22 @@
|
||||
.case-copy small { color: var(--teal); font-family: "DM Mono", monospace; font-size: 11px; letter-spacing: .06em; }
|
||||
.case-copy h3 { margin: 9px 0 7px; }
|
||||
.case-copy p { margin: 0; color: var(--muted); font-size: 13px; line-height: 1.65; }
|
||||
.page-note { max-width: 820px; margin: 0 0 22px; color: var(--muted); font-size: 15px; line-height: 1.75; }
|
||||
.signal-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 12px; }
|
||||
.signal { min-height: 150px; padding: 20px; border-top: 4px solid var(--ink); background: #f1f1f3; }
|
||||
.signal.emphasis { color: white; border-color: var(--orange); background: var(--ink); }
|
||||
.signal small { display: block; margin-bottom: 16px; color: var(--muted); font-family: "DM Mono", monospace; font-size: 11px; letter-spacing: .06em; }
|
||||
.signal.emphasis small { color: #ffb5d9; }
|
||||
.signal b { display: block; margin-bottom: 8px; font-size: 18px; }
|
||||
.signal p { margin: 0; color: var(--muted); font-size: 14px; line-height: 1.6; }
|
||||
.signal.emphasis p { color: #f3d8e6; }
|
||||
.timeline { display: grid; grid-template-columns: repeat(4, 1fr); gap: 1px; background: var(--line); }
|
||||
.timeline div { min-height: 145px; padding: 18px; background: #fff; }
|
||||
.timeline b { display: block; margin-bottom: 12px; color: var(--orange); font-family: "DM Mono", monospace; font-size: 14px; }
|
||||
.timeline p { margin: 0; color: var(--muted); font-size: 14px; line-height: 1.55; }
|
||||
.decision-list { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
|
||||
.decision-item { padding: 18px; border-left: 4px solid var(--orange); background: #fff0f7; line-height: 1.65; }
|
||||
.decision-item b { display: block; margin-bottom: 5px; }
|
||||
.pipeline { display: grid; grid-template-columns: repeat(4, 1fr); gap: 10px; margin-top: 28px; }
|
||||
.pipeline-step { position: relative; min-height: 155px; padding: 20px; border: 1px solid var(--line); }
|
||||
.pipeline-step b { display: block; margin-bottom: 12px; font-family: "DM Mono", monospace; font-size: 12px; }
|
||||
@@ -170,11 +186,11 @@
|
||||
.meta { display: none; }
|
||||
.shell { width: min(100% - 28px, 680px); margin-top: 14px; }
|
||||
.page { min-height: 0; padding: 30px 20px; }
|
||||
.key-decision, .bridge, .split-note, .finale, .case-studies { grid-template-columns: 1fr; }
|
||||
.key-decision, .bridge, .split-note, .finale, .case-studies, .signal-grid, .decision-list { grid-template-columns: 1fr; }
|
||||
.case-study { grid-template-columns: 128px 1fr; }
|
||||
.architecture { grid-template-columns: repeat(2, 1fr); }
|
||||
.capabilities { grid-template-columns: repeat(2, 1fr); }
|
||||
.numbers { grid-template-columns: 1fr; }
|
||||
.numbers, .timeline { grid-template-columns: 1fr; }
|
||||
.pipeline { grid-template-columns: repeat(2, 1fr); }
|
||||
.cost-row { grid-template-columns: 92px 1fr; }
|
||||
.cost-impact { grid-column: 2; }
|
||||
@@ -192,77 +208,31 @@
|
||||
|
||||
<main class="shell">
|
||||
<div class="chapter-strip" aria-label="章节导航" role="tablist">
|
||||
<button class="chapter-tab" role="tab" aria-selected="true" aria-controls="chapter-1" data-page="0">01 概览</button>
|
||||
<button class="chapter-tab" role="tab" aria-selected="false" aria-controls="chapter-2" data-page="1">02 架构</button>
|
||||
<button class="chapter-tab" role="tab" aria-selected="false" aria-controls="chapter-3" data-page="2">03 业务适配</button>
|
||||
<button class="chapter-tab" role="tab" aria-selected="false" aria-controls="chapter-4" data-page="3">04 生态治理</button>
|
||||
<button class="chapter-tab" role="tab" aria-selected="false" aria-controls="chapter-5" data-page="4">05 工程链路</button>
|
||||
<button class="chapter-tab" role="tab" aria-selected="false" aria-controls="chapter-6" data-page="5">06 结论</button>
|
||||
<button class="chapter-tab" role="tab" aria-selected="true" aria-controls="page-1" data-page="0">0.1 摘要</button><button class="chapter-tab" role="tab" aria-selected="false" aria-controls="page-2" data-page="1">0.2 结论</button><button class="chapter-tab" role="tab" aria-selected="false" aria-controls="page-3" data-page="2">0.3 总览</button><button class="chapter-tab" role="tab" aria-selected="false" aria-controls="page-4" data-page="3">1.1 栈盘点</button><button class="chapter-tab" role="tab" aria-selected="false" aria-controls="page-5" data-page="4">1.2 四路线</button><button class="chapter-tab" role="tab" aria-selected="false" aria-controls="page-6" data-page="5">1.3 天花板</button><button class="chapter-tab" role="tab" aria-selected="false" aria-controls="page-7" data-page="6">2.1 uni-app</button><button class="chapter-tab" role="tab" aria-selected="false" aria-controls="page-8" data-page="7">2.2 uni-app x</button><button class="chapter-tab" role="tab" aria-selected="false" aria-controls="page-9" data-page="8">2.3 Flutter</button><button class="chapter-tab" role="tab" aria-selected="false" aria-controls="page-10" data-page="9">3.1 F6 集成</button><button class="chapter-tab" role="tab" aria-selected="false" aria-controls="page-11" data-page="10">3.2 原生能力</button><button class="chapter-tab" role="tab" aria-selected="false" aria-controls="page-12" data-page="11">3.3 工程边界</button><button class="chapter-tab" role="tab" aria-selected="false" aria-controls="page-13" data-page="12">4.1 开放性</button><button class="chapter-tab" role="tab" aria-selected="false" aria-controls="page-14" data-page="13">4.2 落地案例</button><button class="chapter-tab" role="tab" aria-selected="false" aria-controls="page-15" data-page="14">4.3 AI 生态</button><button class="chapter-tab" role="tab" aria-selected="false" aria-controls="page-16" data-page="15">5.1 CI/CD</button><button class="chapter-tab" role="tab" aria-selected="false" aria-controls="page-17" data-page="16">5.2 打包边界</button><button class="chapter-tab" role="tab" aria-selected="false" aria-controls="page-18" data-page="17">5.3 扩展能力</button><button class="chapter-tab" role="tab" aria-selected="false" aria-controls="page-19" data-page="18">6.1 成本</button><button class="chapter-tab" role="tab" aria-selected="false" aria-controls="page-20" data-page="19">6.2 公平比较</button><button class="chapter-tab" role="tab" aria-selected="false" aria-controls="page-21" data-page="20">6.3 建议</button>
|
||||
</div>
|
||||
|
||||
<section class="deck" aria-live="polite">
|
||||
<article class="page active orange" id="chapter-1" role="tabpanel">
|
||||
<p class="eyebrow">Chapter 01 / Executive Summary</p>
|
||||
<h1>面向五年周期的<br>独立 App 技术路线选择。</h1>
|
||||
<p class="lede">Continental Retail APP 将整合并关停六套小程序。首版只面向 Android 与 iOS;在十一种候选技术栈中,核心挑战仍是系统级能力、第三方网页集成与长期工程可控性。</p>
|
||||
<div class="rule"></div>
|
||||
<div class="key-decision">
|
||||
<section class="decision"><span class="decision-label">ASSESSMENT DECISION</span><strong>推荐 Flutter</strong><p>首版投入与 uni-app x 基本持平;真正的差异将出现在未来五年新增系统能力、自动化交付和底层问题的处置能力上。</p></section>
|
||||
<aside class="facts" aria-label="评估信息"><div class="fact"><span>评估对象</span><b>Flutter / uni-app / uni-app x</b></div><div class="fact"><span>首版平台</span><b>Android + iOS</b></div><div class="fact"><span>核验日期</span><b>2026.08.25</b></div></aside>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<article class="page" id="chapter-2" role="tabpanel" hidden>
|
||||
<p class="eyebrow">Chapter 02 / Architecture</p>
|
||||
<h2>十一种技术栈,底层仍然只有四条路线。</h2>
|
||||
<div class="architecture">
|
||||
<section class="route"><span class="route-no">01 / NATIVE</span><h3>原生双端</h3><p>Kotlin 与 Swift 分别开发。能力没有上限,但维护两套代码与团队。</p></section>
|
||||
<section class="route"><span class="route-no">02 / WEBVIEW</span><h3>网页套壳</h3><p>uni-app 的路径。系统能力依赖插件,受 WebView 内核与插件生态制约。</p></section>
|
||||
<section class="route"><span class="route-no">03 / COMPILE</span><h3>编译到系统控件</h3><p>uni-app x、React Native、Kuikly、.NET MAUI 的路径。能力上限取决于“翻译词典”和插件覆盖度。</p></section>
|
||||
<section class="route highlight"><span class="route-no">04 / RENDER</span><h3>自绘引擎</h3><p>Flutter 自己绘制像素,原生能力通过标准插件直接对接,边界由工程能力决定。</p></section>
|
||||
</div>
|
||||
<div class="callout"><b>Kuikly 的位置:</b>腾讯于 2025 年开源、内部落地规模可观,但对外生态仅一年多,且更贴合 Kotlin/KMP 团队与动态化需求。本项目不具备这两个前提,应在未来三年后重新评估。</div>
|
||||
<div class="table-scroll"><table class="compare"><thead><tr><th>维度</th><th>uni-app</th><th>uni-app x</th><th>Flutter</th></tr></thead><tbody><tr><td>路线</td><td>网页套壳</td><td>系统控件编译</td><td>自绘引擎</td></tr><tr><td>界面一致性</td><td>受 WebView 影响</td><td>两端系统控件存在差异</td><td>逐像素一致</td></tr><tr><td>能力天花板</td><td>插件生态</td><td>词典 + 插件生态</td><td>自己的工程能力</td></tr></tbody></table></div>
|
||||
</article>
|
||||
|
||||
<article class="page blue" id="chapter-3" role="tabpanel" hidden>
|
||||
<p class="eyebrow">Chapter 03 / Product Fit</p>
|
||||
<h2>原生能力密度,才是本项目的决定性变量。</h2>
|
||||
<div class="bridge">
|
||||
<section class="bridge-way good"><h3><span class="tag">Flutter</span> F6 网页零改动</h3><p>App 在页面加载后注入胶水代码,单一双向 JavaScript Channel 承担请求与回调。F6 无需引入额外脚本。</p></section>
|
||||
<section class="bridge-way risk"><h3><span class="tag">uni-app x</span> 需要外部厂商配合</h3><p>网页须引入 DCloud 的 <code>uni.webview.js</code>;网页到 App 与 App 到网页是两条不对称单向通道,需自行封装协议。</p></section>
|
||||
</div>
|
||||
<div class="rule"></div>
|
||||
<div class="capabilities"><div class="capability">扫码 / VIN 识别</div><div class="capability">相机 / 相册多选</div><div class="capability">弱网离线与重传</div><div class="capability">带进度的大文件上传</div><div class="capability">定位与运行时权限</div><div class="capability">Bugly 崩溃上报</div><div class="capability">神策埋点 SDK</div><div class="capability">物理返回键拦截</div><div class="capability">WebView 文件选择</div><div class="capability">iOS 隐私清单</div></div>
|
||||
<div class="callout"><b>结论:</b>这些能力无论选择哪条路线都需要实现与双端验证。Flutter 的原生实现可同时服务原生页面和 F6 网页通道;uni-app x 则需在 UTS 插件与 HBuilderX 约束下处理。</div>
|
||||
</article>
|
||||
|
||||
<article class="page lime" id="chapter-4" role="tabpanel" hidden>
|
||||
<p class="eyebrow">Chapter 04 / Ecosystem & Governance</p>
|
||||
<h2>生态的价值,在规模化交付与问题发生时才真正显现。</h2>
|
||||
<div class="numbers"><section class="number"><b>91,171</b><p>Flutter 主仓库公开提交数,包含渲染引擎到框架层。</p></section><section class="number"><b>31,002</b><p>Flutter fork 数。公开协作与问题排查的广度。</p></section><section class="number"><b>~8x</b><p>相对 uni-app 主仓库提交数与 fork 数的量级差异。</p></section></div>
|
||||
<div class="split-note"><p><b>开源的层次不同。</b><br>Flutter 从渲染引擎到框架均以 BSD 协议开源。uni-app x 的组件与 API 开源,但 Runtime、SDK 和 HBuilderX 为 DCloud 自有闭源能力。</p><p><b>这不是偏好问题。</b><br>当问题落在渲染层或运行时,Flutter 可以阅读源码、提交修复或自行维护;uni-app x 需要依赖厂商支持。对于五年周期的核心业务系统,这是不同的风险敞口。</p></div>
|
||||
<div class="case-studies">
|
||||
<article class="case-study"><img src="assets/bmw1.png" alt="My BMW App 的车辆状态和车控界面"><div class="case-copy"><small>BMW / 甲档案例</small><h3>96 个变体,自动化交付</h3><p>My BMW App 覆盖 47 国。其 Mobile 2.0 Platform 可在每次构建中自动生成、测试并部署 96 个变体。</p></div></article>
|
||||
<article class="case-study"><img src="assets/vw4.png" alt="ID. UNYX App 的车辆状态和远程车控界面"><div class="case-copy"><small>ID. UNYX / 乙档案例</small><h3>主干页面承载车控场景</h3><p>大众安徽的法定 SDK 披露将 Flutter 列为 App 全部 L1、L2、L3 页面开发语言,展示真实混合架构的主干选择。</p></div></article>
|
||||
</div>
|
||||
<div class="callout"><b>落地证据:</b>字节 90+ 款、闲鱼、美团商家端、京东、携程、BMW 与 ID. UNYX 的公开材料,指向“原生 / 混合底座 + Flutter 承载业务主干”的成熟形态,正是本项目规划的路径。AI 工具链方面,Flutter / Dart 的 skills 和 MCP 服务也是独立开源资产,可接入多种 agent 工具。</div>
|
||||
</article>
|
||||
|
||||
<article class="page orange" id="chapter-5" role="tabpanel" hidden>
|
||||
<p class="eyebrow">Chapter 05 / Delivery & Extensibility</p>
|
||||
<h2>自动化交付,不能依赖某台机器上的一个 IDE。</h2>
|
||||
<p class="lede">既定链路包含 GitLab CI/CD、三套环境、远程 Mac 构建节点、Android OTA 与 iOS TestFlight。目标是每次发布都可追溯、可复现。</p>
|
||||
<div class="pipeline"><section class="pipeline-step ok"><b>01 / COMMIT</b><p>代码提交后触发 lint、格式化与测试卡点。</p></section><section class="pipeline-step ok"><b>02 / BUILD</b><p>Android / iOS 在自有流水线和构建节点中出包。</p></section><section class="pipeline-step block"><b>03 / UTS PLUGIN</b><p>官方限制:UTS 插件只能经 HBuilderX 创建和使用,不支持 CLI。</p></section><section class="pipeline-step block"><b>04 / PACKAGE</b><p>加密付费插件仅支持云端打包;部分系统扩展官方建议离线打包,形成取舍。</p></section></div>
|
||||
<div class="split-note"><p><b>离线打包不是完整原生工程。</b><br>拿到的是围绕闭源 Runtime / AAR 搭建的壳工程:可在外层添加模块,不能修改运行时内部行为。</p><p><b>扩展能力会回到原生。</b><br>小组件、Siri 快捷指令、分享扩展等最终仍需要 Xcode / Android Studio 与 Swift / Kotlin;Flutter 侧可直接遵循标准原生工程规则。</p></div>
|
||||
</article>
|
||||
|
||||
<article class="page blue" id="chapter-6" role="tabpanel" hidden>
|
||||
<p class="eyebrow">Chapter 06 / Recommendation</p>
|
||||
<h2>首版成本持平,五年后的主动权不一样。</h2>
|
||||
<div class="cost-bars"><div class="cost-row"><b>业务集成 45-55%</b><div class="bar"><span style="width: 88%"></span></div><span class="cost-impact">框架基本无差异</span></div><div class="cost-row"><b>UI 实现 20-25%</b><div class="bar"><span style="width: 40%"></span></div><span class="cost-impact">uni-app x 略省</span></div><div class="cost-row"><b>原生桥接 10-15%</b><div class="bar"><span style="width: 27%"></span></div><span class="cost-impact">uni-app x 更贵</span></div><div class="cost-row"><b>工程与可观测 10-15%</b><div class="bar"><span style="width: 27%"></span></div><span class="cost-impact">uni-app x 更贵</span></div></div>
|
||||
<div class="finale"><ol class="reasons"><li><b>架构适配:</b>项目是独立 App,无法获得多端小程序复用收益。</li><li><b>业务风险:</b>F6 集成和十余项原生能力需要更直接、可控的通道。</li><li><b>长期治理:</b>开放生态与完整原生工程为问题处置保留主动权。</li><li><b>交付能力:</b>Flutter 更匹配现有 GitLab CI/CD 与标准原生扩展方式。</li></ol><aside class="stamp" aria-label="最终技术路线建议"><small>FINAL DECISION</small><b>推荐 Flutter</b><p>uni-app x 在鸿蒙支持、小程序/H5 复用、包体和内存上具有真实优势;但它们不是本项目首版的敏感维度。</p></aside></div>
|
||||
</article>
|
||||
<article class="page active orange" id="page-1" role="tabpanel"><p class="eyebrow">0.1 / Executive Summary</p><h1>面向五年周期的<br>独立 App 技术路线选择。</h1><p class="lede">Continental Retail APP 将整合并关停六套小程序。首版只面向 Android 与 iOS;评估重点不在“画页面快不快”,而在系统能力、第三方网页集成与长期工程主动权。</p><div class="key-decision"><section class="decision"><span class="decision-label">ASSESSMENT DECISION</span><strong>推荐 Flutter</strong><p>首版投入与 uni-app x 基本持平。真正拉开差距的是后续系统级需求、自动化交付和运行时问题的处置空间。</p></section><aside class="facts" aria-label="评估信息"><div class="fact"><span>评估对象</span><b>Flutter / uni-app / uni-app x</b></div><div class="fact"><span>首版平台</span><b>Android + iOS</b></div><div class="fact"><span>外部数据核验</span><b>2026.08.25</b></div></aside></div></article>
|
||||
<article class="page" id="page-2" role="tabpanel" hidden><p class="eyebrow">0.2 / Decision Logic</p><h2>四条可核验的推荐理由。</h2><div class="signal-grid"><section class="signal emphasis"><small>01 / ARCHITECTURE</small><b>适配独立 App</b><p>项目正在关停小程序,不获得 uni-app 系最核心的多端复用收益。</p></section><section class="signal"><small>02 / NATIVE DENSITY</small><b>原生能力密集</b><p>扫码、OCR、上传、定位、离线、权限和 SDK 集成不会因更换框架而消失。</p></section><section class="signal"><small>03 / OWNERSHIP</small><b>能力上限可控</b><p>Flutter 的边界是自身工程能力;uni-app x 的关键边界仍受 Runtime、插件和打包体系影响。</p></section></div><div class="callout"><b>关键判断:</b>这不是“哪种技术更流行”的偏好选择,而是当前项目是否愿意为不使用的多端复用能力,承担工具链和运行时上的约束。</div></article>
|
||||
<article class="page blue" id="page-3" role="tabpanel" hidden><p class="eyebrow">0.3 / Comparison At A Glance</p><h2>优势与代价,都应放到同一张桌子上。</h2><div class="table-scroll"><table class="compare"><thead><tr><th>维度</th><th>Flutter</th><th>uni-app x</th></tr></thead><tbody><tr><td>架构路线</td><td>自绘引擎</td><td>编译到系统控件</td></tr><tr><td>F6 网页</td><td>App 侧建立通道,F6 零改动</td><td>F6 需引入 DCloud JS 文件</td></tr><tr><td>原生能力</td><td>Pigeon 强类型生成,支持 CLI</td><td>UTS 插件,工具链绑定 HBuilderX</td></tr><tr><td>工程归属</td><td>完整自有 Android / iOS 工程</td><td>围绕闭源 Runtime 的壳工程</td></tr><tr><td>客观优势</td><td>生态、开放性与界面一致性</td><td>鸿蒙、一套代码复用、包体与内存</td></tr></tbody></table></div><p class="page-note">包体、内存与鸿蒙是 uni-app x 的真实优势,但均不在本项目首版的敏感维度。</p></article>
|
||||
<article class="page" id="page-4" role="tabpanel" hidden><p class="eyebrow">1.1 / Market Landscape</p><h2>十一种候选技术栈,先完整摆上台面。</h2><div class="table-scroll"><table class="compare"><thead><tr><th>路线</th><th>代表方案</th><th>适用前提</th></tr></thead><tbody><tr><td>原生双端</td><td>Kotlin / Swift</td><td>能力上限优先,接受双端团队</td></tr><tr><td>网页套壳</td><td>uni-app、Taro、Cordova、Capacitor</td><td>小程序 / H5 为主,App 为补充</td></tr><tr><td>编译到系统控件</td><td>uni-app x、React Native、Kuikly、MAUI</td><td>翻译层与插件覆盖需求范围</td></tr><tr><td>自绘引擎</td><td>Flutter</td><td>需要跨端一致且长期演进的独立 App</td></tr><tr><td>逻辑层共享</td><td>Kotlin Multiplatform</td><td>愿意保留两端 UI 开发</td></tr></tbody></table></div><div class="callout"><b>本轮不展开的方案:</b>React Native 的核心前提是已有 React 人力;Taro、Cordova、Capacitor 的重心仍是网页路线;KMP 只共享逻辑;Kuikly 则对外生态仍处早期。</div></article>
|
||||
<article class="page orange" id="page-5" role="tabpanel" hidden><p class="eyebrow">1.2 / Four Architectural Routes</p><h2>品牌不同,能力上限来自同一套底层规律。</h2><div class="architecture"><section class="route"><span class="route-no">01 / NATIVE</span><h3>原生双端</h3><p>系统给什么就能用什么;代价是两份 UI 和两组工程协作。</p></section><section class="route"><span class="route-no">02 / WEBVIEW</span><h3>网页套壳</h3><p>一套 Web 代码覆盖多端;系统能力必须借插件从网页环境打洞。</p></section><section class="route"><span class="route-no">03 / COMPILE</span><h3>编译到控件</h3><p>由语言和词典翻译到 Kotlin / Swift;词典外的能力需要自行补齐。</p></section><section class="route highlight"><span class="route-no">04 / RENDER</span><h3>自绘引擎</h3><p>Flutter 自己绘制像素,系统能力通过标准原生插件直接连接。</p></section></div><p class="page-note">Kotlin Multiplatform 是例外:它默认只共享逻辑层;配上 Compose Multiplatform 才进入 UI 跨端路线。</p></article>
|
||||
<article class="page blue" id="page-6" role="tabpanel" hidden><p class="eyebrow">1.3 / Capability Ceiling</p><h2>五年后真正要问的:天花板在谁手里?</h2><div class="signal-grid"><section class="signal"><small>WEBVIEW</small><b>插件生态</b><p>没有人提供或持续维护的能力,就会成为业务路线的阻塞点。</p></section><section class="signal"><small>COMPILE TO NATIVE</small><b>词典 + 插件</b><p>既受平台映射能力影响,也受插件和 IDE 工具链制约。</p></section><section class="signal emphasis"><small>FLUTTER</small><b>自身工程能力</b><p>原生工程、渲染框架和桥接协议都在项目可掌控范围内。</p></section></div><div class="callout"><b>本项目的结论:</b>需求只会增加,能力上限归属不是技术偏好,而是五年周期的风险管理问题。</div></article>
|
||||
<article class="page" id="page-7" role="tabpanel" hidden><p class="eyebrow">2.1 / uni-app</p><h2>uni-app 的价值,在小程序主导的多端复用。</h2><div class="split-note"><p><b>它是什么。</b><br>使用 Vue / JavaScript 开发,App 端运行在系统 WebView。它的目标是让小程序团队顺便发布 App 与 H5。</p><p><b>它适合什么。</b><br>小程序是主要入口、App 只是辅助触点的商城或业务工具。此时同一套页面复用有明确回报。</p></div><div class="decision-list"><div class="decision-item"><b>项目不匹配点</b>当前项目正在整合并关闭六套小程序,首版也不发布 H5。</div><div class="decision-item"><b>直接后果</b>界面本质仍是网页,重原生能力需要反复通过插件打通。</div></div></article>
|
||||
<article class="page orange" id="page-8" role="tabpanel" hidden><p class="eyebrow">2.2 / uni-app x</p><h2>uni-app x 不是传统 uni-app 的简单升级。</h2><p class="page-note">它使用 UTS / UVue,编译到 Android Kotlin、iOS Swift、鸿蒙 ArkTS,并使用系统原生控件渲染。设计方向值得肯定,但其能力边界仍由映射层、插件和工具链共同决定。</p><div class="signal-grid"><section class="signal"><small>STRENGTH</small><b>UTS 桥接思路清晰</b><p>直接编译目标端语言,相比字符串式方法调用更具类型表达力。</p></section><section class="signal"><small>CONSTRAINT</small><b>旧插件不能直接迁移</b><p>传统 uni-app 原生插件不兼容,旧市场也已停止接受新增上架。</p></section><section class="signal emphasis"><small>PROJECT FIT</small><b>部分适合</b><p>可完成 App,但无法消除本项目中原生集成与自动化交付的复杂度。</p></section></div></article>
|
||||
<article class="page blue" id="page-9" role="tabpanel" hidden><p class="eyebrow">2.3 / Flutter</p><h2>Flutter 的出发点,就是构建独立 App。</h2><div class="split-note"><p><b>一致性。</b><br>Dart 提前编译;界面由自带引擎逐像素绘制,不依赖 Android 与 iOS 控件的默认差异。</p><p><b>连接原生。</b><br>每项系统能力可封装为独立插件。Pigeon 从一份定义生成 Dart、Kotlin、Swift 三端强类型接口,接口失配在编译期暴露。</p></div><div class="callout"><b>架构判断:</b>本项目要做的是一个独立 App,而不是一个小程序附属品。仅从架构选型,Flutter 已满足最直接的适配条件。</div></article>
|
||||
<article class="page orange" id="page-10" role="tabpanel" hidden><p class="eyebrow">3.1 / F6 Web Integration</p><h2>嵌入 F6 网页,是项目最高风险项。</h2><p class="page-note">报价开单、施工查车、结算收银和提醒模块都依赖嵌入的 F6 页面。网页需要调用扫码、拍照、上传、拨号、登录态和门店上下文等 13 项能力、15 个方法,App 也必须反向通知网页。</p><div class="bridge"><section class="bridge-way good"><h3><span class="tag">Flutter</span> 单一双向通道</h3><p>在页面加载完成后由 App 自动注入胶水代码。请求与回调共用协议,例如 <code>{ id, method, params }</code>,F6 无需修改。</p></section><section class="bridge-way risk"><h3><span class="tag">uni-app x</span> 两条单向通道</h3><p>网页须引入 <code>uni.webview.js</code>;网页到 App 用 postMessage,App 到网页用 evalJS,需自行补齐协议与异常处理。</p></section></div></article>
|
||||
<article class="page" id="page-11" role="tabpanel" hidden><p class="eyebrow">3.2 / Native Capability Density</p><h2>真正的工作重心,不是页面,而是系统集成。</h2><div class="capabilities"><div class="capability">扫码 / VIN OCR</div><div class="capability">相机 / 相册多选</div><div class="capability">文件上传进度</div><div class="capability">弱网离线与重传</div><div class="capability">图片压缩</div><div class="capability">定位与权限</div><div class="capability">Bugly 崩溃桥</div><div class="capability">神策 SDK</div><div class="capability">返回键拦截</div><div class="capability">WebView 文件选择</div></div><div class="callout"><b>成本含义:</b>上述能力无论选择哪条路线都需要实现、维护、双端验证。框架对 UI 的效率影响,只覆盖整体工作中较小的一部分。</div></article>
|
||||
<article class="page blue" id="page-12" role="tabpanel" hidden><p class="eyebrow">3.3 / Module Boundaries</p><h2>十九个模块并行开发,边界必须能被强制执行。</h2><div class="timeline"><div><b>19 模块</b><p>近三百条需求,长期多人并行开发。</p></div><div><b>21 包</b><p>Flutter 以 Melos 组织基础设施、业务模块与原生能力层。</p></div><div><b>编译期</b><p>包依赖机制可阻止业务模块直接引用彼此内部实现。</p></div><div><b>第二年</b><p>边界约束的价值,会在重构、替换和新增能力时放大。</p></div></div><p class="page-note">uni-app x 也可以组织工程化目录,但模块边界更多依赖团队自觉和评审纪律,缺少同等强度的物理阻断。</p></article>
|
||||
<article class="page" id="page-13" role="tabpanel" hidden><p class="eyebrow">4.1 / Openness & Continuity</p><h2>关键不是“是否开源”,而是开到哪一层。</h2><div class="numbers"><section class="number"><b>91,171</b><p>Flutter 主仓库公开提交数,包含渲染引擎到框架层。</p></section><section class="number"><b>31,002</b><p>Flutter Fork 数,体现公开协作与问题排查广度。</p></section><section class="number"><b>~8x</b><p>相对 uni-app 主仓库提交数与 Fork 数的量级差异。</p></section></div><div class="split-note"><p><b>Flutter。</b><br>引擎和框架均以 BSD 开源,原生工程由项目自身掌握。</p><p><b>uni-app x。</b><br>组件与 API 开源;Runtime、SDK 与 HBuilderX 为 DCloud 自有闭源能力。</p></div></article>
|
||||
<article class="page orange" id="page-14" role="tabpanel" hidden><p class="eyebrow">4.2 / Production Evidence</p><h2>大型 App 的真实形态,是混合底座加跨端业务主干。</h2><div class="case-studies"><article class="case-study"><img src="assets/bmw1.png" alt="My BMW App 的车辆状态和车控界面"><div class="case-copy"><small>BMW / 甲档案例</small><h3>96 个变体,自动化交付</h3><p>My BMW App 覆盖 47 国。Mobile 2.0 Platform 每次构建可自动生成、测试并部署 96 个变体。</p></div></article><article class="case-study"><img src="assets/vw4.png" alt="ID. UNYX App 的车辆状态和远程车控界面"><div class="case-copy"><small>ID. UNYX / 乙档案例</small><h3>主干页面承载车控场景</h3><p>大众安徽法定 SDK 披露将 Flutter 列为 App 全部 L1、L2、L3 页面开发语言。</p></div></article></div><div class="callout"><b>同一形态的公开案例:</b>字节 90+ 款应用、闲鱼主链路、美团商家端、京东、携程、BMW 与 ID. UNYX 都证明:原生能力仍在原生侧,业务页面可以稳定由 Flutter 承担。</div></article>
|
||||
<article class="page blue" id="page-15" role="tabpanel" hidden><p class="eyebrow">4.3 / AI Toolchain</p><h2>AI 辅助效率,来自开放生态与公开代码沉淀。</h2><div class="table-scroll"><table class="compare"><thead><tr><th>维度</th><th>Flutter / Dart</th><th>uni-app x</th></tr></thead><tbody><tr><td>官方 Skills</td><td>独立开源仓库,可 Fork / PR</td><td>主要内置于 uni-agent</td></tr><tr><td>MCP</td><td>Dart & Flutter MCP Server</td><td>uni-app-x-mcp</td></tr><tr><td>工具适配</td><td>可接入多种 AI 编程工具</td><td>以自家生态和少数工具为主</td></tr><tr><td>公开语料</td><td>近十年全球 Dart / Flutter 项目</td><td>UTS / UVue 较新,公开沉淀有限</td></tr></tbody></table></div><div class="callout"><b>实际影响:</b>当开发者需要生成、调试、重构或验证原生桥接与业务组件时,公开生态的深度会直接反映在生成质量和返工率上。</div></article>
|
||||
<article class="page" id="page-16" role="tabpanel" hidden><p class="eyebrow">5.1 / Delivery Pipeline</p><h2>目标是每个版本都能从一次提交中重建。</h2><p class="lede">既定工程链路:GitLab CI/CD,lint / 格式化 / 测试卡点,dev / uat / prod 三环境,远程 Mac 出 iOS 包,Android OTA 与 iOS TestFlight 分发。</p><div class="pipeline"><section class="pipeline-step ok"><b>01 / COMMIT</b><p>提交触发静态检查、格式化和测试。</p></section><section class="pipeline-step ok"><b>02 / BUILD</b><p>Android / iOS 在自有节点完成可追溯构建。</p></section><section class="pipeline-step block"><b>03 / UTS PLUGIN</b><p>UTS 插件创建和使用绑定 HBuilderX,官方不支持 CLI。</p></section><section class="pipeline-step block"><b>04 / PACKAGE</b><p>云打包、离线打包和加密插件之间存在结构性取舍。</p></section></div></article>
|
||||
<article class="page orange" id="page-17" role="tabpanel" hidden><p class="eyebrow">5.2 / Packaging Boundaries</p><h2>“离线打包”给的是壳,不是完全可控的原生工程。</h2><div class="table-scroll"><table class="compare"><thead><tr><th>范围</th><th>可以修改</th><th>不能修改</th></tr></thead><tbody><tr><td>工程外层</td><td>包名、图标、权限、ABI、原生模块</td><td>运行时页面容器和生命周期</td></tr><tr><td>Android</td><td>Manifest 与 Gradle 配置</td><td>闭源 AAR 内部实现与 UTS 通信机制</td></tr><tr><td>应用入口</td><td>可在约束下定制</td><td>Application 必须继承 DCloudApplication</td></tr><tr><td>语言选择</td><td>Flutter 标准 Kotlin / Swift</td><td>传统离线 SDK 官方声明不支持 Kotlin</td></tr></tbody></table></div><div class="callout"><b>核心区别:</b>Flutter 以模块挂入自己的标准 Android / iOS 工程;uni-app x 离线 / 嵌入路径则是把自定义内容放入围绕闭源运行时构成的宿主壳中。</div></article>
|
||||
<article class="page blue" id="page-18" role="tabpanel" hidden><p class="eyebrow">5.3 / Extensions</p><h2>桌面小组件、Siri 和分享扩展,最终都会回到原生。</h2><div class="signal-grid"><section class="signal"><small>WIDGET</small><b>小组件</b><p>iOS 需要 Xcode、SwiftUI 与 WidgetKit 的 .appex;Android 同样需要 Kotlin、Manifest 和 XML。</p></section><section class="signal"><small>SIRI / INTENTS</small><b>系统语音能力</b><p>官方建议离线打包后在原生工程实现 AppShortcutsProvider,再通过 UTS 衔接业务。</p></section><section class="signal emphasis"><small>CONFLICT</small><b>加密插件与离线打包</b><p>加密 UTS 插件仅支持云端传统打包,和部分扩展所需的离线路径互斥。</p></section></div><p class="page-note">做得到不等于低成本:两端仍需写 Swift / Kotlin,并额外承受一层厂商打包与基座规则。</p></article>
|
||||
<article class="page" id="page-19" role="tabpanel" hidden><p class="eyebrow">6.1 / First Release Cost</p><h2>首版成本基本持平,差异在 ±10% 内。</h2><div class="cost-bars"><div class="cost-row"><b>业务集成 45–55%</b><div class="bar"><span style="width: 88%"></span></div><span class="cost-impact">框架基本无差异</span></div><div class="cost-row"><b>UI 实现 20–25%</b><div class="bar"><span style="width: 40%"></span></div><span class="cost-impact">uni-app x 略省</span></div><div class="cost-row"><b>原生桥接 10–15%</b><div class="bar"><span style="width: 27%"></span></div><span class="cost-impact">uni-app x 更贵</span></div><div class="cost-row"><b>工程与可观测 10–15%</b><div class="bar"><span style="width: 27%"></span></div><span class="cost-impact">uni-app x 更贵</span></div></div><div class="callout"><b>成本不是决策理由。</b> UI 熟悉度带来的节省被原生桥接、插件工具链与 CI / 发布成本抵消,首版不应以工时差异作为主导依据。</div></article>
|
||||
<article class="page orange" id="page-20" role="tabpanel" hidden><p class="eyebrow">6.2 / Fair Comparison</p><h2>uni-app x 的三项真实优势,应当被正面计入。</h2><div class="decision-list"><div class="decision-item"><b>鸿蒙支持更完整</b>UTS 可直接编译 ArkTS;Flutter 主线不支持鸿蒙,社区分支正在跟进。</div><div class="decision-item"><b>小程序与 H5 复用</b>若未来需要 App、小程序、H5 同时发布,价值会立即显现。</div><div class="decision-item"><b>UTS 的语言方向正确</b>直接编译 Kotlin / Swift 的桥接方式比传统字符串式调用更干净。</div><div class="decision-item"><b>包体、内存与热更新</b>uni-app x 在这些方面有实际优势,但本项目没有包体 KPI,发版也采用正规分发链路。</div></div><p class="page-note">这些优势不应被回避;它们只是没有改变本项目在 F6 集成、原生能力密度和 CI 可控性上的关键判断。</p></article>
|
||||
<article class="page blue" id="page-21" role="tabpanel" hidden><p class="eyebrow">6.3 / Final Recommendation</p><h2>推荐 Flutter,把能力上限留在自己的工程里。</h2><div class="finale"><ol class="reasons"><li><b>架构适配:</b>项目是独立 App,无法获得多端小程序复用收益。</li><li><b>业务风险:</b>F6 集成和十余项原生能力需要直接、可控的通道。</li><li><b>长期治理:</b>开放生态与完整原生工程为问题处置保留主动权。</li><li><b>交付能力:</b>Flutter 匹配既有 GitLab CI/CD 与标准原生扩展方式。</li></ol><aside class="stamp" aria-label="最终技术路线建议"><small>FINAL DECISION</small><b>推荐 Flutter</b><p>若最终仍选择 uni-app x,应在开工前落实 F6 改造承诺、神策 SDK、Bugly UTS 封装、CLI/CI 路径以及云端与离线打包的取舍。</p></aside></div></article>
|
||||
</section>
|
||||
|
||||
<footer class="controls">
|
||||
|
||||
Reference in New Issue
Block a user