Flutter入门:从零开始构建跨平台应用
上周五晚上11点,我还在公司对着一堆Docker日志抓狂——没错,就是那个双11压测后线上突然502的锅。作为网易成都这边一个干了三年服务端的老油条,日常写Springboot接口、调优Redis缓存、和运维“友好”对线已经成了生活的一部分。但最近被拉进一个新项目组,领导丢给我一句:“你们服务端也得懂点前端,这次我们试试用Flutter搞个内部工具App。”
我?写UI?不是,我连CSS都写不利索啊!不过转念一想,反正最近在学Rust(成都这节奏太舒服了,下班还能卷点新东西),顺手搞搞Flutter也行,说不定哪天跳槽能吹“全栈”(狗头保命)。
为啥是Flutter?
其实一开始PM(产品经理)嚷嚷着要上React Native,说社区大、生态好。但我们组后端全是Java系的,Springboot写了三年,对JS那一套真有点PTSD。而且之前有个兄弟用RN写了个活动页,结果iOS审核被拒三次,理由是“动态下发代码”,直接把人整emo了。
Flutter不一样——Dart语言虽然小众,但语法对Java/C++出身的人极其友好,而且编译成原生ARM代码,性能稳如老狗。更重要的是,一套代码跑iOS/Android/Web甚至桌面端,对于我们这种人手紧张、又要快速交付的内部工具项目,简直是救命稻草。
吐槽一句:我们测试同学听说不用同时测两套UI,当场请我喝了杯霸王茶姬。感动!
环境搭建:别被VSCode插件劝退
我平时写代码全靠VSCode + 一堆插件续命。Flutter官方推荐用Android Studio,但我试了下,启动慢得像加载《逆水寒》的登录界面。果断切回VSCode,装上这几个插件:
- Flutter
- Dart
- Pubspec Assist(自动生成依赖引用,懒人必备)
- Error Lens(报错直接标红,比看终端快十倍)
然后终端里跑:
flutter doctor
第一次跑大概率一堆❌,尤其是iOS开发者证书那块。别慌,按提示一步步来就行。我在Mac上折腾了半小时Xcode命令行工具,Windows同事更惨,直接重装了两次Git for Windows(记得选“Use Git from Windows Command Prompt”)。
小贴士:如果你也在成都,建议找个周末去太古里星巴克边喝咖啡边配环境——反正不花钱,纯属玄学加速。
从“Hello World”到连上Springboot后端
新建项目贼简单:
flutter create my_internal_tool
cd my_internal_tool
flutter run
默认会弹出一个计数器页面。但我们要的是连后端API!刚好我们Springboot服务有一套现成的RESTful接口,比如获取用户列表:
GET /api/v1/users
在Flutter里发起HTTP请求,得先加依赖。打开pubspec.yaml:
dependencies:
flutter:
sdk: flutter
http: ^0.13.5 # 别用dio!新手容易被拦截器绕晕
然后写个简单的Service类:
import 'package:http/http.dart' as http;
import 'dart:convert';
class UserService {
static Future<List<dynamic>> getUsers() async {
final response = await http.get(
Uri.parse('http://your-springboot-server:8080/api/v1/users'),
);
if (response.statusCode == 200) {
return jsonDecode(response.body);
} else {
throw Exception('Failed to load users');
}
}
}
重点来了:如果你在模拟器里跑,地址千万别写localhost!Android模拟器里要用10.0.2.2,iOS模拟器才认localhost。我们组新人在这栽过两次,差点被运维笑死。
踩坑实录:状态管理与平台差异
坑1:StatefulWidget 写到怀疑人生
刚开始我把所有逻辑塞进一个Widget里,结果setState一刷新,整个页面重绘,输入框内容全丢。后来才明白:Flutter的状态管理不能乱来。
对于小项目,用Provider就够了(比Bloc简单多了)。先装依赖:
provider: ^6.0.5
然后把UserService包装成ChangeNotifier,UI层用Consumer监听。这样数据变了,只刷新相关组件,再也不用担心输入框“瞬移”。
坟2:iOS和Android的UI表现不一致
比如一个按钮,在Android上圆角正常,iOS上却方得像砖头。查文档才发现:Material Design 和 Cupertino 风格有差异。
解决方案很简单——别混用!如果目标用户主要是Android(我们内部工具确实如此),就全用MaterialApp + ElevatedButton;如果是iOS优先,就上CupertinoApp。
另外,字体大小也要注意。我们设计师给的Figma稿是14px,但在Flutter里写fontSize: 14,iOS显示会偏小。最后统一用MediaQuery动态计算:
Text(
'Hello',
style: TextStyle(
fontSize: MediaQuery.of(context).textScaleFactor * 14,
),
)
坑3:Release包打出来白屏?
这个问题卡了我整整一天。Debug模式一切正常,一打release包就白屏。最后发现是网络权限没开!
- Android要在
AndroidManifest.xml加:<uses-permission android:name="android.permission.INTERNET" /> - iOS要在
Info.plist加:<key>NSAppTransportSecurity</key> <dict> <key>NSAllowsArbitraryLoads</key> <true/> </dict>
血泪教训:永远先检查权限,再骂框架!
性能优化:别让用户觉得“卡”
虽然Flutter号称60fps,但如果滥用ListView.builder或者图片不压缩,照样卡成PPT。
我们做了三件事:
- 图片用
cached_network_image:自动缓存+占位图,避免滚动时闪白 - 长列表用
ListView.builder:只渲染可见项 - 复杂动画用
RepaintBoundary:隔离重绘区域
上线后用Flutter DevTools测了下,帧率稳定在58-60fps,测试同学终于没提“卡顿”bug了(感动哭)。
发布到应用市场?其实没那么难
内部工具不需要上架,但好奇还是试了下。
- Android:生成签名APK,一行命令搞定
flutter build apk --release - iOS:得用Xcode Archive,但Flutter帮我们处理了90%的配置。唯一麻烦的是证书,建议用Apple Developer账号自动管理。
最骚的是,同一套代码,还能编译成Web版!虽然性能不如原生,但给运营同学临时查数据够用了。
总结:值得投入吗?
从抗拒到真香,我只用了两周。现在这个内部工具已经替代了三个老旧的H5页面,运维也不用半夜爬起来修Nginx配置了(他们请我吃了顿火锅,成都的快乐就是这么朴实无华)。
| 对比项 | 原H5方案 | Flutter方案 |
|---|---|---|
| 开发效率 | 需适配多端 | 一套代码全平台 |
| 性能 | 受限于WebView | 接近原生 |
| 调试体验 | F12看控制台 | DevTools可视化 |
| 与Springboot对接 | CORS各种坑 | 直接HTTP调用 |
当然,Flutter也不是银弹。如果你要做大量原生交互(比如蓝牙、传感器),还是得写Platform Channel,那感觉就像在Java和Dart之间“传纸条”,挺痛苦的。
但对我这种服务端出身、偶尔客串移动端的“缝合怪”来说,Flutter真的是性价比之王。下次团建,我准备跟PM提议:咱们新活动页也用Flutter吧?省下的加班时间,够打三把《永劫无间》了。
后记:写完这篇教程,我发现隔壁组做Unity的哥们也开始偷看Flutter文档了。果然,在成都,没有一个程序员能拒绝“少加班+多摸鱼”的技术方案(手动狗头)。

评论 0