Is there some good reason to use api over implementation in gradle when using your own library ? Is there any good reason to use it in some other situation ? I could not find answer in other questions about it. Or its just when you have to because of transition from using of compile ?
Besides your own library one the most relevant situation where I see it useful is when you have a multi-module project. In this kind of projects you most likely end up having modules that have dependencies of other modules and since you might want that gradle recompiles your modules dependencies if there is any change in those modules api is the answer.
api is the equivalent of compile, and implementation was added to improve gradle builds by not having to recompile every dependency but only the ones that needs to be recompiled.
The following articles are a good source of information about it, and they are very concise.
Implementation vs API dependency
Implementation Vs Api in Android Gradle plugin 3.0
Update:
From gradle docs:
The api bucket is used to declare dependencies that should
transitively be visible by downstream consumers when they are
compiled. The implementation bucket is used to declare dependencies
which should not leak into the compile classpath of consumers (because
they are purely internal details).
This means that if your own library wants to expose any dependency to its consumers you should use api. Any dependencies with api in your own library will be part of the compile classpath of the app consuming your own library. With implementation you wont expose the dependencies you are using in your own library to the app that is consuming it.
You can see this being applied in well known libraries like ButterKnife for instance. Where the "core" butterknife module, which is the one the consumer app adds as dependency, is exposing butterknife-annotations to the consumer through api project(':butterknife-annotations'). And this is what allows the consumer use the binding annotations from butterknife such as #BindView.
If the butterknife-annotations were added in butterknife with implementation instead of api, the consumer app will not be able to use those binding annotations. Because the butterknife-annotations will no longer be part of the compile classpath of the consumer app.
I am using gradle dependency of
implementation 'com.google.android.gms:play-services-location:15.0.1'
at runtime I get below error
java.lang.NoClassDefFoundError: Failed resolution of: Lcom/google/android/gms/location/LocationRequest;
I am trying to fetch lat long using LocationRequest and when I am using this code in a standalone project it works. And when I am trying to build a library with same code I get above error.
I have checked, both standalone project and library project have same dependencies and versions.
This maybe because of 2 reasons
1st possible reason
When you used this library directly you used implementation method in build.gradle.
So you can use it directly in simple app module.
When you move it to your library and use that location library using same implementation option that location library can be only used by your library. and can't be used by app module in which you have used your library
Try by replacing that implementation by api for location library like this
api 'com.google.android.gms:play-services-location:15.0.1'
For more details refer this post for implementation vs api - Here
2nd possible reason
As you mentioned in comments, its a runtime error
As per my opinion it maybe because of obfuscation by ProGuard
add that class to keep ProGuard rule like this
-keep class com.google.android.gms.location.** { *; }
So this will stop obfuscation of that Location Request class
The code is working now with below changes (I am still looking for an explnation)
in the library gradle edited to below dependency
compileOnly "com.google.android.gms:play-services-location:15.0.1"
and in the app's gradle file added below dependency
runtimeOnly 'com.google.android.gms:play-services-location:11.6.0'
my guess is, since "compileOnly" takes care of adding the dependency in library and "runtimeOnly" takes care of using that dependency the code works and is able to find LocationRequest class.
P.S adityakamble49 's answer in the thread also helped. Please try that as well as it might work for your case.
I'm getting the following error while trying to use Work Manager. I've migrated my project to AndroidX and all other architecture components are working.
def work_version = "1.0.0-alpha02"
/* Work Manager for Background Tasks */
implementation "android.arch.work:work-runtime:$work_version"
implementation "android.arch.work:work-firebase:$work_version"
I'm quite sure I need some dependencies from the Support Library. But I have no clue which one's they are.
I've tried adding the annotations package since the error says it can't find a class file for RestrictTo$Scope. Still doesn't work.
implementation "com.android.support:support-annotations:28.0.0-alpha1"
You are including a reference to the wrong support library, you want the androidx one.
androidx.annotation
Look in
AndroidX refactoring
you will find
androidx.annotation:annotation:1.0.0-alpha1
to correspond with
com.android.support:support-annotations
Make sure that you have only libraries for one or the other kind in your dependencies (project wide).
I was using okhttp 3.8 with dagger 2.11, it works great. When I changed to okhttp 3.9 I was getting ERROR javax.annotation.Nullable not found.
So by some luck I tried including the dagger-android2.x dependency and that fixed the error.
I understood that If you want to use classes like DaggerActivity or if you want to inject activities or fragments you must include the dagger.android package, but why do I need to include it for OkHttp to be used with Dagger?
Edit: I did some more investigating.
This change in the https://github.com/square/okhttp/commit/d4a9cf4772ae9d8991e58d934dea433798c9b8eb#diff-e88e53bd5c3b6fb1ba650f55b1261052R21
+import javax.annotation.Nullable;
is the problem.I had to include:
implementation 'com.google.code.findbugs:jsr305:3.0.2' to fix the error
Update 2:
I was injecting into my websocket listener, which I really didn't need to do. This caused the ERROR javax.annotation.Nullable not found. I changed my code to not inject into the websocketlistener and the error is gone and no need for additional dependencies, the error was entirely my fault.
You don't actually have to include the dagger-android2.x dependency. What happens is that OkHttp 3.9 now uses the javax.annotation.Nullable, which the dagger-android2.x dependency uses internally and is, therefore, also available for OkHttp through gradle merge.
Adding compile 'com.google.code.findbugs:jsr305:3.0.2' to your project should be enough, as you pointed out.
I'm using Dagger 2 and Kotlin for Android development.
My project is also a multi-module project.
My settings.gradle file is like this:
include :app
include :lib
I'm also maintaining the lib module.
In the Dagger Files (for example in the component), I try to get the item from other module. For example:
#Component
interface AppComponent{
fun getPresenter() : Presenter
}
The Presenter object is defined in lib module. I was working in linux environment and I'm using Android Studio 3 preview canary 5. The code is working well and I am able to generate APK.
But my company wanted to generate the APK using stable version of Android Studio. I'm using Android Studio 2.3.3.
When compiling the Android Project, I encountered this error:
error: error.NonExistentClass
The error appears when
:app:kaptDebugKotlin
is performed and caused by the dagger class cannot found, the class is defined in the other project. What can be the possible workaround for this? Sorry for my bad English.
Just add this to build gradle file to avoid the issues related NonExistentClass
kapt {
correctErrorTypes true
}
https://kotlinlang.org/docs/reference/kapt.html#non-existent-type-correction
The Root Cause
Basically, there's not much that can be done to fix this when using kapt. To quote this link that tackles the same problem in another library that uses pre-processors (OrmaDatabase):
Because Kotlin makes its stubs before Java Annotation Processing runs,
Kotlin knows just nothing about OrmaDatabase, and the name of the
declaration in stubs will be error.NonExistentClass. This breaks the
Annotation Processing tool. It's a kind of kapt limitation
How to fix it (the workaround)
Just use plain apt or annotationProcessor for running Dagger compiler. As soon as I changed:
kapt libs.daggerCompiler
to
annotationProcessor libs.daggerCompiler
in my module level build.gradle file, I was able to get the errors. After you've fixed the errors, you gotta revert the line back to kapt because otherwise dagger classes wouldn't be generated since they're defined in Kotlin.
I had a very similar situation with a NonExistentClass error in a multi-module project using Dagger and turns out I forgot to add the kotlin library dependency. So, just adding it in the sub-module solved my problem:
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$rootProject.kotlinVersion"
tldr: Change kapt to annotationProcessor in build.gradle and you will see the real problem.
I got the same error, and it turned out that I just commented out a class that I was using in my AppComponent. Unfortunately the kapt tool didn't give me the proper error message. If you change the kapt to annotationProcessor at your library's compiler, and try to build, it won't succeed neither, but you will get a more detailed error message.
In my case, I had #Nullable annotation from support-annotations while I had removed it in order to migrate to AndroidX.
When building, because the annotation was not imported correctly, it was detected as invalid.
What I did was to check the code and fix all imports.
After removing the outdated library
implementation 'androidx.hilt:hilt-lifecycle-viewmodel:1.0.0-alpha03'
kapt 'androidx.hilt:hilt-compiler:1.0.0-alpha03'
I got this error:
incompatible types: NonExistentClass cannot be converted to Annotation
Looking at https://dagger.dev/hilt/view-model.html I changed in a ViewModel:
class MainViewModel #ViewModelInject constructor(
...
) : ViewModel() {
to
#HiltViewModel
class MainViewModel #Inject constructor(
...
) : ViewModel() {
I've found if you're using
kapt {
generateStubs = true
}
changing to false will then present the actual error, you will probably have issues building the Dagger Graph once it's compilation issues have been corrected, but simply change back to true, and you should be good
It seems, there is a bug with kapt, project cleaning should help.
./gradlew clean
I got this error when I had moved by mistake a test class into my main sourceset. Moving it back to the test sourceset got rid of the error.
I received this error, when there was a compilation error in my Injected class. Please ensure that there aren't any compilation errors.
For all those arriving like me on this topic with a similar error.
Check your annotation imports.
For me the problem was I had the #MicronautTest annotation same as another test just the wrong one. Somehow intellij seems to think the import is fine while it really is not.
I had
import io.micronaut.test.extensions.junit5.annotation.MicronautTest
yet needed the kotest one.
import io.micronaut.test.extensions.kotest.annotation.MicronautTest
The kapt error is, while technically correct, quite uninformative.
So just check the imports and if they are all correct.
ERROR : error.NonExistentClass
This means there is a problem with providing dependencies( and not the dependency itself!).
Sometimes annotation processor(in this case Dagger) is unable to build dependency graph on the first build iteration due to a provider absence.
For instance: You are passing GlideApp as a parameter in your provider while GlideApp class is not generated yet! So, watch out for your providers for NonExistentClass errors.
I had the same issue recently. As I sometimes commit through the Android Studio (3.4.c6) I use the "Optimize imports" option to remove unused imports. For some reason, it removed the import for the Parcelize annotation.
It appeared the errors after I upgraded the .gradle version.
Upgraded the version for mockito from 2.7.21 to 2.+ fixed the issue for me.
- androidTestCompile "org.mockito:mockito-android:2.7.21" // remove this
+ androidTestCompile "org.mockito:mockito-android:2.+" // add this
If you come across this problem after Android X migration and start loosing your mind here is one thing you can try.
My Case:
Our project had few modules in it, lets call one of them myModuleProject.
After migration to Android X it was compiling and running fine if I run it from android studio, but when code moved to cloud and CI starts build, it was failing with ':myModuleProject:kaptDebugKotlin' and with long list of errors such as
e: /home/circleci/code/myModuleProject/build/tmp/kapt3/stubs/debug/package_name_here/reporter/bindingadapter/SomeBindingAdapterKt.java:14: error: incompatible types: NonExistentClass cannot be converted to Annotation
#error.NonExistentClass()
After two days of nightmare I found that not only root project gradle.properties but also module projects should include following!
android.databinding.enableV2=true
android.useAndroidX=true
android.enableJetifier=true
It seems kapt cannot find the class, or cannot determine which class to use. e.g.
import foo.* // class foo.Abc
import bar.* // annotation bar.Abc
#Abc
class Xyz { ... }
I had a project with Dagger injecting something into Presenters
At one moment I got a persistent
"NonExistentClass.java:3: error: error.NonExistentClass must be INTERFACE" error
The root cause was trivial: a rogue copy of the valid #Inject annotated file with unsatisfied dependencies somehow slipped into the project. How can we find it? The project in Android Studio looks OK.
Look at the error message, it looks like:
/home/alex/AndroidProvects/TopProject/app/build/tmp/kapt3/stubs/onlineDebug/error/NonExistentClass.java:3: error: error.NonExistentClass must be INTERFACE
public final class NonExistentClass {
Search at the compiled by kapt build files in
/home/alex/AndroidProvects/TopProject/app/build/tmp/kapt3/stubs/onlineDebug/app for "NonExistentClass" string
You will find the exact file with the exact unsatisfied Dagger dependency (in my case it was a rogue orphan file in the place where it shouldn't exist)
I had similar issues with dagger. Adding the following helped solve it :
// dagger
implementation dep('com.google.dagger:dagger')
implementation dep('com.google.dagger:dagger-android-support')
implementation dep('com.spotify.dagger.android:dagger')
kapt dep('com.google.dagger:dagger-android-processor')
kapt dep('com.google.dagger:dagger-compiler')