Flutter入门:从零开始构建跨平台应用

高冷猫
2025-12-16 01:34
阅读 323

上周五晚上十点,我还在公司调一个诡异的 CSS 动画兼容性问题。运维大哥突然在群里@我:“前端同学,iOS 上面那个按钮点不动了!” 我一拍大腿——完了,又是 Safari 的 transform 事件冒泡 Bug!正想回一句“这不是我的锅”,产品经理幽幽地补了一句:“对了,下周三要上新功能,Android 和 iOS 都得同步上线。”

我当时真的想砸电脑。

作为一个纯前端出身、最近才被逼着学 Node.js 做全栈的新人(入职刚俩月,每天都在怀疑人生),我早就受够了这种“一套逻辑写三遍”的折磨:Web 一套、H5 一套、小程序再来一套……更别提还要和安卓组老哥、iOS 组大佬反复对齐 UI 细节。测试同学每次看到我都叹气:“你们前端能不能统一一下组件库?”

就在这时,隔壁组一个搞移动端的老哥神秘兮兮地凑过来:“要不要试试 Flutter?一次编码,多端跑,连 Windows 桌面都能打。”

我一开始是拒绝的——毕竟我连 Java 都没怎么碰过,更别说 Dart 了。但想到以后不用再被 Safari 和 Chrome 的 flex 差异逼疯,还是咬牙点了头。

为什么不是 React Native?也不是原生?

其实我们团队内部吵过好几次技术选型。React Native(RN)呼声最高,毕竟我们前端组全是 React 老兵。但问题也很明显:

  • 热更新受限:苹果审核越来越严,RN 的 JS Bundle 热更新容易被拒。
  • 性能瓶颈:复杂动画或列表滚动时,Bridge 通信开销大,掉帧严重。
  • Native 依赖多:一旦要用到原生模块(比如蓝牙、扫码),还得拉安卓/iOS 同事一起改,沟通成本爆炸。

而原生开发?算了吧。我们组总共三个前端,老板还指望我们顺手把后端 API 也写了(Springboot 项目正在疯狂迭代中)。让我一个人同时维护两套原生代码?怕不是想让我直接提离职。

于是 Flutter 成了折中之选。它的核心优势在于:

  • 自绘引擎:Skia 直接渲染,不依赖系统 WebView 或原生控件,UI 一致性极高。
  • Dart 语言:虽然冷门,但语法接近 JS + TS,上手快;AOT 编译性能接近原生。
  • 热重载(Hot Reload):改完代码秒级刷新,比 RN 的 Live Reload 快得多,开发体验直接起飞。

为了说服技术总监,我还偷偷做了个对比表格(别告诉他是我写的):

特性 Flutter React Native 原生 (iOS/Android)
跨平台一致性 ⭐⭐⭐⭐⭐ ⭐⭐☆
开发效率 ⭐⭐⭐⭐ ⭐⭐⭐⭐ ⭐⭐
性能(动画/列表) ⭐⭐⭐⭐ ⭐⭐ ⭐⭐⭐⭐⭐
社区生态 ⭐⭐⭐ ⭐⭐⭐⭐ ⭐⭐⭐⭐⭐
学习曲线 ⭐⭐(需学 Dart) ⭐(JS/TS 友好) ⭐⭐⭐⭐(双平台)
热更新能力 ⭐(受限) ⭐⭐(风险高) ⭐(基本无)

总监看完只说了一句:“行,你先做个 Demo,下周一晨会演示。”

从零搭建:踩坑实录

第一步:环境配置 —— 别信官方文档!

Flutter 官方文档写得像天书,尤其是 Windows 用户。我按照指南装完 Android Studio,结果 flutter doctor 报了一堆红叉:

[!] Android toolchain - develop for Android devices
    ✗ Unable to locate Android SDK.

折腾半天才发现,新版 Android Studio 默认不装 SDK Platform Tools。得手动去 SDK Manager 里勾选。还有 PATH 环境变量……我差点把 flutter_console.bat 当成救命稻草。

