Skip to content

Flutter 排错手册 ​

Flutter 排错先分类,再动手。不要一上来就清缓存、删 lock、换 SDK,否则容易把问题变成多个问题。

有效排错的顺序是:

  1. 先判断问题发生在哪个阶段:环境、依赖、构建、运行、布局、网络、性能、发布。
  2. 保留第一条真实错误,不要只看最后一行失败提示。
  3. 用最小复现缩小范围:新项目是否能跑、换设备是否复现、去掉插件是否恢复。
  4. 只改一个变量,然后验证。
  5. 记录最终原因和处理方式,避免下次重复踩坑。

排查入口 ​

问题优先检查
环境异常flutter doctor
依赖冲突pubspec.yaml、pubspec.lock、SDK constraint
Android 构建失败Gradle、Kotlin、minSdk、namespace、签名
iOS 构建失败CocoaPods、Xcode、证书、描述文件、权限
页面白屏日志、异常栈、路由、状态机、首帧
布局溢出Row/Column 主轴空间、滚动容器约束
接口联调异常请求参数、环境域名、token、错误码、代理
权限异常Manifest、Info.plist、运行时授权、系统设置
卡顿Profile mode、DevTools Performance、图片和重建范围

常用命令:

bash
flutter doctor -v
flutter devices
flutter analyze
flutter test
flutter run -v
flutter clean
flutter pub get
flutter pub deps
flutter pub outdated

flutter clean 是清理构建产物,不是万能药。它适合构建缓存或平台构建产物异常,但如果根因是依赖冲突、权限缺失、Gradle 版本不匹配,清理后仍然会失败。

依赖问题 ​

bash
flutter pub get
flutter pub outdated
flutter pub deps

dependency_overrides 只适合临时验证,不建议长期作为正式解法。

症状可能原因处理
version solving failed依赖版本约束冲突看冲突链,升级或降低相关包
某插件只在一个平台失败插件平台实现缺失或版本不兼容查插件支持平台和原生配置
升级 Flutter 后大量报错SDK、插件、Dart 语法约束变化分阶段升级,不要一次升所有依赖
本地能跑 CI 失败系统环境、缓存、大小写路径差异固定 SDK 版本,检查路径大小写

排依赖冲突时,先看直接依赖,再看传递依赖。不要只盯着报错包名,有时真正需要升级的是上游依赖。

构建问题 ​

Android 构建失败时,优先找第一条真实错误,而不是最后一行 BUILD FAILED。常见原因包括 Gradle 插件版本、Kotlin 版本、minSdk、namespace、签名和混淆。

iOS 构建失败时,重点看 CocoaPods、Xcode 版本、最低系统版本、证书、描述文件和 Info.plist 权限文案。

Android 常见问题 ​

症状检查点
Gradle 下载失败网络、镜像、Gradle wrapper、代理
minSdkVersion 不满足插件要求更高 minSdk
namespace not specifiedAndroid Gradle Plugin 新版本需要 namespace
Kotlin 编译失败Kotlin 插件版本和依赖不匹配
release 包运行异常混淆、资源压缩、签名、ABI
权限相关功能无效AndroidManifest.xml、运行时权限、系统版本

Android 排查时可以使用:

bash
cd android
./gradlew assembleDebug --stacktrace
./gradlew app:dependencies

iOS 常见问题 ​

症状检查点
Pod install 失败CocoaPods 版本、Podfile、Ruby 环境
Xcode 编译失败Xcode 版本、最低 iOS、Swift 版本
真机安装失败证书、描述文件、Bundle ID
权限弹窗不出现Info.plist 权限文案缺失
插件链接失败Pod 依赖、架构、原生 SDK 版本

iOS 排查时不要忽略 Xcode 的完整错误。很多 Flutter 命令只展示摘要,真实原因要去 Xcode build log 里看。

白屏问题 ​

白屏要分三类:

类型检查点
启动白屏初始化阻塞、首帧过慢、启动图配置
页面白屏路由错误、异常被吞、布局不可见
数据白屏接口失败但没有错误态、状态机缺分支

排查白屏可以按这个顺序:

  1. 看控制台是否有异常栈。
  2. 确认 main()、runApp()、根路由是否执行。
  3. 检查首屏初始化是否有同步阻塞。
  4. 检查页面是否进入加载态但永远不结束。
  5. 检查接口失败后是否缺少错误态。
  6. 检查布局是否不可见,例如高度为 0、颜色同背景、被遮挡。
  7. release 才白屏时,检查混淆、资源、权限、初始化顺序。

不要在页面里吞掉异常后只返回空容器。至少要记录日志,并在用户界面给出失败状态和重试入口。

布局溢出 ​

典型报错包括 RenderFlex overflowed、Vertical viewport was given unbounded height、BoxConstraints forces an infinite width。布局问题通常来自约束不清。

场景原因处理
Row 文本溢出文本没有被约束宽度用 Expanded 或 Flexible
Column 中列表报无限高度ListView 不知道自己高度用 Expanded 包裹
滚动容器里套 Expanded滚动方向约束是无限的改用固定高度或 sliver
图片撑爆布局图片原始尺寸大,显示约束不清设置宽高、fit、裁剪
键盘弹起遮挡页面没有处理 inset使用 Scaffold、滚动容器或调整布局

