Compile, Provided, APK - Android dependency scope - java

While adding new dependencies to android project especially in Android Studio in Dependencies there are three scope options Compile/Provided/APK.
What are the effects of choosing each one, when should we use them ? Besides what the name says.
EDIT:
"Properly handle 'provided' and 'package' scopes to do what they should be doing.
'provided' and 'package' cannot be used with Android Libraries, and will generate an error" .. this is from http://tools.android.com/tech-docs/new-build-system

provided - compile-time only dependency
package - package-time only dependency
compile - compile-time and package-time dependency
provided is commonly used for annotation processing based libraries. Usually these libraries are separated in two artifacts - "annotation" and "compiler". "compiler" is provided dependency because you do not need to use it in application, only for compilation; and "annotation" is compile dependency - it is used in application code and therefore compiles. Or generated code may require additional dependencies while your application may not. E.g. dagger dependencies configuration:
compile 'com.squareup.dagger:dagger:1.2.2'
provided 'com.squareup.dagger:dagger-compiler:1.2.2'

These properties come from maven scopes.
They simply indicate how to treat particular dependencies during each step of build process.
compile - a default approach, it simply means that all dependencies should be available at compile-time. Compile dependencies are available in all classpaths of a project. Furthermore, those dependencies are propagated to dependent projects. A compile-time dependency is generally required at runtime.
package - declares additional configuration for building an application. You can list plugins that add additional functionality to the build process.
provided - it means that runtime environment has these dependencies included. For example, when you look into android.jar library internals you will see java.lang.RuntimeException: Stub! in every method body.
That has some consequences:
You can develop Android applications locally, without having complete Android environment.
Your APK you must run it on an android device or an emulator because they provide implementation of these methods.
Your apps that reference the SDK classes will build properly, because the jar provides the class metadata.
Unless you use some library that provides artifacts (e.g. Robolectric), you have to run tests on your emulator/device.
provided and package cannot be used with Android Libraries, and will generate an error.
Here is how sourceSet looks like:
More info about build system: https://www.youtube.com/watch?v=LCJAgPkpmR0
An awesome article about Gradle: http://www.sinking.in/blog/provided-scope-in-gradle/

Xavier talks here about the APK scope.
in the Android plugin, The equivalent (sort of) of runtime is called apk. You can do
dependencies {
apk files('libs/foo.jar')
}
and it'll only get packaged but won't be on the compile classpath.

With gradle 6.5.1 provided gives the below error
Could not find method provided() for arguments [directory '....'] on object of type org.gradle.api.internal.artifacts.dsl.dependencies.DefaultDependencyHandler.
I used compileOnly to use the dependencies at only compile time and not to inlcude in the final build artifact

Related

What scope should i apply for the libraries used in my jar ,?

I am developing an application which will be published to nexus repository used as a dependency by other applications.
I am using gradle for the build, and have applied the maven plugin.
When i do a gradle install, the dependency scope in the generated pom is automatically applied as 'runtime' for the libraries that i have added as dependencies.
I am using "implementation" for adding my dependencies.
What is the recommended scope for the libraries i my case ?
I see compile would have been useful , but is now deprecated. Should i use compileClasspath ?
Thanks !
The scope of the dependencies is controlled by the configuration you define them in in the dependencies { } block.
Gradle has great table with descriptions as to when you should use them.
Most commonly, you'll use these two:
implementation - This is where you should declare dependencies which are purely internal and not meant to be exposed to consumers.
api - This is where you should declare dependencies which are transitively exported to consumers, for compile.

How to fix warning about "dependency is ignored for debug..."

I have java module, that used not only for android projects, but also for java projects. Java module used json, so it has dependency:
compile 'org.json:json:20160810'
Of couse, on build android project I has warning:
WARNING: Dependency org.json:json:20160810 is ignored for debug as it
may be conflicting with the internal version provided by Android.
In case of problem, please repackage with jarjar to change the class packages
I'm use module with sources, not as jar and I do not want install module to local repository.
How I can fix issue with warning?
I know, that for jar I can use exclude group/module, but it do not work for module.

What is the proper Gradle project structure for switching between 'project' and 'external' dependencies

