Flutter Web 混合开发的真实体验
为什么选这条路
做「雷达快传」的时候,需求很明确:iOS / Android 双端都要跑,部分页面还得在 WebView 里嵌入 Web 内容。Flutter 天然适合这个场景——一套 Dart 代码,iOS、Android、Web 三端共享逻辑层。
但 Web 混合开发不是把 flutter build web 跑一下就完事了。实际项目里会遇到一堆”文档没写但你会踩”的问题。
架构分层
1 | ┌─────────────────────────────────┐ |
核心思路:一套业务逻辑 + 平台差异化 UI 适配,不做”一套代码原样跑三端”的白日梦。
踩过的坑
1. WebView 里的 JS 通信
Flutter Web 端用 webview_flutter 不现实——它依赖原生 WebView,Web 平台根本不存在这个概念。解决方案:
- 移动端:
webview_flutter+MethodChannel走原生桥接 - Web 端:直接用
dart:html的IFrameElement,通过postMessage通信
1 | // Web 端 JS 通信封装 |
关键点:Android/iOS 和 Web 的通信通道完全独立实现,但接口保持一致,上层业务层无感知。
2. Platform Channel 的条件编译
用了 dart.library.io 和 dart.library.html 做平台判断:
1 | import 'bridge_stub.dart' |
编译时 Dart 会自动选择对应平台的实现,零运行时开销。
3. Web 端性能优化
Flutter Web 的 CanvasKit 渲染器很重,首屏加载慢。实际方案:
- 开发阶段用
--web-renderer canvaskit(保证渲染一致性) - 生产部署切
--web-renderer auto(移动端自动降级 HTML 渲染器) - 图片全部走 CDN + WebP 格式
- 路由懒加载,
deferred as延迟加载非首屏模块
4. 文件下载的兼容处理
移动端用 dio + 原生存储权限,Web 端得用浏览器的下载机制:
1 | void downloadFile(String url, String filename) { |
5. 状态管理的选择
试过 BLoC、Provider、Riverpod,最终在项目里选了 Riverpod:
- 不需要
BuildContext就能访问状态 autoDispose自动管理生命周期,Web 端内存控制友好- 原生支持异步状态(
AsyncNotifier),减少模板代码
打包与部署
| 平台 | 命令 | 产物 |
|---|---|---|
| Android | flutter build apk --release |
APK / AAB |
| iOS | flutter build ipa --release |
IPA |
| Web | flutter build web --release |
build/web/ |
Web 产物部署到 OpenCloudOS 服务器上,Nginx 做反向代理 + Gzip 压缩。CDN 加速静态资源。
真实感受
好处:
- Dart 写起来比 JS 舒服,类型安全 + 空安全省了大量防御性代码
- 三端共享 80% 代码,维护成本砍半
- Flutter 的 UI 一致性确实强,iOS 和 Android 长得一模一样
痛点:
- Web 生态相关的库(支付、分享、推送)接口不统一,需要逐平台适配
- Web 端包体积偏大(CanvasKit ~2MB),首屏优化是个持续工程
- 调试 WebView 通信问题时要同时开 Chrome DevTools + Flutter DevTools,心智负担不小
总结
Flutter Web 混合开发适合「移动端为主、Web 为辅」的产品形态。如果你的产品重 Web 轻移动端,不如直接用 React / Vue。但如果你的主力战场在 App 上,Web 端只是做做管理后台或分享落地页——Flutter 一套代码打天下的价值就出来了。
关键不是选什么技术,是搞清楚自己的产品形态。

