-
Notifications
You must be signed in to change notification settings - Fork 2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[ksp] Dagger fails to resolved ViewBinding classes generated by the Android Gradle plugin #4049
Comments
ViewBinding is a KAPT processor and thus not compatible with KSP processors, essentially you are running into the issue described here: https://dagger.dev/dev-guide/ksp#interaction-with-javackapt-processors. See also google/ksp#1388. |
ViewBinding does not rely on KAPT. It is its own code-generating task created by AGP. |
Ups! I was thinking of DataBinding then which I believe has an annotation processor component that runs in KAPT for Kotlin sources. Sorry for the confusion. 😅 So, ViewBinding being a task in AGP then my guess is that it needs some extra wiring so that generates classes are part of KSP's inputs. I'll ask AGP team and investigate more... |
I've made a simple minimum reproducible app, in case it helps: https://github.com/ZOlbrys/HiltKspViewBindingTestApp The error only happens when you use view bindings in a generic manner, FWIW. |
Hey @danysantiago Glad to hear that you are investigating this issue. Is there any progress on this one? |
any updates on this one? thank you! |
The AGP team is looking into it: https://issuetracker.google.com/301245705 |
We're working on a proper fix for the issue by exposing an API for generated java sources by the android gradle plugin to be consumed by KSP gradle plugin. Meanwhile, you can add the following snippet to your build file as a workaround to wire databinding/viewbinding generated classes to the ksp task.
|
While this didn't quite work for me right away, it did highlight what I needed to do to get things working in my case. Sincere thanks for the stopgap solution @AmrAfifiy 🙏 Here's the modified code that fit my situation: androidComponents {
onVariants(selector().all(), { variant ->
afterEvaluate {
// This is a workaround for https://issuetracker.google.com/301245705 which depends on internal
// implementations of the android gradle plugin and the ksp gradle plugin which might change in the future
// in an unpredictable way.
def dataBindingTask = (DataBindingGenBaseClassesTask) project.tasks.named("dataBindingGenBaseClasses" + variant.name.capitalize()).get()
if (dataBindingTask != null) {
project.tasks.getByName("ksp" + variant.name.capitalize() + "Kotlin") {
((AbstractKotlinCompileTool) it).setSource(dataBindingTask.sourceOutFolder)
}
}
}
})
} The main difference included here was picked up by a user on IssueTracker, who raised a very valid point that not all modules that apply the ksp plugin use view binding. So with that in mind, it makes sense to optionally process I hope that helps! |
There is a workaround for those who are facing a simular issue with AIDL using: // Workaround for https://github.com/google/dagger/issues/4158
androidComponents {
onVariants(selector().all(), { variant ->
afterEvaluate {
def capName = variant.name.capitalize()
tasks.getByName("ksp${capName}Kotlin") {
setSource(tasks.getByName("compile${capName}Aidl").outputs)
}
}
})
} Originally posted by @Goooler in #4158 (comment) |
Facing the same issue with a custom plugin that generates Kotlin files and registers them using val androidComponents = project.extensions.getByType(AndroidComponentsExtension::class.java)
androidComponents.onVariants { variant ->
val task = project.tasks.register("myTask${variant.name.capitalized()}", MyKotlinGeneratingTask::class.java)
variant.sources.java!!.addGeneratedSourceDirectory(task) { it.outputDirectory }
} Dagger KSP processor as of 2.48.1/KSP 1.0.13 cannot resolve any type generated by the custom task. |
Is there a version of snippet in Kotlin DSL? I am not really sure how to apply the Kotlin sample from the issue tracker. Thanks |
Something like the following should work for you as a Kotlin DSL: import com.android.build.gradle.internal.tasks.databinding.DataBindingGenBaseClassesTask
import org.gradle.api.UnknownTaskException
import org.jetbrains.kotlin.gradle.tasks.AbstractKotlinCompileTool
extensions.configure<LibraryAndroidComponentsExtension> {
onVariants { variant ->
afterEvaluate {
project.tasks.getByName("ksp${variant.name.capitalize()}Kotlin") {
val dataBindingTask =
try {
val taskName = "dataBindingGenBaseClasses${variant.name.capitalize()}"
project.tasks.getByName(taskName) as DataBindingGenBaseClassesTask
} catch (e: UnknownTaskException) {
return@getByName
}
project.tasks.getByName("ksp${variant.name.capitalize()}Kotlin") {
(this as AbstractKotlinCompileTool<*>).setSource(dataBindingTask.sourceOutFolder)
}
}
}
}
} |
Which part of the |
Ah, apologies. I have this configured as a plugin. As a pure DSL within your app's import com.android.build.gradle.internal.tasks.databinding.DataBindingGenBaseClassesTask
import org.gradle.api.UnknownTaskException
import org.jetbrains.kotlin.gradle.tasks.AbstractKotlinCompileTool
androidComponents {
onVariants(selector().all()) { variant ->
afterEvaluate {
project.tasks.getByName("ksp${variant.name.capitalize()}Kotlin") {
val dataBindingTask =
try {
val taskName = "dataBindingGenBaseClasses${variant.name.capitalize()}"
project.tasks.getByName(taskName) as DataBindingGenBaseClassesTask
} catch (e: UnknownTaskException) {
return@getByName
}
project.tasks.getByName("ksp${variant.name.capitalize()}Kotlin") {
(this as AbstractKotlinCompileTool<*>).setSource(dataBindingTask.sourceOutFolder)
}
}
}
}
} |
This work, thanks a lot! |
As others pointed out, this is not an issue only of View Binding. BuildConfig, SafeArgs, AIDL, etc. are affected just the same. Here's a script covering all of them. /*
* AGP tasks do not get properly wired to the KSP task at the moment.
* As a result, KSP sees `error.NonExistentClass` instead of generated types.
*
* https://github.com/google/dagger/issues/4049
* https://github.com/google/dagger/issues/4051
* https://github.com/google/dagger/issues/4061
* https://github.com/google/dagger/issues/4158
*/
androidComponents {
onVariants(selector().all()) { variant ->
afterEvaluate {
val variantName = variant.name.capitalize()
val ksp = "ksp${variantName}Kotlin"
val viewBinding = "dataBindingGenBaseClasses$variantName"
val buildConfig = "generate${variantName}BuildConfig"
val safeArgs = "generateSafeArgs$variantName"
val aidl = "compile${variantName}Aidl"
val kspTask = project.tasks.findByName(ksp)
as? org.jetbrains.kotlin.gradle.tasks.AbstractKotlinCompileTool<*>
val viewBindingTask = project.tasks.findByName(viewBinding)
as? com.android.build.gradle.internal.tasks.databinding.DataBindingGenBaseClassesTask
val buildConfigTask = project.tasks.findByName(buildConfig)
as? com.android.build.gradle.tasks.GenerateBuildConfig
val aidlTask = project.tasks.findByName(aidl)
as? com.android.build.gradle.tasks.AidlCompile
val safeArgsTask = project.tasks.findByName(safeArgs)
as? androidx.navigation.safeargs.gradle.ArgumentsGenerationTask
kspTask?.run {
viewBindingTask?.let { setSource(it.sourceOutFolder) }
buildConfigTask?.let { setSource(it.sourceOutputDir) }
aidlTask?.let { setSource(it.sourceOutputDir) }
safeArgsTask?.let { setSource(it.outputDir) }
}
}
}
} |
thanks,it work for me! |
Thanks! You might also want to add these lines if you use protobuf (with datastore for example) androidComponents {
onVariants(selector().all()) { variant ->
afterEvaluate {
//...
val proto = "generate${variantName}Proto"
//...
val protoTask = project.tasks.findByName(proto)
as? com.google.protobuf.gradle.GenerateProtoTask
kspTask?.run {
//...
protoTask?.let { setSource(it.outputSourceDirectorySet) }
}
}
}
} |
AGP issue fixed: Can confirm, issue not reproduce anymore with ksp 1.9.22-1.0.18 |
I've just updated to this version to check out if it works, but unfortunately I still have the same error:
My
and I've tried the workarounds too (adapted to |
I have the same error. Any updates on this? |
I have the same error as @rekaszeru . Any updates on this? |
AFAIK, this is not a Dagger issue. However, there's a number of workarounds listed above, e.g. #4049 (comment). |
@bcorso , like @rekaszeru said, we have tried the workarounds. Specifically this was what I put in my Convention plugin: configure<LibraryAndroidComponentsExtension> {
onVariants { variant ->
afterEvaluate {
val variantName = variant.name.capitalize()
val kspTaskName = "ksp${variantName}Kotlin"
println("kspTaskName: $kspTaskName")
val wireTaskName = "generate${variantName}Protos"
val kspTask = project.tasks.findByName(kspTaskName) as? AbstractKotlinCompileTool<*>
val wireTask = project.tasks.findByName(wireTaskName) as? WireTask
kspTask?.run {
wireTask?.let {
// itSource: SomeClass.proto
println("itSource: ${it.source.files.joinToString { it.name }}")
setSource(it.source)
}
}
}
}
} And yet dagger ksp chokes when it can't find "SomeClass". Edit: Wait, why would .proto be in the source that we want to set for kspTask? |
AFAICT, @rekaszeru never directly confirmed if they tried the workaround or not. My interpretation of #4049 (comment) was that they tried upgrading to the new KSP version mentioned in #4049 (comment). Like I said, this isn't really a Dagger issue. This is an AGP/KSP issue and it just fails in Dagger because they aren't getting the ordering/wiring of generation correct.
As mentioned in #4049 (comment), this issue shows up with a number of different libraries like Protobuf, View Binding, BuildConfig, SafeArgs, AIDL, etc. so you have to make sure the workaround you use includes the library you need. |
@rekaszeru configure<LibraryAndroidComponentsExtension> {
onVariants { variant ->
afterEvaluate {
val variantName = variant.name.capitalize()
val kspTaskName = "ksp${variantName}Kotlin"
val wireTaskName = "generate${variantName}Protos"
val kspTask = project.tasks.findByName(kspTaskName) as? AbstractKotlinCompileTool<*>
val wireTask = project.tasks.findByName(wireTaskName) as? WireTask
kspTask?.run {
wireTask?.let {
dependsOn(it) // It chokes if you try to setSource without `dependsOn`, so I guess we need both.
setSource(it.outputDirectories)
}
}
}
}
} Are you able to verify? |
is this still valid after google/ksp#1739 ? |
@guness While that fix may fix some of the code generators, I believe this has to be fixed/checked on a generator by generator basis as it depends on where the outputs of those generators go. We can't really test with all of the different generators out there, so you'll probably want to check in your project for the ones you use, and if still running into issues, wire up the tasks as described above. |
I have a class that uses ViewBinding as a generic parameter:
DownloadsListBinding
is a class generated from a xml layout resource by the Android Gradle Plugin, and everything is working fine with kapt, but when trying to use KSP, the compilation fails with the following error:Versions:
Gradle Plugin version: 8.1.1
Kotlin: 1.9.10
KSP: 1.9.10-1.0.13
Hilt: 2.48
The text was updated successfully, but these errors were encountered: