如果你在终端敲下flutter run屏幕很快打出这行字Running Gradle task assembleDebug...然后光标就在那里转啊转一分钟、五分钟、二十分钟……项目却始终没启动。这大概是 Flutter 开发里最常见也最劝退的一幕。我最早碰到它是在接手一个从仓库里刚拉下来的模拟项目时当时整整等了一个小时进度纹丝不动一度以为是编译器坏了。后来排查得多了发现这个现象背后其实并不是一个单一问题它是好几个环节坏运气叠加的结果。今天就把我在这条路上踩过的坑、试过的办法、以及最后沉淀下来的一套处理流程完整写出来希望能给你省下和我当初一样多的时间。1. 先看懂这个提示你说它“卡”到底卡在哪1.1 这句话不是进度条而是构建链路的最后一环要解决一个看着像“卡死”的问题第一步是弄清楚这行字到底在干嘛。Flutter 项目虽然以 Dart 为主但它最终要跑在 Android 设备上就不能绕过 Android 原生的构建体系。flutter run在编译完 Dart 代码之后会进入 Android 工程目录调用 Android Gradle PluginAGP去执行assembleDebug任务产出可安装的 debug APK。这个任务背后是一系列串联操作解析项目配置、解析依赖、合并资源、生成 R 类、把 Java/Kotlin 代码编译成字节码、再用 D8/R8 转换、打包、签名。每一步都可能耗时而终端只给你一行“正在执行”的提示并不会把内部状态都铺开。所以这行字停了很久不代表机器死机了只代表 Gradle 还在某个环节里工作或者正在耐心等待某个外部资源。你得学会判断它是在“干活”还是“卡死”这是后面所有排查的前提。1.2 首次构建慢和真正卡死的区别要分清我第一次遇到的时候直觉是项目坏了。后来发现新项目首次构建本身就有一个“可怕”的启动成本要下载 Gradle 发行版、AGP 插件、Kotlin 插件、AndroidX 库、以及项目依赖的各种第三方包下载量往小了说是几十MB往大了说可以到几百MB甚至 GB 级别。你机器上如果没有任何缓存这个初次下载过程会非常难熬而且它不像 IDE 里的下载弹窗没有明确的百分比进度。这是“慢”不代表“卡死”。真正的“卡死”往往表现为日志长时间没有任何新增、网络传输量为零、CPU 占用也近乎为零。两者处理方式完全不同慢你要想办法加速网络或缓存资源卡死你要去查版本兼容性、依赖冲突、甚至 Gradle Daemon 状态。所以别一上来就删缓存重来那样反而可能把部分下载好的缓存弄丢让下一次构建变得更长。2. 卡在assembleDebug的常见原因拆解2.1 网络下载绝大多数“卡”都是下载耗时在背锅我实际排查过的案例里九成以上的“卡很久”都和下载有关。Gradle 默认的依赖源是 Google Maven 和 Maven Central这两个仓库本身没问题但在某些网络环境下访问速度确实堪忧。特别是项目依赖链很复杂的时候Gradle 需要逐个下载 jar 和 aar还得校验、解压、索引整个过程叠加起来等待时间就会成倍放大。判断方法很简单在卡住的同时打开文件管理器看~/.gradle/caches/modules-2/files-2.1目录Windows 下是C:\Users\你的用户名\.gradle\...如果里面的文件数量和大小在慢慢增长说明下载通道在工作只是速度让你抓狂。如果这个目录一直不变再加上 CPU 几乎为 0那才需要考虑其他原因。2.2 版本匹配Gradle、AGP、JDK 三者的隐藏契约另一个常见的“隐形杀手”是版本不匹配。Flutter 的模板在创建项目时会写入一套经过验证的 Gradle、AGP、JDK 组合但开发者的本机环境往往不会和模板完全一致。比如新项目用了 AGP 8.x它要求 JDK 17 起步而老项目可能还是 JDK 11这时候 Gradle 会在配置阶段出现各种匪夷所思的行为甚至长时间没有明确报错。我遇到过一位开发者的项目卡在assembleDebug超过半小时最后看日志发现只是 JDK 版本太低导致某个插件编译阶段反复重试。所以遇到长时间构建第一反应不是去查依赖有没有写错而是先核对版本组合。提供一个粗略参考典型场景Gradle 版本AGP 版本JDK 版本较老的 Flutter 模板6.x ~ 7.x4.x ~ 7.x11 或 17新版 Flutter 模板7.x ~ 8.x7.x ~ 8.x17具体数字要以项目里gradle-wrapper.properties和 Flutter 官方对应关系为准不要只看我这张表硬套。项目能跑就尽量不要为了追新去动版本。2.3 机器资源与项目复杂度内存、磁盘、杀毒软件都在添乱还有一种情况是项目本身很大多模块、多依赖加上资源文件特别多。构建时每个模块都要经历编译、转换、合并中间产物又大又碎内存不足时Gradle 会频繁触发 GC表现为卡在某一步很久不动。磁盘 IO 慢也一样致命因为构建过程要反复读写缓存和临时文件。Windows 上还要注意杀毒软件的实时扫描。我有一次帮别人排查项目构建卡在某个资源合并任务上最后发现是安全软件在反复扫描.gradle和build目录每次扫描把文件锁住Gradle 只能等。把项目目录、Gradle 缓存目录加入扫描排除列表后构建速度立刻正常。3. 五分钟定位法先用日志把问题揪出来3.1 开启详细日志flutter run -v看执行到哪个任务遇到卡顿千万别靠猜。第一步是重新运行一次带详细日志的命令flutter run -v-v会输出非常冗长的过程日志从加载 Flutter 引擎到执行 Gradle 任务都会写出来。卡住以后看终端最后几十行能大致知道它停在哪一类任务上。同时打开任务管理器或系统监视器观察 Java/Gradle 相关进程的 CPU 消耗。如果日志停在Downloading相关文字CPU 又很低那基本可以确定是网络下载瓶颈如果日志已经进入类似:app:compileDebugKotlin、:app:processDebugResources之类的阶段CPU 又很高那反而是正常编译正在卖力工作只不过项目太大或配置太差。3.2 直接跑原生命令绕开 Flutter 从 Gradle 侧找真相flutter run的日志虽多但夹着很多 Dart 工具链的信息。我更推荐绕开 Flutter 直接进android目录里跑原生构建命令cd android ./gradlew assembleDebug --info --stacktrace--info会输出每个 task 的耗时、依赖下载的 URL、以及缓存命中情况。我第一次用这招时恍然大悟原来flutter run只显示一行字后面 Gradle 已经默默执行了几十个任务。如果你想看得更细还可以用--debug不过日志量极大日常排查--info就够了。3.3 观察关键目录与日志判断是等待还是计算除了命令日志另外两个观察点很实用。一个是 Gradle Wrapper 的发行版下载目录~/.gradle/wrapper/dists首次构建如果看到里面有个正在下载的.zip.part文件说明卡在 Gradle 本身的分发下载另一个是 Gradle Daemon 的日志目录~/.gradle/daemon/版本号里面记录着每个构建进程的运行细节。真到了疑难杂症阶段这些日志里的异常信息往往比终端输出更准确。4. 对症下药从依赖源到构建参数的一整套提速方案4.1 修改仓库地址把依赖拉取切换到更快的镜像通道如果定位到瓶颈是网络下载最直接的提速方式是把依赖仓库地址切换到访问速度更快的公共镜像。这里要注意别只改一处settings.gradle里的pluginManagement和dependencyResolutionManagement两个区域都要处理。下面是一个典型的配置模板其中mirrors.example.com是占位符你需要替换成自己网络环境下实测速度更好的公共 Maven 镜像地址// settings.gradle pluginManagement { repositories { // 优先走公共镜像镜像不通时回退默认源 maven { url https://mirrors.example.com/repository/gradle-plugin/ } google() mavenCentral() gradlePluginPortal() } } dependencyResolutionManagement { repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) repositories { maven { url https://mirrors.example.com/repository/google/ } maven { url https://mirrors.example.com/repository/public/ } google() mavenCentral() } }如果项目是老式结构仓库地址写在根目录build.gradle的allprojects.repositories里那就同样把镜像仓库地址加到最前面。改完之后最好把 Gradle 缓存里已经存在的那部分保留让缺失的依赖走新地址重新下载。实测下来这个改动往往能把首次下载时间从半小时压到几分钟。注意修改后如果出现某些仓库找不到依赖的情况说明镜像同步不全可以临时保留默认源作为回退。4.2 调优gradle.properties内存、并行、缓存一次配齐网络问题解决后还要让 Gradle 本身跑得顺畅。打开android/gradle.properties这几个参数值得重点配置# 给 Gradle 分配的内存根据机器配置调整 org.gradle.jvmargs-Xmx4g -XX:MaxMetaspaceSize1g -Dfile.encodingUTF-8 # 并行构建多个模块 org.gradle.paralleltrue # 开启构建缓存任务产物复用 org.gradle.cachingtrue # 复用后台构建进程避免每次冷启动 org.gradle.daemontrue # 按需配置减少无关模块的配置耗时 org.gradle.configureondemandtrueorg.gradle.jvmargs是关键——Gradle 依赖分析、资源合并、代码编译都会消耗大量内存默认堆设置通常偏保守遇到大项目时 GC 频繁会拖慢整个构建。但也不能无脑调大如果你机器只有 8G 内存强行设置-Xmx8g反而会让整机卡顿。parallel和caching对多模块项目收益明显但低配机器上并行任务太多之也可能互相抢资源需要实际测试后取舍。4.3 锁定版本与本地分发不追新不折腾很多构建慢的问题根源其实是版本错乱。只要项目能正常工作就尽量不要手动去改gradle-wrapper.properties里的 Gradle 版本也不要因为看到新版本特性就顺手升级 AGP。Flutter 版本升级后模板生成的 Gradle 配置通常会同步更新这时候要注意项目里是否残留了旧的本地配置冲突往往会带来莫名其妙的构建卡顿。另一个容易忽略的点是 Gradle 发行版本身的下载。gradle-wrapper.properties默认的distributionUrl指向官方下载地址如果这个地址在你的网络环境下访问很慢可以改成镜像地址或者直接把压缩包下载到本地后用file://指定distributionUrlfile\:///D:/software/gradle-8.7-bin.zip这种方式对团队协作也友好只要大家统一了本地 Gradle 文件路径就不会反复从远程下载同一个几百MB的压缩包。注意改完要重新运行构建验证一下别让 wrapper 校验签名的逻辑因为路径问题报错。4.4 构建缓存与本地缓存把重复劳动压缩到最小除了首次构建日常开发的痛苦更多来自反复构建。好在 Gradle 本身提供了构建缓存Build Cache你只要在gradle.properties里开了org.gradle.cachingtrue同一台机器上相同输入的任务结果就能被复用。对于 Flutter 项目还有一个容易被忽略的命令flutter precache --android这个命令会预先下载 Flutter 引擎和 Android 相关的原生产物可以避免每次创建新项目或切换分支时重复下载这些体积偏大的二进制文件。配合 Gradle 缓存第二次构建的耗时往往能从十几分钟降到一两分钟这也是我后来越来越少被“卡在 assembleDebug”困扰的原因。5. 实操案例一个模拟项目的完整抢救记录5.1 改造前的现象与初始日志为了说得更具体我用一个模拟项目 X 来复盘。项目是标准的 Flutter 模板工程依赖了几个常用库。第一次在空白环境执行flutter run卡在Running Gradle task assembleDebug...超过 40 分钟没有任何报错。终端日志的最后几行几乎不变CPU 占用极低网络看起来也没在跑。我用./gradlew assembleDebug --info --stacktrace重新执行发现日志里大量的Downloading ...反复出现而且同一个 URL 还会重试。这证实了网络下载是首要瓶颈。5.2 改造后的配置内容与执行效果针对模拟项目 X我做了三处改动。第一是在settings.gradle里将仓库地址优先改为公共镜像第二是在gradle.properties中把内存改成-Xmx4g并开启并行、缓存和 Daemon第三是把 Gradle Wrapper 的发行版改成镜像地址下载。改造后完整执行一次assembleDebug总共耗时大约 12 分钟其中大头仍然是最初那一轮依赖下载紧接着再执行第二次构建由于缓存已经建立耗时直接降到 1 分 20 秒左右。flutter run不再出现夸张的卡顿应用很快就能启动起来。这段过程也提醒我所谓“快”不是一个绝对数字而是把一次性的高成本用缓存摊薄把后续的重复构建变成轻量操作。5.3 改造过程中的几个取舍点配置不是越多越好。我在模拟项目 X 上同时尝试开org.gradle.configureondemandtrue确实让配置阶段快了一些但在某些自定义插件较多的项目里它可能会导致任务依赖不完整反而引发异常。另一个争议点是android.enableJetifierfalse如果你的项目没有使用旧的 support 库依赖关闭 Jetifier 可以减少大量转换工作但凡是还依赖老库的项目关掉它就会直接构建失败。所以这些参数都需要按项目实际情况验证别照着网上的万能配置抄完就不管了。6. 常见问题与排查技巧实录6.1 常见问题速查表下面这张表把我这几年遇到的典型状况整理成了速查形式你可以对号入座现象可能原因优先处理方向卡在首次构建日志出现大量 Downloading依赖下载网络耗时换镜像仓库、预下载依赖卡在下载 Gradle 发行版Wrapper 下载慢用本地 zip 或镜像 distributionUrl卡在编译任务CPU 高但迟迟不走内存不足或项目过大调大 jvmargs、关闭并行每次构建都像首次构建缓存未开启或配置不生效开启 caching、检查缓存目录日志偶尔打印错误但不退出版本不兼容、插件冲突核对 JDK/AGP/Gradle 版本Windows 下卡在某资源任务杀毒软件扫描锁定文件排除目录、暂时关闭实时防护6.2 几个容易被忽略的细节技巧排查过程中有几个细节非常影响效率。第一别急着删除.gradle目录。很多人一卡就删缓存重来结果把已经下载好的大半依赖也清掉了下次构建又要从头开始。想清理某个依赖可以进caches/modules-2/files-2.1找到对应的 group 目录精确删除甚至可以先试./gradlew --stop重启 Gradle Daemon 再重试。第二注意项目路径不要有中文、空格或者过长路径。Gradle 对这类路径的兼容性有时会触发诡异卡顿尤其是 Windows 环境。我之前有次项目放在一个带中文的目录下构建经常卡在资源合并改到纯英文路径问题就消失了。第三尽量让首次构建一次性执行完不要中途频繁打断。被打断的下载容易留下不完整的缓存文件下次构建再触发时反而可能因为校验不对而重复下载。第四遇到问题先跑一次原生命令./gradlew assembleDebug而不是反复在 IDE 里重试。IDE 的错误提示有时会被缓存而命令行里的信息更原始、更准确。我在排查里很多次都是靠命令行日志里的一个 URL 才定位到真正卡住的地方。7. 关于这个问题的最后一点个人经验如果让我只说一条对 Flutter 开发者最有用的建议那就是把 Gradle 这条链路当作一个独立的基础设施来对待而不是等它出问题才去查。新建项目后先到android目录跑一次./gradlew assembleDebug确认原生的构建链路是通的再回到顶层用flutter run做完整调试。这个过程能帮你把问题分隔开卡在 Gradle 里就去查 Gradle 这边卡在 Dart 编译或插件那边再去查 Flutter 工具链。另外我自己的习惯是把常用的镜像配置、gradle.properties参数和本地 Gradle 发行版路径整理成一个模板块每次新建项目直接复用再根据项目差异微调。这套做法看起来不起眼但能省掉大量重复的首次构建痛苦。希望这篇文章能让你下次看到Running Gradle task assembleDebug...的时候不用再焦虑地盯着光标发呆而是有条不紊地把日志翻出来找到真正拖后腿的环节然后一次解决。
阅读完成 · 觉得有帮助?