(This is basically the same question as in Android: library project with Retrofit results in NoClassDefFoundError but for play-services-auth).
I'm trying to build an android library project which uses play-services-auth to access SmartLock for Passwords.
It seems to be working as long as I use api instead of implementation on my gradle-dependency for com.google.android.gms:play-services-auth. It seems that this is the only dependency needing this (all others can used with implementation).
When using implementation here as well, the calling app will crash with NoClassDefFoundError:
java.lang.NoClassDefFoundError: Failed resolution of: Lcom/google/android/gms/common/api/GoogleApiClient$Builder;
I'm using consumerProguardFiles with a bunch of proguard-rule-files (e.g. one for okhttp3, retrofit2 etc. from this repo). All this will then be packed into an AAR, so rules from the dependencies should be added as well.
It seems that I'm missing a proguard-rule for play-services-auth. Can somebody post the rules needed to use com.google.android.gms:play-services-auth in a library project?
Related
I've recently migrated my project to use AndroidX
My apps crashes, after I migrate to AndroidX, due to library still using Support Library. Here's a list of my 3rd-party dependencies/library, that failed to transform into AndroidX:
com.clevertap.android:clevertap-android-sdk:3.4.2
com.readystatesoftware.chuck:library:1.1.0
com.ncapdevi:frag-nav:2.4.0
jp.wasabeef:recyclerview-animators:2.3.0
com.github.chivorns:smartmaterialspinner:1.1.6
com.facebook.android:facebook-android-sdk:5.0.1
com.github.PierfrancescoSoffritti:AndroidYouTubePlayer:7.0.1 (I still cannot upgrade it to 10.x.x, because major API changes)
com.github.nikartm:image-support:1.0.5
My Setups:
AS & AGP: 3.6.2
targetSdk: 29
minSdk: 16
Data & View Binding: Both enabled
Gradle DSL: Kotlin
Gradle: gradle-6.0.1-all
What I've done so far:
Using Refactor -> Migrate to AndroidX tools from Android Studio, but ended-up force close it, because takes a long time
android.enableJetifier=true & android.useAndroidX=true
Using the shell scripts to manually mapping artifact, class and imports from Support Library to AndroidX, thanks #Danlew, also #Danlew mentioned in ADS '19 talks here
Already checked my :app:dependencies that 3rd-party dependencies already migrated to use AndroidX artifacts, but only a few of them (failed for the above dependencies list)
Deleting ./root_project/.idea, ./root_project/.gradle & ~/.gradle/caches (to fix compile-error/IDE error, references: AndroidX migrate dependency / libraries
Understanding the jetifier: What is Jetifier? & official android docs
Did a workaround to use AndroidX for annotation processor like: Glide & Dagger
Checking the ~/.gradle directories for the jetified-* libs the jetified aar exist, unfortunately it's failed for clevertap & others libs listed above.
My conclusions, the jetifier works by rewriting the binary .class of our 3rd-party library if Support Library imports/class detected, and modify (jetified/mapping it) into AndroidX respectively.
But in my case, the dependencies listed above doesn't use correct AndroidX imports and resulting runtime crash, due to having a transitive dependent for Support Library.
Does jetifier currently doesn't support transitive dependency inside 3rd-party library as well? But, strangely it works for a few library (unlisted from above)
[UPDATED 1]
In the meantime (quickfix):
I did downloading all the transitive dependencies of the libraries exhaustively one-by-one
Using jetifier-standalone commands instead for the libraries aar
Manually adding the libraries aar and its dependencies to app/build.gradle.kts as flatDirs
Is this really a workaround, is there anything better I can do?
[UPDATED 2]
I've using a maintained version of chuck as well. But found this same issue as well:
cannot generate view binders com.sun.tools.javac.code.Symbol$CompletionFailure: class file for android.support.v7.widget.AppCompatImageView not found
After checking my 3rd-party libs, I also ended-up manually adding the aar after I use jetifier-standalone for this library:
com.clevertap.android:clevertap-android-sdk:3.4.2
com.github.nikartm:image-support:1.0.5
Many also recommends to use api instead of implementation but for me, I don't want to bloated my project with transitive dependency
In other SO also recommends below:
either remove the library,
forked it to support androidx / waiting for the author to upgrade it
manually using jetifier-standalone for those specicif libs, and include as local aar (this is my best approach, right now)
Unless the jetifier able to state this into official documentation, for its limitation: https://developer.android.com/jetpack/androidx/releases/jetifier
Seems like there's the least we can do, and hope, many of the 3rd-party authors will upgrade to AndroidX soon.
Here's a bonus article for references:
You can use can-i-drop-jetifier libs to detects does your libs (transitively) needs jetifier enabled or not
The time is right to migrate to AndroidX with this baby-steps
Better structure packaging with AndroidX and also a headache along the way
Turns out my current workaround was using this approach: https://github.com/bumptech/glide/issues/3080#issuecomment-495430590
Magical regex to turns a blacklist into a whiteliset
android.jetifier.blacklist=^(?!.*[\\\\/](com\\.github\\.bumptech\\.glide|com\\.clevertap\\.android|com\\.facebook\\.android|com\\.github\\.nikartm|com\\.github\\.PierfrancescoSoffritti|com\\.github\\.prolificinteractive)[\\\\/]).*$
If NoClassDef exceptions thrown, then I add the library package name into the android.jetifier.blacklist to whitelisted them.
In the above cases, I'm trying to whitelist:
glide
clevertap
nikartm
facebook-sdk
YoutubeAndroidPlayer (v7) still not using v10
prolificinteractive
I have an internal library hosted on a maven repo. And it is being downloaded successfully and I am able to access it. But once I run the code, it crashes saying that the retrofit library that my library uses cannot be found.
Although the build was successful when deploying the internal library and it works when I run it through the code of the library by including it as a submodule rather than a maven dependency.
EDIT
Ok. So I was able to fix the crash by including the retrofit library in my main project as a dependency as well (which was weird)
But now I am confused regarding "implementation" and "api" in gradle file.
My Understanding was that if I have built a library using retrofit as "implementation", making available my library through maven. That retrofit library will be available when some use my library. But it seems like if you use "implementation", you have to explicitly include that retrofit library in your project dependency as well.
Should I be using "api" so that my library automatically includes retrofit so that the main project doesn't require it to be added?
I know the difference between the two as discussed here.
As Android developer,
Why I should care about this?
In gradle, why should I use compileOnly vs implementation/api?
Why I should care about this?
To make your apps build but not ship with unnecessary stuff.
In gradle, why should I use compileOnly vs implementation/api?
The documentation for compileOnly gives one use case as an example:
Gradle adds the dependency to the compilation classpath only (it is not added to the build output). This is useful when you're creating an Android library module and you need the dependency during compilation, but it's optional to have present at runtime. That is, if you use this configuration, then your library module must include a runtime condition to check whether the dependency is available, and then gracefully change its behavior so it can still function if it's not provided. This helps reduce the size of the final APK by not adding transient dependencies that aren't critical. This configuration behaves just like provided (which is now deprecated).
source
For example, consider a push messaging library that supports both Firebase FCM and Amazon ADM but does not require either. It would unnecessarily bloat apps if it would ship with both as transitive dependencies. With compileOnly the library can still be built. Developers using the library can select which dependencies to actually use.
Another example could be compile-time annotations that do not need to ship with the application.
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.
Previously my gradle used to look like this and worked fine (apart from few registered bugs)
implementation 'com.dji:dji-sdk:4.3.2'
Now, after changing to
implementation 'com.dji:dji-sdk:4.4.0'
the Camera and other files cannot be recognized anymore. I am attaching a screenshot of the unrecognized imports.
However when I am trying to add
//dji-drones-sdk
implementation 'com.dji:dji-sdk:4.4.0'
provided 'com.dji:dji-sdk-provided:4.4.0'
I am getting "could not download dji-sdk-provided.jar"
Screenshot attached
All the examples and github codes are in version 4.3.2. Can anyone help me out?
Here is the link to the dji sdk
I have found the issue. After Gradle 3.4, the "provided" is replaced by "compileOnly"
I quote,
Gradle adds the dependency to the compilation classpath only (it is not added to the build output). This is useful when you're creating an Android library module and you need the dependency during compilation, but it's optional to have present at runtime. That is, if you use this configuration, then your library module must include a runtime condition to check whether the dependency is available, and then gracefully change its behavior so it can still function if it's not provided. This helps reduce the size of the final APK by not adding transient dependencies that aren't critical. This configuration behaves just like provided (which is now deprecated).
Hence using compileOnly in place of provided will do the trick.
Here is a link to the gradle changes documentation