Dependency conflict error in my Android app which has Android Tests - android

I'm using AndroidStudio and Gradle to build my Android app with tests in the 'androidTest' source directory. I added a new dependency and am now getting the following issue when running Android Tests either in AndroidStudio or via './gradlew connectedCheck'. What's the preferred way to resolve this?
'Warning:Conflict with dependency 'org.somelibrary:library-core'. Resolved versions for app and test app differ.'
As of Android Gradle Plugin 1.1.1 the error displays like this:
"Warning:Conflict with dependency 'com.google.code.findbugs:jsr305'. Resolved versions for app (1.3.9) and test app (2.0.1) differ."

When you build and run Android Tests for your app the Android Gradle plugin builds two APKs (the app and the test APK). During the gradle run the dependencies for the app and test builds are compared. Dependencies that exist in both are removed from the test build when the version numbers are the same. When the same dependencies are in use, but differ by version number then you will need to manually resolve the dependency conflict and this error is presented.
To resolve the conflict you first need to figure out the two versions that are conflicting. If you aren't already using the Android Gradle Plugin v1.1.1+ then if you upgrade to that version the error message will give you the conflicting version numbers. Choose which one you need.
*When choosing between the conflict numbers it might be important to keep in mind that unless you've overridden the default gradle dependency resolution strategy (failOnVersionConflict) then conflicts internally within the app and test builds (separately) will be resolved by choosing the greater version.
Now you need to decide how to resolve the conflict. If you need to force the use of the lower version (1.2) of the library you will need to force the dependency to be resolved for both the app and test builds to a specific version of the library like this:
// Needed to resolve app vs test dependencies, specifically, transitive dependencies of
// libraryq and libraryz. Forcing the use of the smaller version after regression testing.
configurations.all {
resolutionStrategy.force 'org.somelibrary:library-core:1.2'
}
If you need to use the 2.1 version of the dependency then you can use the snippet above as well, but you will never start using a newer version of the library regardless of whether transitive dependency updates require it. Alternatively, you can also add a new normal dependency to either the app or the test builds (whichever was trying to use the 1.2 version of the dependency). This will force the app or test build to depend on the (previously mentioned) gradle dependency resolution strategy and therefore use the 2.1 version of the library for that build.
// Force the use of 2.1 because the app requires that version in libraryq transitively.
androidTestCompile 'org.somelibrary:library-core:2.1'
or
// Force the use of 2.1 because the Android Tests require that version in libraryz.
compile 'org.somelibrary:library-core:2.1'
In this solution the error could resurface, if say version 3.3, started to be used in only one of either the test or the app builds, but this is typically OK because you'll be notified of another incompatibility at build time and can take action.
Update: A few new solutions to this question now also list excluding a particular transitive dependency from a declared dependency. This is a valid solution, but puts more onus on the developers. In the same way that the forced dependency resolution suggestion above above hard codes a version into the build, the exclude-transitive-dependency solution specifically overrides the stated requirements of a library. Sometimes library developers have bugs or work around bugs in various other libraries so when you implement these solutions you take some risk in potentially having to chase down very obscure bugs.

