ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

Android Studio构建卡住?Gradle打包assembleDebug卡顿原因与解决

Android Studio构建卡住?Gradle打包assembleDebug卡顿原因与解决 新装的Android Studio新建完项目满怀期待点下Run结果Build窗口就卡在“Running Gradle task assembleDebug...”这一行短则几分钟长到能让人怀疑人生。我帮人远程排查过几十次这种问题也在论坛里看过无数个求助帖今天干脆把原因和解决办法一次性理清楚。核心关键词就是这几样Android Studio、apk、Gradle、assembleDebug。只要搞清楚Gradle在这个阶段到底在做什么卡住的原因其实就三种下载Gradle本身、下载依赖、编译资源。对症下药十分钟内就能把打包流程跑通。这篇文章适合什么人来读刚入门Android开发、第一次用Android Studio打apk的新手以及被公司老项目构建速度搞到崩溃的开发者。我不会只丢一句“去换镜像”而是会把每一步的原理、改法、验证方式都写清楚保证你看完之后不仅能解决眼前的卡顿以后遇到Gradle相关的构建问题也知道该从哪里下手。1. 先别急着改配置搞懂“Running Gradle task assembleDebug”背后到底在干什么1.1 从点击Run到APK落地构建链路里发生了什么很多人看到“Running Gradle task assembleDebug”就以为电脑卡死了其实Android Studio只是把Gradle的日志压缩成了一行状态提示。Gradle本身是一个自动化构建工具Android项目通过Android Gradle Plugin简称AGP接入Gradle负责把Java/Kotlin源码、资源文件、清单文件、第三方依赖打包成apk。以一个标准的app模块为例执行assembleDebug任务时Gradle会按照任务依赖关系依次执行preBuild、generateDebugSources、processDebugResources、compileDebugKotlin、dexBuilderDebug、mergeDexDebug、packageDebug等。这一长串任务里任何一个环节耗时过长界面上都会显示为“Running Gradle task assembleDebug”。所以它不是一个单一操作而是一整条流水线的总入口。如果你翻看Build窗口底部的详细日志会发现Gradle会输出“ Task :app:processDebugResources”、“ Task :app:compileDebugKotlin”这样的行。每个Task代表一个具体的构建步骤。搞清楚这一步你就不会一卡住就到处乱搜“为什么assembleDebug卡住”而是能顺着日志找到真正的瓶颈。1.2 为什么会“卡住”先分清是下载慢、编译慢还是真报错“卡住”这个词其实很笼统我建议你先把三种情况分清楚现场表现真正原因处理优先级日志显示Download https://services.gradle.org/distributions/gradle-8.13-bin.zip正在下载Gradle发行版默认源在国外速度极慢高改镜像源日志反复打印某个依赖的Download/Resolve依赖仓库源google()和mavenCentral()连不上或超时高改仓库镜像日志停在某个Task比如compileDebugKotlin编译本身耗时可能跟机器配置、增量编译失效有关中优化JVM参数界面一直转圈但日志没有任何输出Gradle daemon启动阶段卡住多半是启动内存或Network问题中检查daemon状态我的经验是绝大多数“卡住”并非真的卡死而是Gradle在后台下载文件界面没有进度条看起来像是死掉了。尤其是第一次构建新项目Gradle需要做三件事下载Gradle工具包、下载AGP插件、下载项目声明的所有第三方库。这一整套流程下来数据量轻松超过一两个GB如果网络环境不好界面卡几十分钟都很正常。还有一个细节很多人不知道如果Gradle在下载过程中断掉它会留下一个.part文件下次构建时从断点继续下载。有时候你以为等很久了其实它在反复重试同一个连接不稳定的地址。所以遇到这种问题别傻等先按下面的方法把下载源换掉。2. 根治方案一把Gradle发行版下载源切成国内镜像2.1 wrapper是什么为什么每次构建都会先下载一个几百MB的包Gradle Wrapper是Android项目的标配它由gradle-wrapper.jar、gradle-wrapper.properties等文件组成。wrapper的作用是锁定项目使用的Gradle版本避免“我这台机器能编译你那台不行”的版本差异问题。gradle-wrapper.properties里最关键的一行是distributionUrlhttps\://services.gradle.org/distributions/gradle-8.13-bin.zip这行代码决定了Gradle从哪个地址下载工具包。第一次构建时wrapper会把zip下载到用户目录下的.gradle/wrapper/dists文件夹里解压后当作构建工具使用。问题就出在这里services.gradle.org是官方下载地址在大陆网络环境下访问速度极不稳定经常出现几十KB每秒甚至连接超时的情况。这跟你电脑配置、项目大小都无关纯属下载源的问题。解决办法也很直接把distributionUrl指向国内镜像站。2.2 修改gradle-wrapper.properties一次替换解决下载卡死打开项目根目录下的gradle/wrapper/gradle-wrapper.properties找到distributionUrl这一行替换成镜像地址。我推荐两个比较稳的镜像源镜像站地址格式腾讯云镜像https://mirrors.cloud.tencent.com/gradle/gradle-8.13-bin.zip华为云镜像https://mirrors.huaweicloud.com/gradle/gradle-8.13-bin.zip改完之后整个文件大概是这样的distributionBaseGRADLE_USER_HOME distributionPathwrapper/dists distributionUrlhttps\://mirrors.cloud.tencent.com/gradle/gradle-8.13-bin.zip networkTimeout10000 validateDistributionUrltrue zipStoreBaseGRADLE_USER_HOME zipStorePathwrapper/dists注意版本号一定要保留原样不要顺手把gradle-8.13改成别的版本。Gradle版本与Android Gradle Plugin版本有对应关系随便换会导致Gradle同步失败报出“Minimum supported Gradle version is X.X.X”的错误。所以这里只改域名和路径版本号必须跟原来一致。改完回到Android Studio点击Sync Project或者直接在终端执行gradlew assembleDebug。如果之前下载中断过建议先手动删除C:\Users\你的用户名.gradle\wrapper\dists\gradle-8.13-bin下的残留文件否则可能继续跟断点死磕。2.3 手把手把Gradle压缩包“搬”到本地离线包方案如果你所在的环境网络特别差连镜像站都下载不稳定那就采用离线包方案。原理很简单手动下载Gradle压缩包放到wrapper指定的缓存目录下让Gradle跳过下载步骤。先从镜像站下载对应版本的zip例如gradle-8.13-bin.zip。然后找到wrapper的缓存目录Windows下一般是C:\Users\你的用户名\.gradle\wrapper\dists\gradle-8.13-bin\哈希字符串\这个哈希字符串是Gradle根据distributionUrl自动生成的目录名每台机器可能不同。你只需要确认两点目录名里包含gradle-8.13-bin目录下存在gradle-8.13-bin.zip文件。放好之后删除该目录下残留的.part和.lck文件再执行构建。Gradle检测到zip已经存在就会跳过下载直接解压使用。注意不要直接把zip解压到别的目录然后用“Local distribution”硬指定路径。这样做虽然也能构建但会破坏wrapper的版本锁定机制。团队协作时别人推代码上来你本地可能就编译不了。动态生成哈希目录虽然看起来繁琐但它是保证项目可移植性的正确做法。3. 根治方案二依赖仓库源镜像解决同步阶段“卡死”3.1 依赖同步与assembleDebug的关系下载的都是什么解决了Gradle本身的下载还有另一座大山依赖下载。Android项目的依赖来源主要就是google()和mavenCentral()这两个仓库默认都在国外。当你执行assembleDebug时Gradle会解析项目所有的依赖坐标逐个从仓库拉取jar/aar文件缓存到.gradle/caches/modules-2/files-2.1目录下。如果仓库连不上Gradle不会立刻报错而是会反复重试界面就一直显示“Running Gradle task assembleDebug”。从Build窗口能看到类似“Could not resolve com.squareup.okhttp3:okhttp:4.12.0”的日志后面跟着一串超时异常。只要依赖数量一多下载耗时完全不可控。熟悉Maven的朋友可能知道国内有不少Maven仓库镜像阿里云就是最常用的一个。把google()和mavenCentral()替换成阿里云镜像下载速度会有质的提升。3.2 修改settings.gradle与根build.gradle新旧工程的配置差异Android项目配置仓库源的位置跟Gradle版本有关。Gradle 7.0之后Google官方推荐在settings.gradle文件里统一管理仓库而不是散落在根build.gradle里。新版项目的settings.gradle默认长这样pluginManagement { repositories { google() mavenCentral() gradlePluginPortal() } } dependencyResolutionManagement { repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) repositories { google() mavenCentral() } } rootProject.name MyApp include :app改造的核心是两段pluginManagement里的repositories负责下载AGP等Gradle插件dependencyResolutionManagement里的repositories负责下载项目第三方依赖。改法都一样把阿里云镜像加在最前面官方地址保留在后面兜底pluginManagement { repositories { maven { url https://maven.aliyun.com/repository/gradle-plugin } maven { url https://maven.aliyun.com/repository/google } maven { url https://maven.aliyun.com/repository/public } maven { url https://maven.aliyun.com/repository/central } google() mavenCentral() gradlePluginPortal() } } dependencyResolutionManagement { repositoriesMode.set(RepositoriesMode.PREFER_SETTINGS) repositories { maven { url https://maven.aliyun.com/repository/google } maven { url https://maven.aliyun.com/repository/public } maven { url https://maven.aliyun.com/repository/central } google() mavenCentral() } }这里有个容易踩的坑很多老教程让新人去根build.gradle里的allprojects改仓库但新版Gradle如果settings里设置了RepositoriesMode.FAIL_ON_PROJECT_REPOS项目级build.gradle里再写repositories就会直接构建失败。所以我建议Gradle 7.0以上的项目一律改settings.gradle老项目才去改build.gradle。还有一点必须注意如果你引入了华为HMS、Mapbox这些私有仓库的依赖它们的仓库地址也必须保留不能全用镜像替换。镜像站只是同步了Google和Maven Central的部分仓库私有仓库不一定有。保守做法是“镜像在前官方在后私有仓库单独保留”。3.3 全局init.gradle一次配置所有项目共用如果你手头项目多每个settings.gradle都改一遍有点烦。Gradle提供了一个全局初始化脚本可以给所有项目统一注入仓库配置。在用户目录下找到.gradle文件夹Windows是C:\Users\你的用户名.gradle如果没有init.d目录就新建一个然后创建一个init.gradle文件内容如下allprojects { repositories { maven { url https://maven.aliyun.com/repository/public } maven { url https://maven.aliyun.com/repository/google } maven { url https://maven.aliyun.com/repository/central } google() mavenCentral() } }这个脚本对所有Gradle项目全局生效。但我要提醒一句在Gradle 7.x之后Google越来越强调settings.gradle的集中管理方式init.gradle的allprojects配置在新项目里不一定有最终话语权甚至可能被Settings的dependencyResolutionManagement覆盖。所以init.gradle更适合配合老项目使用或者是做应急兜底。新项目老老实实改settings.gradle这是目前最可靠的做法。如果你想要一个“全局只改一次”的方案我建议这样做保持settings.gradle里的仓库配置统一为镜像优先同时保留官方仓库。这样一个团队的所有成员只要同步代码就都能用上镜像不需要每个人单独配置。3.4 不敢乱动仓库配置离线模式与依赖缓存详解有些读者会问“我公司项目走的是内网环境根本没有外网怎么办”Gradle提供了离线模式Offline work。在Android Studio的Settings里找到Build Tools Gradle勾选Offline work或者在命令行执行gradlew assembleDebug --offline。离线模式的含义是Gradle不访问任何远程仓库只使用本地缓存中的依赖。如果你的依赖第一次就在有网环境下完整下载过离线模式构建会非常快因为它跳过了所有网络请求。但离线模式有个大坑一旦项目新增了依赖或者需要下载缓存中没有的版本离线模式会直接报错而且报错信息不太友好只说“No cached version available for ...”。很多新手不知道这个机制看到报错就去删缓存、删Gradle目录结果越搞越糟。我的建议是离线模式只用于缓存已经齐备、且网络环境不稳定的场景。日常开发还是保持在线状态只是把仓库源换成镜像这样新增依赖时才能自动下载。4. 构建成功是第一步把APK打包过程变成“日常快跑”4.1 三个顺手就能做的构建加速配置解决了下载问题之后如果你的机器配置一般还会觉得构建偏慢。Gradle有一些开箱即用的加速项全在gradle.properties文件里配置。第一个是加大Gradle JVM内存。默认的org.gradle.jvmargs通常只有1G多对大型项目不太够容易频繁触发GC导致构建变慢。我常用的配置是org.gradle.jvmargs-Xmx4096m -XX:MaxMetaspaceSize1g -Dfile.encodingUTF-8第二个是开启构建缓存和并行编译org.gradle.cachingtrue org.gradle.paralleltrue构建缓存可以让Gradle在多次构建之间复用Task的输出结果并行编译则是把不同的模块任务分配到多个线程执行。对多模块项目效果非常明显。第三个是开启配置缓存Configuration Cacheorg.gradle.configuration-cachetrue配置缓存能把项目配置阶段的结果缓存下来第二次构建开始时会快很多。不过有些老插件不兼容配置缓存开启后如果报错关掉即可。注意内存配置不是越大越好。如果你的电脑只有8G内存强行配-Xmx6g反而会因为物理内存不足导致系统频繁交换整个机器卡到没法用。建议根据自己电脑的内存大小合理设置16G内存的机器配4096m比较稳妥。4.2 从Build菜单到命令行gradlew assembleDebug的正确姿势在Android Studio里点Run确实是最直观的构建方式但命令行构建也有很多优势。比如在终端执行gradlew assembleDebug时你能看到完整的任务执行日志不会被Android Studio的界面“美化”掉细节。Windows系统在项目根目录执行gradlew.bat assembleDebugmacOS / Linux执行./gradlew assembleDebug命令执行成功后日志末尾会显示“BUILD SUCCESSFUL”同时在Build窗口对应的任务上能看到绿色的勾。生成的apk默认在app/build/outputs/apk/debug/app-debug.apk这个路径是固定的直接在文件管理器里按路径找就行。命令行构建还有一个好处它可以配合CI持续集成流程使用比如提交代码后自动打测试包。团队里如果有人只负责测试不需要装Android Studio直接拉代码执行gradlew assembleDebug也能出包。4.3 打包产物检查debug版APK和release版有什么区别以及签名相关补充既然标题说的是assembleDebug我就把Debug包和Release包的差别顺带提一下。Debug包的全称是app-debug.apk它是为开发调试设计的包默认使用Android SDK自带的debug.keystore签名可以直接安装到手机上。它的特点是体积大、包含调试信息适合日常联调和自测。Release包可以通过执行assembleRelease生成它需要进行正式的签名配置否则会打出一个未签名的包无法安装到手机。签名的作用是标识应用作者和保证应用完整性每次升级App都必须使用同一个签名否则会报“应用未安装”或“签名冲突”。如果你只是临时打个包发给自己或者朋友体验用Debug包完全够用。但如果准备上架应用商店就必须在build.gradle里配置signingConfigs使用正式的keystore文件签名并生成app-release.apk。关于“apk签名工具”这个概念网上很多一键签名工具其实就是对keystore和apksigner命令行工具的封装手动操作也不复杂但那是另一个话题这里就不展开了。5. 常见问题排查实录这些报错我全踩过5.1 Gradle下载与同步相关报错报错信息原因分析解决方案Download gradle-8.13-bin.zip 进度条不动官方下载源连不上改gradle-wrapper.properties为腾讯云/华为云镜像Could not install Gradle distribution from gradle-8.13-bin.zip下载过程中断、网络超时或校验失败删除dists目录下的残留文件重新构建或改为离线包方案Could not resolve com.android.tools.build:gradle:8.2.2AGP插件没下载下来在settings.gradle的pluginManagement里配置阿里云gradle-plugin镜像Minimum supported Gradle version is 8.2. Current version is 8.0wrapper版本与AGP不匹配回退AGP版本或升级distributionUrl中的Gradle版本这里单独说下“Minimum supported Gradle version”这个报错它很容易误导人。简单理解就是AGP和Gradle之间有版本兼容矩阵比如AGP 8.1要求Gradle 8.0以上AGP 7.4要求Gradle 7.5以上。你改了镜像URL之后一定不要把distributionUrl里的版本号换高或换低否则就会踩到这个兼容性坑。5.2 构建过程中的典型Gradle问题报错信息原因分析解决方案Deprecated Gradle features were used in this build, making it incompatible with Gradle 9.0项目用了某些旧语法或API只是警告不阻止构建暂时忽略或逐步替换废弃APIGradle DSL method not found: minsdkversion()方法名拼写错误正确写法是小驼峰minSdkVersion检查app/build.gradle里的配置把方法名修正为minSdkVersionCould not find com.android.tools.build:gradle:8.2.2指定版本不存在或镜像未同步换成官方仓库试试或检查版本号是否存在FileNotFoundException: .gradle/caches/... 不可访问缓存目录损坏或被杀毒软件锁定关闭杀毒软件对项目的实时扫描删除caches目录后重新构建“Deprecated Gradle features were used”这个警告很多老项目构建时都会打出来。它不算错误构建会正常成功。但如果哪天你升级Gradle大版本警告就可能变成真正的错误。所以看到它不用着急处理但最好记录一下等有空的时候看看是哪个插件用了旧特性。5.3 两个特殊场景Flutter项目和中文乱码最近有不少人问Flutter项目打包apk时碰到“You are applying Flutters main Gradle plugin imperatively using the apply script”这个报错。这个报错说的是项目在android/settings.gradle里还在用老式的apply path方式加载Flutter插件而新版Flutter要求用插件DSL方式。处理方法是把settings.gradle里的apply配置改成plugins { id dev.flutter.flutter-plugin-loader version 1.0.0 }这个报错不会让你的assembleDebug一直“卡住”但它会在构建开始时弹出来。如果你不是Flutter项目看到这句话可以直接忽略。再说说中文乱码。Windows系统下终端执行gradlew时经常遇到中文路径或中文字符编码问题构建日志里可能出现一堆乱码。解决方法是确保gradle.properties里设置了UTF-8编码我在前面4.1节里写的-Dfile.encodingUTF-8就是干这个用的。如果项目路径本身包含中文或空格也容易引发奇奇怪怪的构建异常建议把项目放在纯英文路径下。5.4 排查卡死问题的通用思路很多人卡住之后的第一反应是疯狂点Stop、再Run这是最没有帮助的操作。正确的排查顺序是先打开Build窗口拉到最底部看最后一行实际输出。如果最后一行是Download那就是网络问题解决下载源如果最后一行是某个Task且长时间不变那可能是这个Task内部卡住了可以按CtrlBreakWindows或CtrlCmacOS打断查看线程转储如果整个窗口一片空白连日志都没有那Gradle daemon可能都没起来。Gradle daemon是Gradle的后台进程它负责承载构建任务。第一次构建通常会启动一个daemon进程如果这个进程因为内存不足或端口被占用启动失败你会看到莫名其妙的卡顿。在项目根目录执行gradlew --stop可以清理掉已有的daemon再重新执行构建。这个操作很简单但常常见效我建议碰到疑难杂症时先来一下。还有个小技巧给Gradle配置本地代理不是必须的镜像源已经能解决99%的下载问题。如果镜像源也慢那就检查一下是不是只有你一个人慢还是整个团队都慢。整个团队都慢多半是网络出口问题只有你一个人慢检查一下本地是否有防火墙或杀毒软件拦截了Gradle的下载请求。很多杀毒软件会把Gradle的临时文件当成可疑程序扫描导致构建极慢把.gradle目录加入白名单会有明显改善。最后分享一点个人体会。我现在无论接手新项目还是自己开新项目都会先干三件事改gradle-wrapper.properties的distributionUrl为腾讯云镜像、改settings.gradle仓库源为阿里云镜像优先、把gradle.properties里的org.gradle.jvmargs调到适配当前机器内存的大小。这三步做完正常情况下assembleDebug不会再有“长时间卡住”的体验第一次构建三到五分钟后续增量构建基本在一分钟以内。如果哪天你的构建又莫名其妙卡住了记住先看日志分清是在下载还是在编译再决定是否要清理daemon、清理缓存或者检查网络。千万不要一上来就删掉整个.gradle目录那只会让下次构建从头再来浪费更多时间。Gradle这个构建工具没有太多玄学它的每一步操作都在日志里有记录只要你愿意多看几行问题基本都能定位到。
返回列表