排查时可以打开 Flutter Inspector,选中出问题的 Widget,看父子约束。不要只靠肉眼移动几个 padding。

状态和重建问题 ​

状态问题常见表现:

症状可能原因
页面反复请求接口请求放在 build 中
列表项状态错乱缺少稳定 Key
输入框内容丢失控制器生命周期不对
页面退出后仍收到回调订阅、定时器、控制器没有释放
局部操作导致整页闪烁状态作用域过大
数据更新 UI 不刷新状态对象没有通知或引用未变化

处理原则:

  • 不在 build 中制造副作用。
  • 控制器、订阅、动画在 dispose 释放。
  • 列表项使用业务 ID 作为 Key。
  • 高频变化拆成更小组件或更小状态作用域。
  • 页面状态用明确模型表达加载、成功、空、失败。

网络和异步问题 ​

网络问题不要只显示“请求失败”。至少要区分:

类型例子处理
连接问题无网络、超时、DNS可重试,保留缓存
认证问题token 过期、401刷新 token 或跳登录
权限问题403提示无权限
业务错误参数错误、状态不可操作展示业务文案
服务错误500、网关错误重试或稍后再试
解析错误字段类型不匹配记录日志,降级处理

异步回调还要注意页面生命周期。页面已经销毁后再调用 setState,会出现 setState() called after dispose()。这种问题常见于网络请求、定时器、流订阅和动画回调。处理方式是取消订阅、判断 mounted,或者把异步逻辑放到更合适的状态管理对象里。

接口联调问题 ​

联调阶段要先确认请求真的发到了正确服务。常见问题包括:

现象检查点
本地正常,测试包失败--dart-define 环境、接口域名、证书、代理
401 或频繁退出登录token 存储、刷新 token、时间偏差、账号互踢
403权限、角色、租户、接口灰度
字段解析失败DTO 可空、字段类型、后端兼容变更
分页重复或丢数据排序规则、游标、刷新和加载更多状态
上传失败文件大小、MIME、权限、超时、后台限制

页面不要直接展示后端原始错误。更稳的做法是把接口错误映射成应用错误,再由页面决定提示、重试、跳转登录或保留缓存。

权限和设备能力问题 ​

设备能力相关问题通常跨 Dart、插件和原生配置三层:

能力检查点
相机/相册权限文案、运行时授权、系统相册限制、文件路径
定位前台/后台权限、系统定位开关、精确定位、服务不可用
通知通知权限、厂商通道、token 注册、点击跳转
蓝牙系统版本权限变化、扫描限制、定位权限依赖
支付/分享SDK 配置、回调 URL、签名、应用白名单

调试这类问题时,要分别验证:原生配置是否齐全、插件是否支持当前平台、用户授权状态是否符合预期、异常是否能被业务层接住。

卡顿问题 ​

卡顿不要用 debug 模式判断。用 profile mode 和 DevTools 看 UI 线程、Raster 线程、图片解码、布局和绘制耗时。

常见处理:

  • 缩小 setState 影响范围。
  • 使用 ListView.builder 懒构建。
  • 避免 shrinkWrap 处理大列表。
  • 图片按显示尺寸加载。
  • 复杂绘制用 RepaintBoundary 验证隔离效果。
  • 大计算移出主 isolate。

性能问题要先分类:

类型表现排查
启动慢点开应用很久才显示首屏初始化、同步 IO、插件启动、资源加载
滚动卡列表滑动掉帧列表项过重、图片过大、重建范围大
动画卡过渡不流畅每帧计算、绘制、图层复杂度
内存高用久后变慢或崩溃图片缓存、对象泄漏、订阅未释放
某页面慢进入页面明显停顿同步计算、首屏接口、复杂布局

优化不要凭感觉。先用 DevTools 找到瓶颈属于 build、layout、paint、raster、network 还是 memory,再做有针对性的改动。每次优化后要保留对比数据。

应用发布阶段问题 ​

有些问题 debug 没有、release 才出现:

问题可能原因
release 白屏混淆、资源缺失、初始化异常、权限
某插件 release 失效ProGuard/R8 规则缺失、原生 SDK 配置差异
iOS 审核被拒权限文案、隐私说明、后台能力声明不完整
线上崩溃无法定位没接崩溃收集或符号化信息缺失
不同渠道行为不同环境变量、接口域名、签名、配置文件混用

发布前至少确认:

  • 环境配置明确区分 dev、test、prod。
  • Android 签名、混淆、渠道和版本号正确。
  • iOS Bundle ID、证书、描述文件和权限文案正确。
  • 崩溃收集、日志、关键埋点可用。
  • 有回滚或紧急修复路径。

排错闭环模板 ​

遇到问题时可以按下面模板记录:

text
问题现象:
发生环境:Flutter 版本、Dart 版本、设备、系统版本、debug/profile/release
复现步骤:
第一条真实错误:
已排除项:
根因:
修复方式:
验证结果:
后续预防:

这类记录比“已修复”更有价值。Flutter 项目很多问题会在团队、设备、插件、系统版本变化后重复出现,沉淀排错记录能明显降低后续成本。

别急,先让缓存热一下。