Had similar problem.
First - I upgrade the gradle plugin to 1.1.1 (in the project's gradle):
classpath 'com.android.tools.build:gradle:1.1.1'
which helped me realize that the problem was the app referring to:
com.android.support:support-annotations:21.0.3
while the test app was referring to:
com.android.support:support-annotations:20.0.0
(due to specifying androidTestCompile 'com.squareup.assertj:assertj-android-appcompat-v7:1.0.0')
solved it by specifying:
androidTestCompile 'com.android.support:support-annotations:21.0.3'

Alternatively, one can exclude the conflicting dependency (e.g. support annotations library) pulled in by the test app dependency (e.g. assertj-android), by using the following:
testCompile('com.squareup.assertj:assertj-android:1.0.0') {
exclude group: 'com.android.support', module: 'support-annotations'
}

Gradle has Resolution Strategy Mechanism.
You can resolve this conflict by adding below lines to app level build.gradle file:
configurations.all {
resolutionStrategy {
force 'com.google.code.findbugs:jsr305:1.3.9', 'com.google.code.findbugs:jsr305:2.0.1'
}
}

If you look at the (generated) .iml file(s), you can see the conflicting version numbers quite easily. In my case:
<orderEntry type="library" exported="" scope="TEST" name="support-annotations-20.0.0" level="project" />
<orderEntry type="library" exported="" name="support-annotations-21.0.3" level="project" />
Going back to version 1.0.1 of the gradle plugin resolves the problem.

Related

Android dependency has different version for the compile and runtime classpath

I am using a lot of Firebase related libraries in my project. Upon syncing, I am facing the following error.
Android dependency 'com.google.firebase:firebase-iid' has different
version for the compile (17.0.3) and runtime (17.1.1) classpath. You
should manually set the same version via DependencyResolution
The thing is that I have not even declared firebase-iid in my dependencies and this is coming as a transitive dependency from other firebase libraries.
Upon running the dependency chart, I am able to find the following things.
Version 17.0.3 is coming from com.google.android.gms:play-services-measurement-api:16.4.0
Whereas 17.1.1 is coming from com.google.firebase:firebase-messaging:17.5.0
Ideally it should resolve it internally and the higher version should be automatically picked. But this is not happening.
Any idea why this is happening and how to resolve this issue?
There is not updated gradle for com.google.android.gms:play-services-measurement-api:
The latest release is on March 2019, version : 16.4.0 .
So, your implementation is not correct for this measurement-api .
Use :
com.google.android.gms:play-services-measurement-api:16.4.0
com.google.firebase:firebase-messaging:17.5.0
refer this link : https://mvnrepository.com/artifact/com.google.android.gms/play-services-measurement-api/16.4.0
https://mvnrepository.com/artifact/com.google.firebase/firebase-messaging
Yes you are right, gradle should automatically resolve to a single version of a library, but as I experienced sometimes, it does, sometimes, it does not. But when It does not resolve to a single version of same library, we can force it to use a single specific version like explained below.
configurations.all {
resolutionStrategy {
force "com.google.android.gms:play-services-measurement-api:17.1.1"
force "com.google.firebase:firebase-messaging:17.5.0"
}
}
dependencies {
// ... all dependencies here...
}
Try using above code forcing gradle to use a single version. Might help in your case.

Why must $kotlin_version be explicitly specified in Android?

Supporting Kotlin in an Android studio project requires two dependencies: kotlin-gradle-plugin in Project/build.gradle and kotlin-stdlib-jdk7 in Project/app/build.gradle, and these two need to have the same version. The common method seems to be using a single kotlin_version variable which you then have to manually change when the IDE updates its Kotlin plugin — as of Android Studio 3.1.3, the IDE is still not able to automatically update the dependencies if you use a $variable as the version.
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
In non-Android Kotlin projects i.e. those using apply: 'kotlin' instead of apply plugin: 'kotlin-android', it is possible to simply omit the version from the kotlin-stdlib-jdk7 dependency, which will then be automatically resolved from the plugin.
implementation 'org.jetbrains.kotlin:kotlin-stdlib-jdk7'
This even works on non-Android modules within Android projects. My question is, why is this not possible in Android modules? Why can't the $kotlin_version simply be omitted? If the feature has been present since Kotlin 1.1.2, why is it still causing compile errors on Android even on Kotlin 1.2.51? Or is it actually possible to do this, and if so, how can it be done?
In fact this is not Kotlin specific but has to do with how Gradle manages dependencies.
See https://docs.gradle.org/current/userguide/declaring_dependencies.html on how to specify the version of a dependency in Gradle.
In this case
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
is the standard way of setting the version. As the this version number is the same for several dependency it is declared in a variable in order to make it easy to change the version for all Kotlin libraries.
implementation 'org.jetbrains.kotlin:kotlin-stdlib-jdk7'
Uses dependency constraints which are available since Gradle 4.6. It is used for the same purpose. One can set the version of a library in a central place and this way keep the version at a common value without having to go through all gradle.properties files of a larger project.

How does Gradle choose between more than 1 versions of the same library in a gradle tree?

Let say I have added Facebook and Twitter dependencies in my app.
com.facebook.android:facebook-android-sdk:4.22.1
com.twitter.sdk.android:twitter:2.1.0
When i look at Gradle tree, They come up with bunch of other transitive dependencies.
Now If Facebook uses com.android.support:support-annotations:24.1.1 and twitter uses com.android.support:support-annotations:25.0.3
Then which version gradle will use.
In gradle tree, It shows -> in front of older version of dependency. I learnt that this means gradle will use the newer version, and will not use the older version.
But this can be a problem, because some libraries are meant to run on the specific versions, and i have faced this problem.
In one of article i found out how npm manages these dependencies conflicts, but i am still unsure how gradle will manage between different version of same library.
You can't have different versions of the same library inside an apk.
As you mentioned, by default, Gradle puts the newest one to the build. If you want to specify a concrete version of the library that should be used in your project, you can add a direct compile (or implementation / api for Android Gradle Plugin v3+) statement with a required version to get one.
Also, you can force version using a special syntax, but it can lead to some problems later. You can find more information about version conflicts resolution in this post

Gradle dependency configuration : implementation vs api vs runtimeonly vs compileonly

Unable to understand the latest gradle dependency configurations which are introduced in Android Studio 3.0 i.e. implementation, api , compileonly and runtimeonly.
Please refer the link : Android Studio 3.0 New Gradle Configuration available at android developers official site.
Based on description mentioned in above link:
implementation: 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.
api: When a module includes an api dependency, it's letting Gradle know that the module wants to transitively export that
dependency to other modules, so that it's available to them at both
runtime and compile time. This configuration behaves just like compile
(which is now deprecated), and you should typically use this only in
library modules. That's because, if an api dependency changes its
external API, Gradle recompiles all modules that have access to that
dependency at compile time. So, having a large number of api
dependencies can significantly increase build times. Unless you want
to expose a dependency's API to a separate test module, app modules
should instead use implementation dependencies.
compileOnly: 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).
runtimeonly: Gradle adds the dependency to the build output only, for use during runtime. That is, it is not added to the compile
classpath. This configuration behaves just like apk (which is now
deprecated).

