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

请求协助构建Gradle中compileOnly与runtimeOnly的对比示例

我来帮你拆解compileOnly和runtimeOnly的核心区别,以及如何写出能直观体现它们特性的测试代码——你当前的问题其实是用反了它们的使用方式,咱们一步步来调整:

先明确两个依赖配置的核心特性
  • compileOnly:只在编译阶段提供依赖类,编译完成后不会将该依赖打包进最终的APK/产物中。也就是说,编译器能看到这些类,但运行时JVM/Android Runtime找不到它们。
  • runtimeOnly:只在运行阶段提供依赖类,编译阶段编译器完全看不到这些类,不会参与编译检查,但会被打包进最终产物,运行时可以正常加载。
调整你的测试示例,直观体现差异

保持你原有的app.gradle依赖配置不变:

dependencies {
    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$rootProject.kotlin_version"
    implementation 'androidx.appcompat:appcompat:1.1.0'
    implementation 'androidx.core:core-ktx:1.2.0'
    compileOnly project(":compileonlylibrary")
    runtimeOnly project(":runtimeonlylibrary")
}

1. 针对compileOnly的正确测试示例

在compileonlylibrary中定义一个接口或注解(这类只在编译时需要定义,运行时不需要依赖原类的内容):

// compileonlylibrary/src/main/kotlin/.../CompileOnlyInterface.kt
interface CompileOnlyInterface {
    fun performAction()
}

// 或者定义一个编译时注解
@Target(AnnotationTarget.FUNCTION)
annotation class LogMethod

然后在MainActivity中使用这些编译时可见的内容:

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        // 1. 使用compileOnly的接口:编译时能识别接口,可正常编写实现
        val myImplementation = object : CompileOnlyInterface {
            override fun performAction() {
                Log.d("CompileOnlyTest", "Action performed from local implementation")
            }
        }
        myImplementation.performAction() // 运行时正常执行,因为我们的代码里包含了实现逻辑

        // 2. 使用compileOnly的注解:编译时生效,运行时不需要注解类存在
        logTest()
    }

    @LogMethod // 编译时编译器能识别这个注解,不会报错
    private fun logTest() {
        Log.d("CompileOnlyTest", "Annotated method called")
    }
}

这里的关键是:compileOnly的依赖只用于编译阶段的语法检查/接口定义,运行时我们不需要依赖原库的类——因为我们自己的代码已经实现了接口,或者注解只是编译时用的标记。

2. 针对runtimeOnly的正确测试示例

在runtimeonlylibrary中定义一个普通类:

// runtimeonlylibrary/src/main/kotlin/.../BarRuntime.kt
class BarRuntime {
    fun sayHello() = "Hello from runtime-only library!"
}

然后在MainActivity中通过反射调用这个类(因为编译时编译器看不到BarRuntime,不能直接实例化):

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)

    // ... 前面compileOnly的代码 ...

    // 使用runtimeOnly的类:通过反射加载,编译时不需要直接引用
    try {
        // 注意替换成你实际的类全限定名
        val barClass = Class.forName("com.example.runtimeonlylibrary.BarRuntime")
        val barInstance = barClass.newInstance()
        val sayHelloMethod = barClass.getMethod("sayHello")
        val result = sayHelloMethod.invoke(barInstance) as String
        Log.d("RuntimeOnlyTest", result) // 运行时正常输出,因为runtimeOnly依赖已打包进APK
    } catch (e: Exception) {
        Log.e("RuntimeOnlyTest", "Failed to call BarRuntime", e)
    }
}

这里的关键是:runtimeOnly的类编译时不可见,所以不能直接写BarRuntime(),但运行时因为依赖被打包了,反射可以正常加载并调用。

总结你的原有问题
  • 你直接实例化FooCompile():因为compileOnly依赖不会被打包,运行时找不到这个类,所以崩溃。
  • 你直接写BarRuntime():因为runtimeOnly依赖编译时不可见,编译器找不到这个类,所以编译报错。

通过上面的调整,就能清晰看到两个配置的差异啦!

内容的提问来源于stack exchange,提问作者Ricardo

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.07 15:37:27