You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

添加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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 23:28:09