I have this small set of libraries and app:
forge-base - java project (Intellij IDEA project)
forge-android - android library project, depends on forge-base (AS project)
forge-android-skeleton - sample android app, depends on forge-android (AS project)
During the initial development I used structure with project dependencies like:
settings.gradle:
...
include ':forge-base'
project(':forge-base').projectDir=new File("$settingsDir/../forge/base")
...
and then in build.gradle:
compile project(':forge-base')
This worked like a charm but later I needed to publish the libs on maven repo and dependencies had to be changed like:
build.gradle:
compile 'com.bolyartech.forge:forge-base:2.0-SNAPSHOT'
The problem that I am facing now is that I am trying to do some major refactoring in all the 3 projects and I need the old deps structure in order easily to confirm the consistency of the projects, e.g. to build just the skeleton app and all the recursive recompile/building to take place automatically (as it does when a lib project is referenced with compile project(':forge-base')). If I use the 'new' structure with publishing to the (local) maven I have to publish the lib each time (with incremented version) I change something in it in order changes to be visible by the other two projects.
What (is there) is the usual/canonical why to handle situations like this?
Is there an easy way to switch between the two 'modes', e.g. 'internal' / 'external' dependencies?
It turns out it is pretty easy to do it. You can use different dependencies for the different build types, i.e. debug/release so for example for my forge-android-skeleton project now I have the following:
in settings.gradle:
include ':app'
include ':forge-base' project(':forge-base').projectDir=new
File("$settingsDir/../../../forge/base")
include ':forge-android' project(':forge-android').projectDir=new
File("$settingsDir/../../../forge-android/forge-android")
in app/build.gradle:
...
releaseCompile ('com.bolyartech.forge:forge-android:2.7-SNAPSHOT')
debugCompile project(':forge-android')
...
Please note that in the settings.gradle you need to have all the dependencies back to the bottom otherwise it will not work (that is the reason forge-base is defined there even not excplicitly used).
You can also define yet another build type like direct-deps and use it in case you don't like to mess with debug/release types.
Please note that in case you are using different IDEs for some of the projects (like in my case IDEA and AS) probably it will be good idea to ensure that both are using same (version of) gradle otherwise unexpected problems may occur.

Gradle - what is "runtime" dependency configuration used for?

Can you please help me understand what are the typical use-cases in which one would use the runtime dependency configuration (provided by the Java plugin)?
In the Gradle user-guide, Table 23.5. Java plugin - dependency configurations, I can see that the runtime configuration is not used by any tasks - as opposed to e.g. the compile configuration which is used by the compileJava task.
What then is the runtime dependency useful for?
The runtime configuration is for libraries that are needed at runtime but NOT at compile time (For example JDBC drivers and SLF4J api implementations).
You could just add them to your compile configuration, but then they would be on the compile classpath and you would run the risk of accidentally introducing a compile dependency on something from the implementation rather than the api.
It is not for libraries that are 'provided' by a container - it is actually how you provide libraries to your app while making sure you haven't introduced a compile depencency on them.

What is the best way to declare transient dependencies between compile and runtime with Eclipse?

We are looking to revamp our Java build process on Eclipse. Currently we use Gradle! As a part of that effort we are looking at whether we are using Gradle in the best possible way. We use the Eclipse plugin for Gradle and declare our dependencies with compile. Unfortunately this adds a ton of transient dependencies with our generated Eclipse projects which is not desirable. These extra dependencies are only valid at runtime.
So, is there a way to declare a dependency ONCE in Gradle and have its compile dependency set to the first level of dependency and its runtime dependency set to the first level plus transient dependencies?
Currently we use the #jar syntax with compile which gives us the first level dependency for compile, but we still have to declare that dependency again for runtime. Not ideal because we have two places to go in order to update a dependency.
Is there a better way?
I assume you mean transitive dependencies.
If you only want direct dependencies to appear on Gradle's compile class path, your current solution seems reasonable. (In the future we want to have a more accurate compile class path out-of-the-box.) Potential improvements are to make the compile configuration non-transitive (rather than using #jar) or to write a plugin that provides a custom dependency syntax, thereby making the duplication between compile and runtime dependencies go away.
However, this won't help you with Eclipse, as Eclipse has no notion of separate compile and runtime class paths. The only way out is to make run configurations responsible for providing the runtime class path, but this might be difficult to set up (e.g. run configurations are often created on-the-fly), and Gradle doesn't have any out-of-the-box support for this. You could use the generic XML hooks of Gradle's Eclipse plugin to generate run configurations, but I'm not sure if the Eclipse Gradle integration would pick them up.
Due to these difficulties, most Eclipse developers put all runtime dependencies on the Eclipse project class path (regardless of whether they are using Gradle or not), despite the obvious disadvantages.
Our vision is that Gradle can one day act as the build engine for Eclipse. Once this happens, discrepancies between IDE and build tool (class paths, code generation, integration testing, etc.) will be a thing of the past. Gradle can already act as the build engine for NetBeans today, and soon also for IntelliJ IDEA (driven by the requirements for Android Studio).
While I certainly agree with #Peter that an overhaul of the Eclipse build process is a long-term goal, in the short term you may be able to accomplish what you want using Maven and m2eclipse. Whether the tradeoffs of moving to Maven are worth that extra control are entirely up to you.

Categories