iOS 更惨。Xcode 升级到 15 后,模拟器一直卡在 “Installing”。最后发现是 Flutter 版本太旧,不支持 Xcode 15。升级 Flutter 后又遇到 CocoaPods 兼容问题……那晚我梦里都是 pod install failed

血泪建议:用 Mac 开发 iOS 应用,别挣扎了。Windows 跑 Android 还行,但 iOS 必须 Mac。我们公司给配了 MacBook Pro,但第一天就被我装崩了 Homebrew……

第二步:写个 Hello World —— Dart 是什么鬼?

新建项目:

flutter create my_first_app
cd my_first_app
flutter run

跑起来是个计数器页面。我盯着代码看了十分钟:

class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;

  void _incrementCounter() {
    setState(() {
      _counter++;
    });
  }
}

这不就是 React 的 useState + setState 吗?!但变量前面那个 _ 下划线是什么意思?查了才知道:Dart 里以下划线开头的成员是私有的(private)。前端人表示:又学到了奇怪的知识。

不过 Dart 的语法糖真香:

  • ?? 空值合并(类似 JS 的 || 但更安全)
  • ... 展开操作符(List/Map 都支持)
  • async/await 原生支持(再也不用写 .then().catch() 了)

第三步:集成现有 Springboot 后端

我们公司的后端全是 Springboot 写的 RESTful API。Flutter 里请求数据很简单:

import 'package:http/http.dart' as http;

Future<User> fetchUser() async {
  final response = await http.get(
    Uri.parse('https://api.mycompany.com/user/123'),
    headers: {'Authorization': 'Bearer $token'},
  );

  if (response.statusCode == 200) {
    return User.fromJson(jsonDecode(response.body));
  } else {
    throw Exception('Failed to load user');
  }
}

但坑来了:CORS!本地调试时,Flutter Web 直接报跨域错误。而移动端(Android/iOS)因为不是浏览器环境,反而没事。我一度以为自己疯了——同一个代码,Web 报错,手机正常?

后来才明白:Flutter Web 本质是编译成 JS 跑在浏览器里,所以受同源策略限制;而移动端是原生 App,网络请求走的是系统底层,不受 CORS 影响。

解决方案?让后端同事在 Springboot 里加个全局 CORS 配置:

@Configuration
public class CorsConfig {
    @Bean
    public CorsConfigurationSource corsConfigurationSource() {
        CorsConfiguration config = new CorsConfiguration();
        config.setAllowedOrigins(Arrays.asList("http://localhost:5000")); // Flutter Web 默认端口
        config.addAllowedHeader("*");
        config.addAllowedMethod("*");
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", config);
        return source;
    }
}

后端大哥一边改一边吐槽:“你们前端又整新活?上次是 Vite,这次是 Flutter?” 我只能赔笑:“哥,这是为了减少你们联调时间啊!”

多端适配:真的“一次编写”吗?

理想很丰满,现实很骨感。虽然 Flutter 宣称“一套代码多端运行”,但细节差异还是不少。

平台特有行为

比如导航栏返回手势:

  • iOS 支持右滑返回
  • Android 是物理返回键

Flutter 通过 ThemeData.platform 自动适配,但如果你自定义了 AppBar,就得手动处理:

AppBar(
  leading: Platform.isIOS
      ? IconButton(icon: Icon(Icons.arrow_back_ios), onPressed: () {})
      : null, // Android 通常不需要返回按钮
)

UI 适配

不同屏幕尺寸怎么办?别慌,Flutter 有神器:

  • MediaQuery.of(context).size.width 获取屏幕宽高
  • LayoutBuilder 根据父容器尺寸动态调整
  • FractionallySizedBox 按比例布局

但最实用的还是 响应式断点,类似 CSS Media Query:

double getScreenWidth(BuildContext context) {
  final width = MediaQuery.of(context).size.width;
  if (width > 600) return 600; // 平板最大宽度
  return width;
}

性能优化:别让 60fps 变幻灯片