How to update Gradle dependencies to their latest version

Is there an easy way to get gradle to update dependencies to their latest available version?
For build reproducibility all my dependencies are defined with a version number like this in my build.gradle file:
dependencies {
compile 'namespace:package1:version'
compile 'namespace:package2:version'
compile 'namespace:package3:version'
}
Periodically I want to update every package to their latest version. Typically this is the first thing I do for a new sprint after making a release.
It's a real pain doing this manually for each package. Ideally I would like a command to update the build.gradle file for me but at the very least a command that prints out which package needs an update and what the latest version number is.
In ruby land I would run bundler update.
This is all I've been able to come up with. I will happily accept another answer if there is a less manual method of doing this.
In Android studio I replace every dependency version with a plus example: compile 'namespace:package1:+'
Sync or build the project which will cause all the dependencies to be resolved to their latest version.
In Android Studio place the cursor on each dependency line in build.gradle and press alt+enter a menu pops up and you can select Replace with specific version
Add to build.gradle:
plugins {
id 'com.github.ben-manes.versions' version '0.17.0'
}
Then you can do gradle dependencyUpdates to get a report of new versions. Unlike the eponymous Maven plugin, there doesn't seem to be a way of automatically updating the build.gradle yet.
More documentation: https://github.com/ben-manes/gradle-versions-plugin
It is not a really good practice as libraries can include changes that may break your code.
A common "tolerated" syntax for
compile 'namespace:package:major_version.minor_version.revision'
would be like
compile 'namespace:package:1.0.+'
considering revision is used by the library authors as bug fixes and improvements updates
Note:
I just did that and you could do
compile 'namespace:package:+'
Edit:
A Proof Of Concept of my latest comment you may want to test.
This was made in 5 minutes, so don't expect it to be perfect nor flexible.
I suffer from it, too. And the best way to check dependencies, even manually, is to go through Project Structure and search for the dependency name and see if there is a newer version.
The problem that this query only checks for the dependencies present in the Maven repository. At least it already goes for Google's.
Note: If you choose to add the dependency with the new version, this will add a duplicity in the your App Gradle, so be sure to delete the old dependency row.
###################
Another possible quick fix is through the command line:
./gradlew app:dependencies
This will generate an output like the one below. Note that the asterisk points to a possible new existing version.

Categories

Resources