Web 团队做 App,我见过太多一拍脑袋就选型的例子。产品经理拿竞品原型说“下周上架”,老板说“别人家H5一套代码两头走,为什么我们不行”,技术群里吵 React Native 还是 Flutter,吵到第三天发现团队里没人写过一行 Swift,也没人碰过 Kotlin。这个时候 Capacitor 被提上桌面,往往是被当成“Web 套壳”的Plan B。但我得说句实在话——Capacitor 不是备胎,它是把 Web 团队的存量能力正经搬到原生生态的一套完整工程方案。
这篇文章不站队,不吹不黑。我会把我自己接触过的几次选型过程、集成实践、线上踩坑全部摊开来讲,从运行时原理到团队能力评估,从 Cordova 迁移账本到六个现实的判断维度,一次性说清楚:Web 团队做 App,到底该不该选 Capacitor。
1. Capacitor 到底解决了什么问题——先别急着站队
很多人第一次见 Capacitor,是刷到 Ionic 的宣传语“用 Web 技术构建原生应用”。第一反应就是:这不就是个套壳框架吗?和 WebView 包一层有什么差别?这么想,方向对了,但只对了一半。
1.1 什么场景下这个方案会被摆上桌
Capacitor 出现的典型场景,是团队已经有一套跑得不错的 Web 项目——可能是管理后台、可能是 H5 商城、可能是面向用户的业务系统——然后突然收到一个 App 需求。注意,这里的关键词是“已经有一套”。Web 团队不是从零做 App,而是要把已有的域名、代码、业务逻辑、设计规范、接口文档这些东西,低成本地延伸到移动端去。
这个前提下,你说让团队用 React Native 从零重写一遍,等于告诉他:之前的业务代码全部作废,埋点体系重来,路由重来,状态管理重来,UI 适配重来。成本不是翻倍,是推倒重来。Capacitor 的定位恰好是反着来的:它的目标不是让你换一套技术栈,而是让你现有的 Web 代码直接跑进一个原生壳里,再用 JS Bridge 去调相机、定位、推送这些 Web 碰不到的设备能力。
我接触过的几个选型场景,基本都对得上这几个特征:
- 业务以内容展示、表单提交、数据列表、流程审批为主;
- 团队里前端/全栈是主力,原生开发最多只会"改个配置";
- 对 App 的诉求是先上架、跑通、能用,再谈体验优化;
- 有一定存量 Web 资产,不愿也不可能从头再来。
如果你符合这几条,Capacitor 才有资格进入讨论。如果产品是强交互、强动画、重 3D 或视频编辑,那它大概率撑不住,这不是黑它,是它的边界。
1.2 Capacitor 和它的前辈们相比,本质差异在哪
要给 Capacitor 定位,得先看它的前身。它出自 Ionic 团队,而 Ionic 最初是建立在 Cordova 之上的 UI 框架,后来 Ionic 团队想甩开 Cordova 的一些历史包袱,干脆自己做了个容器,这就是 2019 年开源的 Capacitor。
Cordova 和 Capacitor 放在一起,表面看都是“原生壳 + WebView + Bridge”,但工程化方式和插件体系差得非常远。
Cordova 最大的问题,是它对现代前端工程的支持太吃力。你项目里有 Vite、Webpack、ES Module、HMR,Cordova 不关心这些,它只管把你的 www 目录整体拷进工程里。开发调试的路径绕来绕去,真机同步靠插件,错误信息靠 alert。用惯了现代工具链的前端,一碰 Cordova 就想骂人。
Capacitor 从设计上就解决了这件事。它支持本地开发服务器(npx cap serve起一个开发入口),代码改动可以热更新到真机,断点调试直接用 Chrome DevTools 的 Remote Debugging 或 Safari Web Inspector。对 Web 团队来说,这套调试链路几乎是零学习成本——你在浏览器里怎么调,在真机里还是怎么调。
另一个本质差异是原生工程的管理方式。Cordova 时代,“原生工程”是个黑盒,插件用 plugin.xml 描述,原生代码藏在 platforms 目录里,你没法也没有好办法去改原生代码。Capacitor 不一样,它要求你npx cap add ios或npx cap add android生成一份真正意义上的原生工程,这份工程是"你的",不是框架的临时产物。你需要改原生代码,直接打开 Xcode 或 Android Studio 改就行。这意味着什么?意味着团队里哪怕只有一个人会写点原生代码,这个工程就可以无限深度定制——从启动页到路由手势,从原生网络库到混合推送,都有得玩。
1.3 它不是另一个跨端框架
这是我最想掰正的一点。React Native 和 Flutter 干的事,是把 UI 渲染层从 Web 拉出来,用自己的引擎或原生组件去渲染——React Native 用 JS 跑逻辑、原生组件画界面,Flutter 直接连 Skia 引擎都给你画出来。它们解决的是"性能和交互体验"问题。
Capacitor 不解决这个问题。它的渲染层就是 WebView,UI 由 HTML/CSS 画出来,业务逻辑由浏览器里的 JavaScript 跑。它解决的是"Web 代码怎么合法、体面、可维护地进入原生生态"这个问题。
所以拿 Capacitor 和 RN/Flutter 比性能,就像拿轿车和卡车比拉货——不是一个物种,做的事情也不一样。Capacitor 的目标从来不是"打得过原生",而是"让 Web 团队的技术存量价值最大化。你写的组件、封装的请求库、沉淀的 UI 规范,到 Capacitor 里还能继续用,这才是它真正的卖点。
2. WebView 性能误区与 Capacitor 的真实运行时
关于 Capacitor,十个讨论里八个会直接拿"WebView 卡"说事。这话搁五年前,我勉强认。但现在还把 WebView 当洪水猛兽,多少有点刻舟求剑。
2.1 现代移动 WebView 的底子和十年前完全两码事
iOS 从 8.0 开始用 WKWebView 换掉了 UIWebView,Android 从 5.0 开始系统 WebView 组件独立升级(WebView 本身的版本可以跟着 Chrome 走)。到了今天,主流设备上的 WKWebView 底层是 WebKit 的 JIT 编译器,JavaScriptCore 会做即时编译;Android 这边大部分厂家的 WebView 底层就是 Chromium,V8 引擎的 JIT 编译加持,性能比老 IE 时代高一个数量级。
我见过一个实际案例:某团队用 Capacitor 包了一个业务审批 App,里面大量的长列表、表单、富文本编辑器,核心页面交互复杂度直逼 PC 端后台。在 iPhone 11 和两三年前的 Android 中端机上,滚动和输入响应基本能保持在可接受的范围——不跟手的情况不是没有,但没那么夸张,日常使用的人根本分辨不出这到底是"原生"还是"Web"。你用户的感知,远没有你自己对着 Console 面板盯着 Performance 火焰图时那么敏感。
2.2 Bridge 调用成本的量化认知
Capacitor 真正需要关心的性能瓶颈,不在渲染,在 Bridge。
Bridge 是 Web 侧 JavaScript 和原生侧代码通信的通道。Capacitor 的 Bridge 用了一种双向异步消息机制——Web 侧通过Capacitor.plugins.XXX.method()发起调用,原生侧监听处理完毕后再回调。这个过程的单次开销很微妙,但绝对不止是"加个函数调用"这么简单。
我拿真机做过粗略统计:连续调用一个什么都不做的自定义插件方法 1000 次,Wi-Fi 下平均单次耗时大概在零点几毫秒到几毫秒之间,性能差一点的 Android 设备上可能会更高。看上去不高?但如果你在业务里写出这种代码:
- 滚动容器里
scroll事件高频回调的时候,每次回调都调一次 Bridge; - 图片懒加载时对每一张图走 Bridge 查询本地缓存;
- 打包一个大的数据对象(比如把整个表单数据 JSON.stringify 之后传给原生层持久化)。
这类用法叠加起来,开销会从"单项不疼"变成"合集头疼"。Capacitor 官方文档在插件开发部分也一直在强调:尽量减少 Bridge 调用次数,尽量批量传输数据。实用的做法是:高频的 Bridge 能力尽量原生侧缓存结果,Web 侧查询后本地记忆;大对象传递走文件或者原生侧直接存取,别走 Bridge 参数。
2.3 内存、启动耗时、首屏加载的真实现状
WebView 的内存占用确实比原生 View 高,这是架构决定的。一个复杂的 H5 页面,JS 堆、DOM 树、CSS 样式层叠渲染,几百 MB 内存很正常。所以 Capacitor 项目里更要注意别做"单页面越滚越长"的设计——页面数据太多时,该分页分页,该虚拟列表虚拟列表,这是 Web 团队本来就该有的基本功。
首屏加载是另一个关键。Capacitor 外壳自身启动很快,原生壳起来之后只有一个加载动作——把 Web 资源读进 WebView。如果资源打包在 App 内部(npx cap copy之后资源在原生工程里),首屏速度一般能做到几秒内完全可交互。如果远程加载(Capacitor 支持 config 里配置server.url),首屏延迟就完全取决于网络状况。这里我强烈建议:正式上架版本,资源必须打进去,远程 URL 只用来做灰度测试或内部演示。否则一旦网络抖动,用户打开 App 就是白屏,这种体验比"套壳感"致命多了。
3. 从 Cordova 迁移到 Capacitor 的生态账本
我身边不少团队早期用的是 Cordova,现在陆续被卡在多方面的历史包袱上。Capacitor 对这类团队来说,不是换血,是"带瘤生存"式的渐进改造。
3.1 插件生态的继承与差异——Cordova 插件的兼容性真实情况
Capacitor 发布时,最大的质疑就是:Cordova 积累了几十年的插件生态,难道全部丢掉?答案是可以部分继承。
Capacitor 内部有一个兼容层,它提供了@capacitor-community/cordova-plugin-name这类包,包装了 Cordova 插件的调用方式。也就是说,很多 Cordova 插件可以直接以 npm 包的形式装进 Capacitor 项目里,Web 侧通过window.cordova.plugins.xxx调用,整个迁移工作量小到可以忽略。
但要注意,"可以跑"和"跑得好"是两码事。Cordova 插件在 Capacitor 下偶尔会出现调用时机、参数格式不完全对齐的情况。更麻烦的是,老版本 Cordova 插件往往自带过时的原生依赖,和 Capacitor 生成的现代原生工程版本冲突。我在一个项目中就遇到过:某个老推送插件内置的 Android SDK 版本和 Capacitor 的 Gradle 版本冲突,一编译就报错,最后只能换新插件。
对于新项目,我的建议永远是:优先使用 Capacitor 官方插件(@capacitor/camera、@capacitor/push-notifications、@capacitor/geolocation这些),它们经过了完整测试,API 也完全是 Promise 风格,配合现代 TS 类型使用体验极佳。Cordova 插件是"迁移保底方案",不是"首选方案"。
3.2 原生代码能力:Capacitor 的现代工程化优势
Cordova 年代,你想写一个自定义原生功能,得上网查 plugin.xml 怎么声明,Java 文件要放在哪个目录,然后在项目里反复用cordova plugin add和cordova prepare,原生改动完全和前端工程隔离。整个体验像把"原生代码"密封在罐头里,看不见也碰不着。
Capacitor 不是这样。npx cap add ios之后,iOS 工程就是一个App.xcworkspace,平时就放仓库里和前端代码一起管理。你可以用 Xcode 直接改 AppDelegate.swift,可以加 Pods 依赖,可以跑 Instruments 测内存,所有原生开发者习以为常的工具链,Capacitor 全都不挡。Android 那边更是如此:android/目录是一个标准 Gradle 工程,你可以加 AndroidManifest 权限、写 Service、接第三方 SDK,没有任何封装障碍。
对 Web 团队来说,这个"工程开放性"意味着什么?意味着你招人能招到"会一点原生但主职是前端"的人,也意味着原生侧有紧急问题可以直接请外援,而不是连工程都打不开。Capacitor 降低了"碰原生"的心理门槛——你不会 Swift 也行,打开 iOS 工程改个 Info.plist 权限描述总能学会吧。
3.3 项目工程目录的变化:从“Web 为主”到“双端原生工程”
第一次跑npx cap add ios && npx cap add android时,很多 Web 同事会愣一下:项目里突然多了ios/和android/两个大目录,这些是什么?这其实是思维模式的变化——你的项目不再是"纯 Web 项目",而是"一个 Web 代码仓库 + 两个原生工程外壳"。
这个变化有几个实际影响:
.gitignore要调整,原生工程里的Pods/、build/目录、.gradle/缓存要排除掉;- 提交策略要调整,原生工程内部的版本号、签名证书配置属于原生团队的职责;
- CI/CD 流程要调整——以前 Web 项目只需 build 后部署到服务器,现在要跑
npx cap sync同步原生依赖、npx cap copy拷贝资源,再走 xcodebuild / Gradle 打包; - 发布流程要调整——Web 项目改一行代码重新部署就行,Capacitor 改一行代码要重新构建原生包,或者走你配置好的热更新路径(这个后面有坑,后面细讲)。
这些变化说大不大,但每一件都需要团队在流程层面接受和适应。我见过不少团队在选型调研阶段被"双端工程"吓退,实际真正跑起来后发现其实工作量可控——毕竟绝大部分时候你只需要操作 Web 侧代码,原生工程是"偶尔进去改一下配置"的存在。
4. 实战中 Web 团队最容易踩的四个坑
这部分才是今天我想认真展开的重头戏。Capacitor 官方文档写得不算难看,但很多问题不踩一次根本没经验。我把几个高频坑和它们的完整排查链路写出来,建议收藏。
4.1 路由和原生返回手势的冲突:iOS 右滑返回令人崩溃
现象:用 Capacitor 打包之后,iOS 上从左边缘右滑,页面动不动无响应,或者滑一下直接白屏,甚至整个 WebView 状态错乱,再侧滑又恢复正常。
根因排查链路:这个问题通常不是 WebView 本身坏了,而是 WebView 的"原生返回手势"和 SPA 内部的 history 栈冲突了。Capacitor 在 iOS 上默认启用了 WKWebView 自带的allowsBackForwardNavigationGestures特性,手势触发时 WKWebView 在自己的"网页浏览历史栈"里做返回,而你的 Vue/React 路由用的是自己的 history API,两者各自记一套栈,一冲突就出现跳转不一致或者白屏。
解决办法(从优到劣排序):
- 如果业务不需要"手势返回 Web 页面前进后退",直接在原生工程里关掉这个特性。Capacitor 的
capacitor.config.json里可以配置ios.allowsBackForwardNavigationGestures为false(老版本字段名可能不同,记得查你对应版本的 schema),关掉后原生手势不再干扰前端的路由。 - 如果想要手势返回且业务路由能配合,就需要在前端做同步:监听 Capacitor 的
backButton事件,在执行原生返回之前先让前端路由 pop 一层,或者把前端 history 栈同步到 WKWebView 的历史表里——后者实现成本高,不推荐小团队搞。
Android 侧同理:系统返回键默认会触发 Capacitor 的backButton事件。如果你不监听,默认行为是"退出 App"(视版本而定),很多 Web 团队第一版上来就发现按返回键直接 App 消失了。处理方式是在前端注册一个全局监听,根据当前路由栈决定要不要阻止默认行为:
import { App as CapacitorApp } from '@capacitor/app'; CapacitorApp.addListener('backButton', ({ canGoBack }) => { if (canGoBack) { // 让前端路由返回一页 window.history.back(); } else { // 这里是最后一页,可提示退出或退出到后台 CapacitorApp.minimizeApp(); } });注意:这个监听逻辑必须在路由 ready 之后再注册,否则路由还没有历史栈,canGoBack 永远为 false。这个坑我用版本号"血泪验证"过。
4.2 键盘弹起遮挡输入框:iOS 的 keyboard 行为不像浏览器
现象:在 iOS 真机上,聚焦输入框时系统键盘弹起来,页面底部被遮住,输入框正好被键盘压住,完全看不见你敲了什么字。Android 上部分机型也会出现。
根因排查链路:iOS 的 WKWebView 对键盘弹起的处理,和你在 Safari 里打开页面不一样。Safari 会主动滚动可视区域让输入框露出来,但 WKWebView 很多情况下不会,页面停留在原位,键盘就这么盖在上面。
解决方向:
第一,Capacitor 官方有@capacitor/keyboard插件,打开它的resize模式:当键盘弹起时,WebView 高度会随键盘上移缩小,整个 WebView 会跟着被压缩,这样页面底部就能在可视区域内,配合 CSS 的height: 100%或100dvh能恢复正常。
第二,如果你不想让 WebView 压缩,想保持页面全尺寸再自行滚动,可以用Keyboard.addListener('keyboardWillShow', ...)自己监听键盘高度,然后手动把当前聚焦的元素scrollIntoView()。实测下来,配合 CSS 的scroll-behavior: smooth体验很自然。
第三,如果页面里有 Fixed 定位的头部底部栏,键盘弹起时这些元素的位置也会乱。这个坑在 iOS 上尤其费解——Fixed 元素在软键盘模式下经常把自己定位到键盘上方去,视觉上等于"底栏被顶起来了"。解决方案是键盘监听时动态切换 fixed 元素的 class,或者干脆用position: sticky替代。
4.3 热更新和审核的边界:别把 App 当 H5 服务器乱发补丁
现象:团队习惯 Web 的发布节奏,上线后在 Capacitor 里配了一个远程资源 URL,想着以后每次发版都走这里,改一行代码发个新页面就完事,不用走商店审核。
结果:提交审核被 Apple 拒了。理由基本是"App 中存在远程加载代码行为,绕过审核"。
根因排查链路:Capacitor 支持通过server.url配置远程加载 Web 资源,这是给开发调试和灰度场景用的,不是给生产环境"把 App 当浏览器壳"用的。Apple 的审核条款明确禁止 App 下载可执行代码并执行,JS/CSS 属于可执行代码范畴——你的代码放在远程服务器,App 每次启动都从远程拉最新页面,这在审核人员眼里就是"动态下发代码绕过审核"。
实际中怎么处理才合规?
- 正式上架版本,资源必须打包进 App 本地(
npx cap copy),不要配置server.url。 - 如果确实想做"不发版更新页面"的诉求,业界常见做法是使用"CAPACITOR_UPDATER"类方案(如
@capgo/capacitor-updater),它会从你自己的更新服务拉取更新包,且只在客户端本地比对版本后从服务端下载新资源。还是要注意:这类方案在 Apple 审核时依旧有风险,需要严格限制更新内容——只更新静态资源和 JS 逻辑,不做引导用户跳转、不做敏感权限变更,否则审核照样找麻烦。 - 真要走更新通道,我的实操建议是:把"热更新"做成"整包更新引导"。也就是新版 Web 资源发布后,App 检测到有新版,弹窗引导用户去应用商店下载最新原生包,而不是自己偷偷换资源。
很多人骂 Apple 审核不透明,但站在它们角度看:App 里藏了一个能动态下发任意代码的通道,这本身就是安全漏洞。凡是热门 App 爆出过"资源被劫持、页面被篡改、数据被偷"的安全事故,十有八九都是远程加载资源这个口子惹的祸。
4.4 权限申请:HTML5 摄像头 API 在 WebView 里不工作
现象:Web 端用navigator.mediaDevices.getUserMedia写好了扫码、拍照功能,在浏览器里调得好好的,打进 Capacitor 后才发现相机根本打不开,或者一打开就黑屏,控制台里报权限错误。
根因:WebView 不是浏览器。浏览器会弹出权限询问框,你可以"允许/拒绝";WebView 里没有这套 UI,暴力的getUserMedia调用会被 WebView 以默认行为拒绝。更关键的是,iOS 的 WKWebView 默认并不支持navigator.mediaDevices这种 H5 摄像头 API,你得到的是 undefined,或者会被要求原生侧先开启对应权限。
正确姿势:在 Capacitor 项目里,摄像头/相册/扫码必须先走原生侧插件。典型流程:
npm install @capacitor/camera @capacitor/filesystem npx cap sync然后在前端调用:
import { Camera, CameraResultType } from '@capacitor/camera'; const photo = await Camera.getPhoto({ resultType: CameraResultType.Uri, source: CameraSource.Camera, });插件会自动处理原生权限申请,并把拍摄结果返回给前端。如果你做的是扫码,建议用@capacitor-mlkit/barcode-scanning或原生第三方 SDK,这类走的是原生摄像头预览 + 原生图像识别,性能和 Web 端扫码库不是一个量级。
与此同时,iOS 原生工程的Info.plist必须配置权限用途说明:
NSCameraUsageDescription(相机权限描述)NSPhotoLibraryUsageDescription(相册权限描述)- 定位、通讯录、蓝牙等各自有对应字段。
不配置,调用权限接口时 App 直接闪退或崩溃,且没有任何 JavaScript 报错。这个字段缺失的排查过程特别容易卡:看到的是前端调用成功但原生崩溃,反复断点找半天才发现是 plist 少了文案。这也是我从 Cordova 时代就养成的习惯——新建工程第一件事,把所有可能用到的权限描述统统一股脑写进 plist 和 AndroidManifest。
5. 该不该选 Capacitor:六个判断维度
最后给一个相对可操作的决策框架。你不需要全部打钩,但每一个维度都值得认真过一遍,别拍脑袋。
5.1 团队技能栈
纯 Web 团队(React/Vue + Node/Java 后端),没有专职原生开发者——Capacitor 明显合适。你们缺的就是"把 Web 能力延伸进原生生态"的管道,Capacitor 刚好是管道。但注意:团队里最好至少有一人愿意钻研一点原生代码,否则遇到工程层面的编译问题(Xcode 升级、Pod 冲突、Gradle 版本)会很痛苦。
如果团队本身就是原生出身,或者已经有 React Native / Flutter 的经验——那 CapCapacitor 就没那么有吸引力,直接用更原生的方案更符合现有能力结构。
5.2 产品形态
内容型(资讯、电商、社区)、工具型(企业管理、办公审批、表单录入)、轻交互型(教程、展示、预约)——Capacitor 是性价比之王。
重交互型(IM 消息并发大量收发、音视频实时通话、白板协作频繁绘制)、重动画型(炫酷引导页、复杂转场、游戏)——请优先考虑原生或 RN/Flutter。这类产品的体验底线,WebView 很难兜住。
5.3 对原生功能的依赖度
App 需要的原生能力越"标准",Capacitor 越省事。相机、定位、推送、分享、扫码、支付,这些官方插件和社区插件都非常成熟,集成成本低。
如果业务用到的是"非标"的原生能力——比如对接企业内部硬件、蓝牙打印机、门禁系统、USB 调试、定制协议通信——你确实需要写自定义原生插件。Capacitor 支持写自定义插件(iOS 上是 Swift,Android 上是 Kotlin),但这部分工作量的本质是原生开发,Web 团队要提前做好心理准备。
5.4 性能和体验底线
先把底线划出来:如果你的老板或者客户对 App 的体验要求是"和微信聊天一样顺滑""和抖音一样流畅",那 Capacitor 满足不了,这不是优化能救回来的,架构决定了天花板。如果体验底线是"打开能看、操作不卡、提交不出错",CapCapacitor 完全能接得住。
我的经验是:给 Capacitor 项目做一期真机性能摸底,挑 20 个核心页面,逐个在低端 Android 和两三年前的 iPhone 上跑一遍,记录启动耗时、页面加载、滚动帧率、内存占用。数据摆在桌上,该选谁,比开会吵三天管用。
5.5 发布和更新节奏
如果产品处于快速迭代期,一周发布几次版本,Web 团队已经习惯了"改完即生效"——Capacitor 会拦住你,因为你每一次发版都要走应用商店审核。这时候你要么接受"发版节奏放缓",要么上远程更新方案(前面说过合规风险,自行斟酌)。
如果产品迭代速度平稳,按月发版,Capacitor 完全没问题。我见过不少企业内部工具、小语种市场应用,两三个月发一次版,稳定性很好,团队不焦虑。
产品一旦上线,用户在使用中反馈 Bug,你要在一两天内出修复版本?Capacitor 会给你带来额外的压迫感。这个时候配置 "热更新通道" 会很诱人,但记得这个选择的代价是审核风险和技术复杂度同步上升。
5.6 长期维护成本
Capacitor 项目长期维护的形态,实际上是一套 Web 代码 + 两个原生壳工程同步管理。每年前端依赖要升级,Capacitor 主版本要跟进(Capacitor 3 到 4 到 5 到 6 的迁移文档我都翻过,每次迁移都需要一定工时),iOS/Android 系统版本升级后 WebView 行为可能变化。
这个维护成本,比纯 Web 高,但比"一个原生 team + 一个 Web team 维护两套代码"低得多。所以它更适合小团队——两三个前端 + 半个原生顾问,就能长期支撑一个业务 App。
我也做个小提醒:长期维护时,Web 代码千万别因"能跑"就放任不管。Capacitor 应用里的 Web 代码长期不重构,等到 WebView 版本升级,或者业务逻辑膨胀到一定程度,那时候的锅就不是 Capacitor 的,而是当年没有维护 Web 代码的运营意识。
写在最后:一个不那么时髦但真实的建议
我本人不迷信工具,也见过太多团队拿着一个热门框架当锤子,看什么都是钉子。Capacitor 的优势和边界都摆在这里——它不解决性能焦虑,不解决原生交互深度,但它真真切切解决了"Web 团队的技术资产如何延续到 App 生态"这个实际问题。
如果你问我个人建议:纯 Web 团队、内容型或工具型产品、发布节奏尚可、不追求极致性能,Capacitor 是可以无脑选的那个答案。它在现代工程化、调试体验、原生可扩展性上,比老方案舒服太多,甚至比很多 RN 项目更容易维持代码健康度——因为你前后端都在跑 JavaScript,心智负担降了很多。
如果你恰好有一个"两周做 POC"的机会,我建议你花一周时间把核心 Web 页面装进 Capacitor 跑一遍真机,再花三天测测 Bridge 插件、权限、路由手势,然后在第二天把键盘遮挡和资源打包的全流程跑通。两周之后,你会得到比任何技术选型文章都准确一百倍的答案。而我的这篇,不过是提前帮你把地图轮廓画出来了。