Gradle 7构建Android项目报错:Cannot run Project.afterEvaluate(Action)
问题概述
- 项目类型:Android
- Gradle wrapper版本:gradle-7.5
- Gradle插件版本:7.4.2
- 执行命令:
./gradlew assembleDevGoogleRelease - 报错信息:
Cannot run Project.afterEvaluate(Action) when the project is already evaluated.
- 报错位置:build.gradle中
exec { ... }代码块
问题原因
Gradle 7.x对任务执行阶段的API使用做了更严格的生命周期限制:在任务的doLast(执行阶段)中直接调用exec闭包时,内部逻辑会尝试触发afterEvaluate(项目评估阶段)的操作,但此时项目评估已经完成,从而触发冲突。Gradle 6.x无此严格限制,因此之前版本可正常运行。
另外原代码中存在变量错误:dirName未定义,会导致后续找不到APK目录,需同步修正。
解决方案
方案一:改用project.exec显式调用
修改doLast中的exec调用逻辑,避免隐式触发评估阶段操作,同时修正dirName变量:
android.applicationVariants.all { variant -> // 修正dirName为variant.dirName,获取变体对应的目录名(如devGoogle/release) def dirPath = "${project.projectDir.absolutePath}/build/outputs/apk/${variant.dirName}/" def filePath = '' variant.outputs.all { outputFileName = "xxx.apk" filePath = outputFileName } variant.getAssembleProvider().get().doLast { if (variant.buildType.name == 'release') { def cmd = "cd .. && ./ossutilmac64 cp -f ${dirPath}${filePath} oss://android-test-sz/${filePath}" // 显式创建输出流,避免隐式引用项目上下文 def outputStream = new ByteArrayOutputStream() // 使用project.exec显式调用 project.exec { executable 'zsh' args '-c', cmd standardOutput = outputStream } println(outputStream.toString()) } } }
方案二:创建独立上传任务(推荐,更符合Gradle设计)
将上传逻辑封装为独立任务,通过任务依赖关联到assemble任务,彻底规避生命周期冲突:
android { // ...其他配置 flavorDimensions "app", "channel" productFlavors { dev { dimension "app" applicationIdSuffix ".dev" } product { dimension "app" } google { dimension "channel" } } // 将变体处理逻辑移到productFlavors外部,避免嵌套问题 applicationVariants.all { variant -> def dirPath = "${project.projectDir.absolutePath}/build/outputs/apk/${variant.dirName}/" def filePath = "xxx.apk" variant.outputs.all { outputFileName = filePath } if (variant.buildType.name == 'release') { // 为每个release变体创建独立的上传任务 def uploadTask = tasks.create(name: "upload${variant.name.capitalize()}ToOss", type: Exec) { executable 'zsh' args '-c', "cd .. && ./ossutilmac64 cp -f ${dirPath}${filePath} oss://android-test-sz/${filePath}" def outputStream = new ByteArrayOutputStream() standardOutput = outputStream doLast { println(outputStream.toString()) } } // 设置assemble任务完成后自动执行上传任务 variant.assembleProvider.get().finalizedBy(uploadTask) } } }
内容的提问来源于stack exchange,提问作者Jospehus Chou
相关产品推荐
相关产品推荐

