34

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."

PaulR
  • 3,223
  • 1
  • 21
  • 32

5 Answers5

63

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.

PaulR
  • 3,223
  • 1
  • 21
  • 32
  • You say "we're hoping to fix this in a later release". Does that mean better reporting of the conflict, or supporting resolution of transitive dependencies across the app and test app? – vaughandroid Feb 24 '15 at 14:46
  • @Baqueta: better reporting of the conflict. – PaulR Feb 24 '15 at 15:04
  • The next answer provides a great solution to determining the dependency version numbers until we improve this a bit. Although we don't suggest going to older versions of the plugin to stop the error from happening. – PaulR Feb 26 '15 at 16:33
  • I've updated this answer to include the adjusted error message which automatically includes the version numbers. – PaulR Mar 13 '15 at 15:31
  • Thanks for the explanation Paul! Can it be achieved also by specifying `force = true` on a non-transitive dependency? In my case I have a `compile 'com.android.support:support-annotations:22.0.0'` dependency which conflicts with a transitive dependency from `androidTestCompile` configuration. Gradle docs say you could use `compile('com.android.support:support-annotations:22.0.0') { force = true }` to "force certain dependency version in case of the conflict". Seems like a clean approach to me (force the non-transitive version) and I tried it, but I can't get it to work. – Marcin Koziński Mar 18 '15 at 15:13
  • Could you provide a link and your exact error msg (with version nums)? – PaulR Mar 18 '15 at 16:16
  • 1
    Link to Gradle doc: https://www.gradle.org/docs/current/dsl/org.gradle.api.artifacts.dsl.DependencyHandler.html (search for "forcing"). My error message is "Warning:Conflict with dependency 'com.android.support:support-annotations'. Resolved versions for app (22.0.0) and test app (20.0.0) differ." (same with and without "force"). Minimal dependencies that result in coflict are: `compile 'com.android.support:support-annotations:22.0.0'` and `androidTestCompile 'com.squareup.assertj:assertj-android:1.0.0'` – Marcin Koziński Mar 18 '15 at 22:15
  • That force directive will force it within each build I think, but not across the app vs test builds which is the comparison the error message is being thrown from. Since you appear to want 22 then you would just add a direct 22 version dependency as an androidTestCompile dependency which will overtake the transitive 20 in that build and resolve this error. – PaulR Mar 25 '15 at 05:18
  • Thanks, Paul. That gives a little headache of updating the version number in one more place. Currently I use excludes in my androidTestCompile dependency to explicitly exclude the conflicting transitive dependency. I think it is nicer, because I don't have to update it, when the version number changes. I was just hoping that with changes to the dependency resolution in the android plugin I could remove my explicit excludes. – Marcin Koziński Mar 25 '15 at 07:52
  • Excludes is a fine approach, but if you're only doing this so you don't have to keep two version numbers in sync it might be easier to declare a version number in the build script or gradle.properties and use a GString ("group:artifact:${libversionnumber}"). – PaulR Mar 25 '15 at 14:50
20

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'
Andrii Abramov
  • 10,019
  • 9
  • 74
  • 96
steineron
  • 389
  • 3
  • 6
  • Hi, How do you realize that app referring to annotations:21.0.3 and test app referring to 20.0.0? what is androidTestCompile 'com.squareup.assertj:assertj-android-appcompat-v7:1.0.0'. Please help.. It will be great help if I resolve this error. – Programmer Sep 07 '15 at 14:15
  • you'd noramlly see a warning in the messages view of android studio upon build. the message will state exactly this kind of mismatch+version names per app/test app. – steineron Nov 26 '15 at 01:16
  • Thank you very much. If you mind me asking, why would it not work for me when I moved both of them down to an earlier version? – Script Kitty Apr 25 '16 at 00:19
  • assertj is a library used for testing - that was just the issue in my case. it varies though. the point is that the plugin to 1.1.1 generates a more informative messages in your studio and tells you which component depends on which version of library in conflict. so one of them needs to use a newer one... newer cause backward compatibility is likelier than forward compatibility. – steineron May 13 '16 at 07:11
6

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' }

Giorgos Kylafas
  • 2,243
  • 25
  • 25
  • 1
    Despite not many votes this might be the simplest solution. You're only making changes to the library you're pulling in, not setting any 'force' resolution strategies, and not double-declaring the conflict library. – Anthony Chuinard Feb 23 '17 at 23:52
5

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'
    }
}
Alexandru Marculescu
  • 5,569
  • 6
  • 34
  • 50
Sagar Rathod
  • 542
  • 8
  • 13
2

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.

Petter Hesselberg
  • 5,062
  • 2
  • 24
  • 42