Problem:
Up until now I've been using Gradle to handle all of my dependencies, and it seems to take care of any duplicate dependencies between other Gradle modules. However, this does not seem to be the case when a duplicate dependency exists within a jar.
Question:
Considering that I have control over what goes into the jar, What is the best practices for handling these dependency conflicts using Gradle:
Do not include any external dependencies in the jar, include them in the project itself using build.gradle
Include all external dependcies in the jar, remove duplicates as they occur by removing them from the project build.gradle. (NOTE: this does not seem scalable, e.g. if there are duplicates between jars themselves.)
Something better (that hopefully handles this automatically)
EDIT: build.gradle file:
apply plugin: 'com.android.application'
android {
signingConfigs {
release { ... }
debug { ... }
}
compileSdkVersion 19
buildToolsVersion '19.1.0'
defaultConfig { ... }
buildTypes {
release { ... }
debug { ... }
}
sourceSets {
instrumentTest.setRoot('tests')
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile 'com.android.support:support-v4:20.0.0'
compile project(':jarModule')
}
When importing external jars that have a dependency that you also have in your local app, you can do two things:
Convert your jar dependency to a Gradle dependency and exclude the dependency
For example:
testCompile('org.robospock:robospock:0.5.0') {
exclude module: "groovy-all" // <-- excludes groovy from robo spock
}
or
Remove the local dependency in your app and rely on the one in the .jar
For example, in your case with Gson:
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile 'com.android.support:support-v4:20.0.0'
compile project(':jarModule')
// compile 'com.google.code.gson:gson:2.3.1' // <-- removed
}
Related
I have a Java module that generates some metadata for my Android app and needs to run as a regular Java application. After updating to Android Studio 3.0 (in 2.3.3 it worked as expected) I get a NoClassDefFoundError for the dependencies (in the case below for com/google/gson/GsonBuilder, the main method itself can be found).
I even tried putting the GSON Jar into the libs folder but it still throws the NoClassDefFoundError.
I assume the dependencies are not properly included. Any idea how to fix this?
The build.gradle looks like this:
apply plugin: 'java'
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'com.google.code.gson:gson:2.8.1'
}
sourceCompatibility = "1.7"
targetCompatibility = "1.7"
My class looks like this:
import com.google.gson.GsonBuilder;
public class myClass {
public static void main(String[] args) {
GsonBuilder builder = new GsonBuilder();
}
}
Use api instead of implementation.
From the docs
When your module configures an implementation dependency, it's
letting Gradle know that the module does not want to leak the
dependency to other modules at compile time. That is, the dependency
is available to other modules only at runtime.
Using this dependency
configuration instead of api or compile can result in significant
build time improvements because it reduces the amount of projects that
the build system needs to recompile. For example, if an implementation
dependency changes its API, Gradle recompiles only that dependency and
the modules that directly depend on it. Most app and test modules
should use this configuration.
See difference between api and implementation here for more info.
This is a problem probably related with Android Gradle plug-in. Try using compile instead of implementation in yourbuild.gradle`:
apply plugin: 'java'
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile 'com.google.code.gson:gson:2.8.1'
}
sourceCompatibility = "1.7"
targetCompatibility = "1.7"
The above is working in Android Studio 3.0 but with Android Gradle plug-in 2.3.3 in root build.gradle:
classpath 'com.android.tools.build:gradle:2.3.3'
UPDATE
I manage to make it works by adding google() to repositories block in root build.gradle. The following build.gradle is for the Java module:
apply plugin: 'java'
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'com.google.code.gson:gson:2.8.1'
}
sourceCompatibility = "1.8"
targetCompatibility = "1.8"
And this is my root build.gradle:
buildscript {
repositories {
jcenter()
google()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.0.0'
classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.7.3'
classpath 'com.github.dcendents:android-maven-gradle-plugin:1.5'
}
}
allprojects {
repositories {
jcenter()
google()
}
}
Tested on Android Studio 3.0 with Gradle 4.1.
I've created my game with Lib-GDX and I'm almost done! :D
the problem is that I forgot to include one of the Third Party feature in the initial GDX setup. Is there any way I can go back and include it, using the gds-setup.jar or any other way? Or must I go the super advanced way and create a new project and include the feature?
To be more precise I'm trying to include the libGDX cross platform Facebook support
You can just add your 3d party stuff to the build.gradle file for your case your need this :
compile "de.tomgrill.gdxfacebook:gdx-facebook-core:1.1.1"
to be added to the dependencies, there is no need of creating new project with gdx-setup.jar
check this topic in the officiel wiki for more info :
Dependency management with Gradle
I just created a new project with gdx-setup.jar and added the Third Party Ext. I wanted. Once that was complete i copied the code that called the TPE in the gradle files and added them to my original game's gradle so for Example:
project(":android") {
apply plugin: "android"
configurations { natives }
dependencies {
compile project(":core")
compile "de.tomgrill.gdxfacebook:gdx-facebook-android:1.1.1"//this is what I needed to add
compile fileTree(dir: 'libs', include: '*.jar')
}
}
project(":core") {
apply plugin: "java"
dependencies {
compile "de.tomgrill.gdxfacebook:gdx-facebook-core:1.1.1"//this was what I needed to add
compile fileTree(dir: 'libs', include: '*.jar')
}
}
this was all in the main project's gradle folder.
I'm developing an app that uses GoogleAPIClient to (obviously) get the user current location in background.
For this task I use IntentService with WakefulBroadcastReceiver (to get the location every hour). Everything was working fine on development environment but when deployed in Play Store some devices are getting this error:
Fatal Exception: java.lang.NoClassDefFoundError: com/google/android/gms/internal/zzsa
at com.google.android.gms.common.api.GoogleApiClient$Builder.<init>(Unknown Source)
at tellerina.com.br.vivara.services.MyService.onHandleIntent(MyService.java:37)
at android.app.IntentService$ServiceHandler.handleMessage(IntentService.java:65)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:157)
at android.os.HandlerThread.run(HandlerThread.java:61)
I have searched the internet for answers but I didn't find anything. Here's the point where the exception appears:
mGoogleApiClient = new GoogleApiClient.Builder(MyApplication.getContext())
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
Thanks a lot!
EDIT
app build.gradle
buildscript {
repositories {
maven { url 'https://maven.fabric.io/public' }
}
dependencies {
classpath 'io.fabric.tools:gradle:1.21.2'
}
}
apply plugin: 'com.android.application'
apply plugin: 'io.fabric'
android {
compileSdkVersion 23
buildToolsVersion "23.0.2"
defaultConfig {
applicationId "app.package"
minSdkVersion 14
targetSdkVersion 22
versionCode 9
versionName "1.5.2"
multiDexEnabled true
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
dexOptions {
javaMaxHeapSize "4g"
}
}
repositories {
mavenCentral()
maven { url 'https://maven.fabric.io/public' }
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile fileTree(dir: 'libs', include: ['*.so'])
compile(project(':volley')) {
exclude module: 'support-v4'
}
compile files('libs/commons-codec-1.9.jar')
compile('com.navercorp.volleyextensions:volley-views:2.0.+') {
exclude module: 'library'
}
compile('com.crashlytics.sdk.android:crashlytics:2.5.5#aar') {
transitive = true;
}
compile 'com.android.support:appcompat-v7:23+'
compile 'com.android.support:cardview-v7:23+'
compile 'com.android.support:recyclerview-v7:23+'
compile 'com.google.code.gson:gson:2.3.1'
compile 'io.card:android-sdk:5.1.1'
compile 'com.github.ksoichiro:androidpagecontrol:0.1.1'
compile 'me.relex:circleindicator:1.1.5#aar'
compile 'com.nineoldandroids:library:2.4.0'
compile 'com.daimajia.easing:library:1.0.1#aar'
compile 'com.daimajia.androidanimations:library:1.1.3#aar'
compile 'com.facebook.android:facebook-android-sdk:4.5.0'
compile 'br.com.jansenfelipe:androidmask:1.0.1'
compile 'com.google.android.gms:play-services:8.4.0'
compile 'com.android.support:multidex:1.0.0'
compile 'com.android.support:design:23+'
compile 'com.squareup.picasso:picasso:2.5.2'
}
apply plugin: 'com.google.gms.google-services'
Root project build.gradle
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:1.5.0'
classpath 'com.google.gms:google-services:+'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
repositories {
jcenter()
}
}
EDIT 2
Using Fabric, now I can see that all of users affected by this problem is using Android 4.x. Maybe the distribution of Play Services is bugged, I don't know. But it's decreasing the number of devices with this error.
You are getting
Fatal Exception: java.lang.NoClassDefFoundError:
com/google/android/gms/internal/zzsa
at com.google.android.gms.common.api.GoogleApiClient$Builder.(Unknown
Source)
NoClassDefFoundError in Java comes when Java Virtual Machine is not able to find a particular class at runtime which was available during compile time.
OLD
dependencies {
// classpath 'com.android.tools.build:gradle:1.5.0'
// classpath 'com.google.gms:google-services:+' //(Avoid Calling "+")
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
GoogleApiClient is used with a variety of static methods. Some of
these methods require that GoogleApiClient be connected, some will
queue up calls before GoogleApiClient is connected;
mGoogleApiClient = new GoogleApiClient.Builder(this)
You should try with your build.gradle
Top-level build file where you can add configuration options common to
all sub-projects/modules.
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:2.0.0-beta2'
classpath 'com.google.gms:google-services:2.0.0-beta2'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
repositories {
jcenter()
}
}
Advice
you can call
compile 'com.android.support:appcompat-v7:23.1.1' instead of
v7:23+
Then Clean-Rebuild-Restart-Sync Your Project .Hope this helps .
Edit
The Android build system consists of an Android plugin for Gradle.
Gradle is an advanced build toolkit that manages dependencies and
allows you to define custom build logic. Android Studio uses a Gradle
wrapper to fully integrate the Android plugin for Gradle. The Android
plugin for Gradle also runs independent of Android Studio.
A plugin is simply any class that implements the Plugin interface. Gradle provides the core plugins as part of its distribution so simply applying the plugin as above is all you need to do.
with beta2 and alpha-5 gradle dosen't show error. But without "apply
plugin: 'services'" and 'classpath' it's not generated
gcm_defaultSenderId for GCM
You can check Get an Instance ID
You should use apply plugin .
This is clearly a proguard configuration error of gms (Google Play Services).
Either it's caused by a wrong version that you build against, and you can build against another one.
Or it's caused by the Play Services installed on the device, and you can only hope that the Play Services team has stopped roolout of this version until the bug is fixed.
FINALLY! I spent literally several hours trying to resolve this issue, maybe it has already been resolved but it turns out any of the google classes you use have to all be the SAME VERSION in the gradle, i.e.
compile 'com.google.android.gms:play-services-identity:7.8.0'
compile 'com.google.android.gms:play-services-location:7.5.0'
I was calling two different versions. Once I chanced it to this:
compile 'com.google.android.gms:play-services-identity:7.8.0'
compile 'com.google.android.gms:play-services-location:7.8.0'
the classdeferror was resolved!
I have Android Studio library project which has it's own Gradle dependencies:
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
testCompile 'junit:junit:4.12'
compile 'com.squareup.retrofit:retrofit:2.0.0-beta2'
compile 'com.squareup.retrofit:converter-gson:2.0.0-beta2'
}
The problem is with those two external libraries (retrofit & converter-gson).
Result of this library project is .aar file. But when I use this .aar file in a separate project I get unresolved class error:
java.lang.NoClassDefFoundError: Failed resolution of: Lretrofit/Retrofit$Builder;
Is there a way to include those gradle dependencies from my library project into the final .aar file?
I tried this answer but it didn't work for me.
EDIT:
My whole build.gradle file from library project.
apply plugin: 'com.android.library'
android {
compileSdkVersion 23
buildToolsVersion "23.0.2"
defaultConfig {
minSdkVersion 15
targetSdkVersion 23
versionCode 1
versionName "1.0"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
testCompile 'junit:junit:4.12'
compile 'com.squareup.retrofit:retrofit:2.0.0-beta2'
compile 'com.squareup.retrofit:converter-gson:2.0.0-beta2'
}
EDIT 2:
This is the part of the build.gradle script in my app project which uses the library which was generated before as an .aar file.
3 versions and none of them work (none of them download automatically dependencies form the library)
(note, I am adding this .aar file into the lib folder of my app project and adding the flatDir instruction into it's gradle.build). I am not doing File->New->NewModule->ImportExistingJAR/AAR
repositories {
flatDir {
dirs 'libs'
}
}
1.
compile(name:'mylibrary-release', ext:'aar')
2.
compile(name:'mylibrary-release', ext:'aar') {
transitive = true
}
3.
compile(':mylibrary-release#aar') {
transitive = true
}
Your AAR library is not the problem. Libraries are not supposed to include their dependencies as it may cause version conflicts further down.
The reason your app project is not transitively loading your library's dependencies is the flatdir. Here's the relevant part in the docs (https://docs.gradle.org/current/userguide/declaring_repositories.html#sub:flat_dir_resolver):
This type of repository does not support any meta-data formats like
Ivy XML or Maven POM files. Instead, Gradle will dynamically generate
a module descriptor (without any dependency information) based on the
presence of artifacts.
The correct approach would be to host your library in a public or private maven repository.
The accepted answer from How to include JAR dependency into an AAR library works. You need to add an evaluation listener, like this:
afterEvaluate {project -> project.tasks.preBuild.dependsOn copyLibs}
I'm trying to use Picasso library in my gradle-android project. I'm using eclipse IDE. When I make gradle build to my project, that is build correctly but in my *.java files, that are using Picasso, I get "Picasso cannot be resolved". Using Ctrl-Shift-R on eclipse I found the jar of Picasso but In the folders build/intermediate/pre-dexed/release and build/intermediate/pre-dexed/debug. My gradle file is below, Could you help me please?
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:1.1.3'
}
}
apply plugin: 'com.android.application'
android {
compileSdkVersion 22
buildToolsVersion "22.0.1"
defaultConfig {
minSdkVersion 16
targetSdkVersion 22
}
}
repositories {
mavenCentral()
}
dependencies {
compile fileTree(dir: 'libs', include: '*.jar')
compile 'com.squareup.picasso:picasso:2.5.0'
}
dependencies {
//compile 'com.parse.bolts:bolts-android:1.+'
//compile fileTree(dir: 'libs', include: 'Parse-*.jar')
compile fileTree(dir: 'libs', include: '*.jar')
compile 'com.android.support:appcompat-v7:21.0.0+'
}
to use Gradle you must use Android Studio
https://developer.android.com/sdk/index.html
Eclipse does not support gradle, only Maven
I had the same problem in using the Picasso library(Cannot be resolved). I faced it in eclipse. I don't know whether it would help you in Android studio. My solution was, I just deleted the libs folder in my project and created the same folder again. After that i copied my picasso jar file to that. And from that moment on wards import option is available for me and the error is gone. :-)