1

Today I started building a library for my company so we could avoid some duplicate code across a few of our apps. The library uses a few dependencies that are duplicated in the apps. In this case, Retrofit and Eventbus. Anyhow when I included my library it looked something like this:

implementation (project(":mylib")

Knowing that I would be using Eventbus as well as some other dependencies, I wanted to test exluding them in order to avoid duplicate dependencies. So I added in Eventbus to the app's gradle file and I excluded Eventbus from my library.

implementation 'org.greenrobot:eventbus:3.0.0'
implementation (project(":mylib")){
    exclude module: 'eventbus'
}

Now I am fully aware that I could just not include Eventbus in the app by just importing mylib, and certainly I have excluded dependencies to avoid build conflicts in the past so I am familiar with the usage, but I just wanted to experiment with it because it occurred to me that I really don't know what's happening under the hood with this exclusion. The term exclusion implies (to me) that this dependency isn't compiled period at the point of exclusion, however, this can't be the case because the 3rd party library (Eventbus in this case) still seems to execute just fine in mylib and if it didn't compile there would be crashing code world wide because of weird library dependency issues. So what exactly is happening here? Is it the case that it still compiles for the library, and it still compiles for the app, but somehow these dependencies are just separated? If so, it seems like that isn't all that efficient because you would still be duplicating all the methods in the project.

Clearly I have a limited knowledge of this, so if someone could clarify this I would very much appreciate it.

sam_c
  • 810
  • 7
  • 25

1 Answers1

2

AAR/JAR library doesn't include dependencies's classes in archive, it only includes your code. Normally they are stored in maven-like repositories with .pom file that contains the list of its dependencies. When you add it to your project in build.gradle file it just downloads the AAR/JAR, parses .pom file and downloads all dependencies listed (recursively repeating the process for each library until it got all the dependencies). Which means that you don't have to exclude module if it also depends on same libraries that your app uses.

Wheh you add library as local module implementation (project(":mylib") it does exactly the same thing, but for each dependency listed in subproject's build.gradle

If you exclude transitive dependency it just makes ignore the artifacts with specified name while parsing .pom files

Amaksoft
  • 954
  • 9
  • 16
  • So if it ignores an artifact in my subproject then it just uses the artifact from the app? Does this work the same if I eventually host the library somewhere and import from outside of the project? – sam_c Sep 27 '17 at 15:31
  • 1
    Yes, exactly. You just exclude the specified (by module group and name) transitive dependencies of one particular artifact from resolution process. If you forget to add them directly to your app project or won't receive as transitives from another artifact, you will not get them at all. If multiple modules depend on different versions of same library, you receive the most recent version of all specified. The same rules apply for external artifacts, that's the way dependency resolution works in general. – Amaksoft Sep 28 '17 at 01:41
  • There actually is a very useful gradle task, that shows the dependency tree and how artifacts are resolved. Just run `./gradlew :{project_module_name}:dependencies` from your project root and it will print the dependency tree for the specified module. The output is huge, but you will see every dependency of each configuration. Also you may be interested in reading the [gradle docs on dependency resolution](https://docs.gradle.org/current/userguide/dependency_management.html) – Amaksoft Sep 28 '17 at 01:51