When do I need to use Kapt in Gradle dependencies?
Usually, libraries interact with annotations in one of these two ways:
- Using reflection. Library code can query annotations at runtime to perform certain logic. These libraries would normally be packaged as a single artifact and would not require using
kapt
orannotationProcessor
. Example: Retrofit, which accesses annotations using reflection and doesn't include an annotation processor. - Using an annotation processor. Annotation processors are compiler plugins that get invoked before the main compilation step, can access annotations and the code around them, and perform tasks based on this input. Annotation processors usually come in separate artifacts since they contain code that is not needed at runtime, hence it shouldn't be packaged into your APK. Example: Butterknife, which processes annotations during compilation and comes with a separate
butterknife-compiler
module that contains the annotation processor. You should usebutterknife-compiler
as akapt
orannotationProcessor
dependency, and notimplementation
,api
orcompile
, since you don't need the annotation processor during runtime.
To answer your question, there's no generic way to know whether a library that relies on annotations comes with an annotation processor. You should check the documentation for the specific library and follow installation instructions.
Annotations (e.g. @Something
) are basically labels for code. You mark one part of the code so that some other code can find those markings.
This "other code" is usually an Annotation Processor. It finds annotations and does something with code marked with those annotations. E.g. it can generate new code (like Dagger, Butterknife, etc.).
Depending on the way you introduce dependencies in your project, (depending on the keyword
you use - implementation
, api
, compileOnly
, runtimeOnly
, annotationProcessor
, kapt
, etc.), the dependency will be used by your project differently.
If you use annotationProcessor
, your dependency will not be packed within your app, but will be used during the compilation of your app.
You don't want to pack the compiler (the code that handles @AnAnnotation
) within your app, since it's just used to properly prepare the code of your app (and is never used within your application in Runtime).
Think of it this way:
If you're going on a train and you need to print a train ticket, you don't want to carry a printer with you on the train. After the printer is done printing the ticket, you take the ticket and go on the train. Printer has done its job already. You can leave it.
If you mark some code with @AnAnnotation
you just want the library that handles that annotation to do its job and disappear. Hence the special type of a dependency - annotationProcessor
.
Now about kapt
. This is simple. If you want to use Annotation Processors in projects with Kotlin code, just use kapt
instead of annotationProcessor
. Think of it as annotationProcessor
with Kotlin support.
Some libraries use @Annotations
differently. They do not cause any code to be generated in compile-time, but they use annotations in runtime.
Those are usually reflection-based libraries that "look through" the code in Runtime. Just like Retrofit is looking through your interface
when your app is executed.
That's why you include a library with @Annotations
normally within your application, and those annotations are packed within your apk for Runtime operation.
Summerizing:
annotationProcessor
and kapt
keywords, are to help you specify how dependencies will be used in your project.
If you want to introduce a library that uses annotations and generates some code, use kapt
not to "bloat" your apk with code that already has done its job, and will never be used again.