添加Jacoco插件时遭遇Unknown Kotlin JVM target:20错误求助
问题:添加Jacoco插件后出现「Unknown Kotlin JVM target:20」错误
项目中所有JVM target配置均设置为17,未提及过JVM target 20,但添加Jacoco插件用于代码覆盖率统计时,执行构建命令出现「Unknown Kotlin JVM target:20」错误,降低Jacoco插件版本后问题仍未解决。
报错日志
./gradlew testDebugUnitTest Starting a Gradle Daemon, 1 incompatible and 1 stopped Daemons could not be reused, use --status for details > Configure project :app Task -> testDebugUnitTest Task -> testReleaseUnitTest > Task :app:kaptGenerateStubsDebugKotlin FAILED FAILURE: Build failed with an exception. * What went wrong: Execution failed for task ':app:kaptGenerateStubsDebugKotlin'. > Error while evaluating property 'compilerOptions.jvmTarget' of task ':app:kaptGenerateStubsDebugKotlin'. > Failed to calculate the value of property 'jvmTarget'. > Unknown Kotlin JVM target: 20 * Try: > Run with --stacktrace option to get the stack trace. > Run with --info or --debug option to get more log output. > Run with --scan to get full insights. * Get more help at https://help.gradle.org BUILD FAILED in 18s 19 actionable tasks: 19 executed
jacoco.gradle配置文件
project.afterEvaluate { project -> setupAndroidReporting() } def setupAndroidReporting() { tasks.withType(Test) { // Whether or not classes without source location should be instrumented jacoco.includeNoLocationClasses = true jacoco.excludes = ['jdk.internal.*'] } // Grab all build types and product flavors def buildTypes = android.buildTypes.collect { type -> type.name } def productFlavors = android.productFlavors.collect { flavor -> flavor.name } // When no product flavors defined, use empty if (!productFlavors) productFlavors.add('') productFlavors.each { productFlavorName -> buildTypes.each { buildTypeName -> def sourceName, sourcePath if (!productFlavorName) { sourceName = sourcePath = "${buildTypeName}" } else { sourceName = "${productFlavorName}${buildTypeName.capitalize()}" sourcePath = "${productFlavorName}/${buildTypeName}" } def testTaskName = "test${sourceName.capitalize()}UnitTest" System.out.println("Task -> $testTaskName") // Create coverage task of form 'testFlavorTypeCoverage' depending on 'testFlavorTypeUnitTest' task "${testTaskName}Coverage"(type: JacocoReport, dependsOn: "$testTaskName") { group = "Reporting" description = "Generate Jacoco coverage reports on the ${sourceName.capitalize()} build." def fileFilter = [ // data binding 'android/databinding/**/*.class', '**/android/databinding/*Binding.class', '**/android/databinding/*', '**/androidx/databinding/*', '**/BR.*', // android '**/R.class', '**/R$*.class', '**/BuildConfig.*', '**/Manifest*.*', '**/*Test*.*', 'android/**/*.*', // kotlin '**/*MapperImpl*.*', '**/*$ViewInjector*.*', '**/*$ViewBinder*.*', '**/BuildConfig.*', '**/*Component*.*', '**/*BR*.*', '**/Manifest*.*', '**/*$Lambda$*.*', '**/*Companion*.*', '**/*Module*.*', '**/*Dagger*.*', '**/*Hilt*.*', '**/*MembersInjector*.*', '**/*_MembersInjector.class', '**/*_Factory*.*', '**/*_Provide*Factory*.*', '**/*Extensions*.*', // sealed and data classes '**/*$Result.*', '**/*$Result$*.*', // adapters generated by moshi '**/*JsonAdapter.*', ] def javaTree = fileTree(dir: "${project.buildDir}/intermediates/javac/$sourceName/classes", excludes: fileFilter) def kotlinTree = fileTree(dir: "${project.buildDir}/tmp/kotlin-classes/$sourceName", excludes: fileFilter) classDirectories.from = files([javaTree], [kotlinTree]) executionData.from = files("${project.buildDir}/jacoco/${testTaskName}.exec") def coverageSourceDirs = ["src/main/java", "src/$productFlavorName/java", "src/$buildTypeName/java"] sourceDirectories.setFrom(files(coverageSourceDirs)) additionalSourceDirs.setFrom(files(coverageSourceDirs)) reports { /*csv.enabled false // change if needed xml.enabled false // change if needed html { enabled true destination file("${buildDir}/coverage-report") }*/ xml.required.set(false) csv.required.set(false) html.required.set(true) } } } } } android { buildTypes { debug { testCoverageEnabled true } } }
app模块build.gradle配置文件
apply from: "$project.rootDir/jacoco.gradle" android { namespace 'cc.mekanism.chatconcept' compileSdk 33 packagingOptions { resources.excludes.add("META-INF/LICENSE.md") resources.excludes.add("META-INF/LICENSE-notice.md") } defaultConfig { applicationId "cc.mekanism.chatconcept" minSdk 24 targetSdk 33 versionCode 1 versionName "1.0" testInstrumentationRunner "cc.mekanism.chatconcept.CustomTestRunner" } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } compileOptions { sourceCompatibility JavaVersion.VERSION_17 targetCompatibility JavaVersion.VERSION_17 } kotlinOptions { jvmTarget = '17' freeCompilerArgs = ['-Xjvm-default=compatibility'] } buildFeatures { viewBinding true } sourceSets { main { java { srcDirs += 'build/generated/source/navigation-args' } } } kapt { correctErrorTypes true } testOptions{ unitTests.returnDefaultValues = true } }
解决方法
1. 强制为kapt任务指定JVM Target
报错发生在kaptGenerateStubsDebugKotlin任务,说明kapt未正确继承kotlinOptions中的JVM配置。在app模块的build.gradle中添加以下配置,强制kapt使用JVM 17:
tasks.withType(org.jetbrains.kotlin.gradle.tasks.KaptGenerateStubs) { kotlinOptions { jvmTarget = '17' } }
2. 调整Jacoco配置位置
将jacoco.gradle中android闭包内的testCoverageEnabled配置移到app模块的build.gradle的debug buildType中,避免配置冲突:
// app模块build.gradle的buildTypes闭包内 debug { testCoverageEnabled true }
同时删除jacoco.gradle中的android闭包部分。
3. 检查Gradle与Kotlin插件兼容性
确保使用的Gradle版本和Kotlin插件版本支持JVM 17:
- Gradle版本建议7.4及以上
- Kotlin插件版本建议1.6.0及以上
4. 清理Gradle缓存
执行命令清理缓存并重新构建,排除缓存导致的版本冲突:
./gradlew clean build --refresh-dependencies
内容的提问来源于stack exchange,提问作者Jay Patel
相关产品推荐
相关产品推荐

