为什么选这条路

做「雷达快传」的时候,需求很明确:iOS / Android 双端都要跑,部分页面还得在 WebView 里嵌入 Web 内容。Flutter 天然适合这个场景——一套 Dart 代码,iOS、Android、Web 三端共享逻辑层。

但 Web 混合开发不是把 flutter build web 跑一下就完事了。实际项目里会遇到一堆”文档没写但你会踩”的问题。

架构分层

1
2
3
4
5
6
7
8
9
10
┌─────────────────────────────────┐
│ Flutter UI 层 │
│ (Material / 自定义组件) │
├─────────────────────────────────┤
│ 共享业务逻辑层 (Dart) │
│ 网络请求 / 状态管理 / 路由 │
├──────────────┬──────────────────┤
│ Native 桥接 │ WebView 桥接 │
│ (MethodCh) │ (JS Bridge) │
└──────────────┴──────────────────┘

核心思路:一套业务逻辑 + 平台差异化 UI 适配,不做”一套代码原样跑三端”的白日梦。

踩过的坑

1. WebView 里的 JS 通信

Flutter Web 端用 webview_flutter 不现实——它依赖原生 WebView,Web 平台根本不存在这个概念。解决方案:

  • 移动端webview_flutter + MethodChannel 走原生桥接
  • Web 端:直接用 dart:htmlIFrameElement,通过 postMessage 通信
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// Web 端 JS 通信封装
import 'dart:html' as html;

class WebJsBridge {
final html.IFrameElement _iframe;

void postMessage(Map<String, dynamic> data) {
_iframe.contentWindow?.postMessage(data, '*');
}

void onMessage(void Function(Map<String, dynamic>) handler) {
html.window.onMessage.listen((event) {
handler(event.data);
});
}
}

关键点:Android/iOS 和 Web 的通信通道完全独立实现,但接口保持一致,上层业务层无感知。

2. Platform Channel 的条件编译

用了 dart.library.iodart.library.html 做平台判断:

1
2
3
import 'bridge_stub.dart'
if (dart.library.io) 'bridge_mobile.dart'
if (dart.library.html) 'bridge_web.dart';

编译时 Dart 会自动选择对应平台的实现,零运行时开销。

3. Web 端性能优化

Flutter Web 的 CanvasKit 渲染器很重,首屏加载慢。实际方案:

  • 开发阶段用 --web-renderer canvaskit(保证渲染一致性)
  • 生产部署切 --web-renderer auto(移动端自动降级 HTML 渲染器)
  • 图片全部走 CDN + WebP 格式
  • 路由懒加载,deferred as 延迟加载非首屏模块

4. 文件下载的兼容处理

移动端用 dio + 原生存储权限,Web 端得用浏览器的下载机制:

1
2
3
4
5
6
7
8
9
void downloadFile(String url, String filename) {
if (kIsWeb) {
final anchor = html.AnchorElement(href: url)
..setAttribute('download', filename)
..click();
} else {
// 走原生 dio 下载 + 文件权限处理
}
}

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 一套代码打天下的价值就出来了。

关键不是选什么技术,是搞清楚自己的产品形态。