Flutter 官方吹嘘 60fps,但写不好照样卡成 PPT。我第一次做长列表时,直接 ListView.builderColumn,结果滑动时掉帧到 20fps。

后来学到几个关键技巧:

  1. 避免在 build 方法里做计算:把 JSON 解析、字符串拼接移到 initState。
  2. 用 const 构造函数:不变的 Widget 加 const,减少重建。
  3. 图片懒加载 & 缓存:用 cached_network_image 包。
  4. 分离状态:Provider 或 Riverpod 管理状态,避免整个页面 rebuild。

最骚的是,Flutter DevTools 里居然能看 Widget 重建次数!绿色是正常,红色就是过度重建。我盯着那个火焰图调了两天,终于把首页帧率稳在了 58+。

发布上线:应用市场的修罗场

开发完只是开始,发布才是噩梦。

Android 发布

流程还算熟悉:

  1. 生成签名 keystore(千万别丢!)
  2. flutter build appbundle
  3. 上传到 Google Play Console

但 Google Play 要求 Target SDK Version ≥ 33,而 Flutter 默认是 31。得手动改 android/app/build.gradle

android {
    compileSdkVersion 34
    defaultConfig {
        targetSdkVersion 34
    }
}

iOS 发布

这才是真正的地狱模式。

  • Xcode Archive 时证书错误(换了三台 Mac 才搞定)
  • App Store Connect 审核被拒三次,理由是“应用缺少核心功能”(其实就是登录页太简单)
  • 最后发现是 Info.plist 里少了隐私描述:
<key>NSCameraUsageDescription</key>
<string>需要访问相机以扫描二维码</string>

经验之谈:iOS 审核前务必用 TestFlight 内部测试!别直接提交正式版。

面试题挑战:面试官问我 Flutter 和 Springboot 怎么配合?

上周部门搞了个“技术分享会”,其实是变相面试题挑战。Leader 突然问我:“如果让你用 Flutter + Springboot 做一个电商 App,怎么设计架构?”

我脑子一热,脱口而出:

  • Flutter 前端负责 UI 和状态管理(Riverpod + AsyncNotifier)
  • Springboot 提供 REST API,用 JWT 做鉴权
  • 数据库 MySQL + Redis 缓存商品信息
  • 文件上传走 MinIO,不占服务器带宽

结果 Leader 摇头:“太浅了。考虑过 WebSocket 实时通知吗?订单状态变更怎么推送到前端?”

我当场石化。后来恶补了 Springboot 的 STOMP over WebSocket,才勉强答上来。

但这也让我意识到:全栈不是前端+后端技能的简单叠加,而是系统思维的升级。以前我只关心“这个按钮怎么实现”,现在得想“用户点击后,数据流经哪些服务,如何保证最终一致性”。

结语:真香!

现在,我们的 Flutter 应用已经上线两周,崩溃率低于 0.1%,用户反馈 UI 流畅度比原生还好(可能是原生组代码太烂?)。最爽的是,产品经理再也不敢说“iOS 和 Android 效果不一样”了。

虽然 Dart 还是有点怪,Hot Reload 偶尔抽风,iOS 审核依然玄学……但比起之前 Web + H5 + 小程序三线作战,现在的幸福感爆棚。

如果你也是前端出身,正在被多端需求折磨;或者像我一样,被逼着转型全栈,不妨试试 Flutter。它可能不是银弹,但至少能让你少熬几个通宵。

对了,昨天 HR 问我:“最近在学啥?”
我说:“Flutter。”
她眼睛一亮:“哦~是不是准备跳槽了?”

我笑了笑,没说话。毕竟,会 Flutter 的前端,在面试市场上可是香饽饽。至于 Springboot?那是我深夜加班时的背景音乐罢了。


P.S. 刚写完这篇博客,运维又在群里@我:“Flutter 应用线上白屏了!”
我深吸一口气,打开了 DevTools……

评论 0

最热最新
暂无评论
匿名用户Lv.1
0
影响力
0
文章
0
粉丝