How do I properly specify dependencies in a published Android library? - android

I'm creating an Android library that will be published to something like Sonatype. Some of my classes depend on classes in the AppCompat library.
If my Android module look like this:
dependencies {
compile "com.android.support:appcompat-v7:25.3.1"
}
will my users run into problems if they add my library as a dependency and also add some future version of appcompat as a dependency?
And related, is there a way I can set this up so they don't have to specify transitive dependencies, or would that even be expected for ease of use?

Related

api or implementation for dependencies in my own library?

Is there some good reason to use api over implementation in gradle when using your own library ? Is there any good reason to use it in some other situation ? I could not find answer in other questions about it. Or its just when you have to because of transition from using of compile ?
Besides your own library one the most relevant situation where I see it useful is when you have a multi-module project. In this kind of projects you most likely end up having modules that have dependencies of other modules and since you might want that gradle recompiles your modules dependencies if there is any change in those modules api is the answer.
api is the equivalent of compile, and implementation was added to improve gradle builds by not having to recompile every dependency but only the ones that needs to be recompiled.
The following articles are a good source of information about it, and they are very concise.
Implementation vs API dependency
Implementation Vs Api in Android Gradle plugin 3.0
Update:
From gradle docs:
The api bucket is used to declare dependencies that should
transitively be visible by downstream consumers when they are
compiled. The implementation bucket is used to declare dependencies
which should not leak into the compile classpath of consumers (because
they are purely internal details).
This means that if your own library wants to expose any dependency to its consumers you should use api. Any dependencies with api in your own library will be part of the compile classpath of the app consuming your own library. With implementation you wont expose the dependencies you are using in your own library to the app that is consuming it.
You can see this being applied in well known libraries like ButterKnife for instance. Where the "core" butterknife module, which is the one the consumer app adds as dependency, is exposing butterknife-annotations to the consumer through api project(':butterknife-annotations'). And this is what allows the consumer use the binding annotations from butterknife such as #BindView.
If the butterknife-annotations were added in butterknife with implementation instead of api, the consumer app will not be able to use those binding annotations. Because the butterknife-annotations will no longer be part of the compile classpath of the consumer app.

Android dependency is set to compileOnly/provided which is not supported

I'm using com.android.tools.build:gradle:3.1.1 with the latest Gradle version (https://services.gradle.org/distributions-snapshots/gradle-4.8-20180417000132+0000-all.zip).
When I use compileOnly dependencies some of them won't compile, some will.
E.g.
compileOnly "com.android.support:support-v4:27.1.1"
works perfectly while
compileOnly "com.facebook.stetho:stetho:1.5.0"
gives a compile error:
Android dependency 'com.facebook.stetho:stetho:1.5.0' is set to compileOnly/provided which is not supported
I was under the impression than any dependency can be compileOnly. Nothing indicates otherwise (https://developer.android.com/studio/build/gradle-plugin-3-0-0-migration.html#new_configurations). Both of these libraries have transitive dependencies.
Any help would be greatly appreciated.
As an experiment, I created a new Android Studio 3.1.1 project. Then, I added a lib module to it as a plain Java library module. I could add compileOnly project(":lib") to the app module, and it compiled. I changed the lib module to be an Android library module (apply plugin: 'com.android.library') with a minimum manifest, and now compileOnly project(":lib") gets the error that you do: "Android dependency 'project :lib' is set to compileOnly/provided which is not supported".
Since there were no other material changes in the lib module, the compileOnly limitation is on Android library modules.
My guess is that it is unclear what "compile only" means for manifest entries, resources, assets, etc. So, they officially punted.
I filed an issue, requesting documentation of this limitation. My requests for documentation usually fall on deaf ears.
At the dawn of "Dynamic feature modules", compileOnly Android library modules could make sense, to allow easy access to the feature module from the base app when it is installed.
That's why I created this feature request: https://issuetracker.google.com/issues/109894265
Feel free to star it and comment with your use cases.
I had a similar issue on a project with many libraries.
I have a libX that I implement in debug with debugImplementation project(':libX') to work with sources, but in release build I target published version releaseImplementation "com.company:libX:1.0.0".
After a refactor, I got a similar error during a release sync about my libX.
Android dependency 'com.company:libX:1.0.0' is set to compileOnly/provided which is not supported.
However, I wasn't using any compileOnly...
The problem was due to one lib which was using libX always as source, (implementation project(':libX')). So in release, gradle was confused as it was implementing libX as sources in some libs, and as published lib in other.

Library dependency issues with gradle 3.0.0-alphaX

I have a library project with submodules that include many dependencies that I'd like to pass to the developer's application. For example, module A may include all the necessary appcompat dependencies.
With the migration changes, I've updated all compile cases to api, which should not affect anything. However, I no longer have access to any of the libraries dependencies. I can only use code and references from my library itself.
Is there any way around this?
One of the build gradle files of my library submodules can be found here for reference.
The dependencies:
dependencies {
api "org.jetbrains.kotlin:kotlin-stdlib:${KOTLIN}"
api "com.android.support:appcompat-v7:${ANDROID_SUPPORT_LIBS}"
api "com.android.support:support-v13:${ANDROID_SUPPORT_LIBS}"
api "com.android.support:design:${ANDROID_SUPPORT_LIBS}"
api "com.android.support:recyclerview-v7:${ANDROID_SUPPORT_LIBS}"
api "com.android.support:cardview-v7:${ANDROID_SUPPORT_LIBS}"
api "com.android.support.constraint:constraint-layout:${CONSTRAINT_LAYOUT}"
api "com.mikepenz:iconics-core:${ICONICS}#aar"
api "com.mikepenz:google-material-typeface:${IICON_GOOGLE}.original#aar"
api "com.afollestad.material-dialogs:core:${MATERIAL_DIALOG}"
api "com.jakewharton.timber:timber:${TIMBER}"
api "org.jetbrains.anko:anko-commons:${ANKO}"
}
Edit:
To clarify, the sample project in the module actually does build properly, but there's an issue with using the dependencies in any other app, where it pulls from jitpack. See this gradle as an example that won't build.
I've tried using combinations of api, implementation, #aar, and transitive.
Come to think of it, this may be a jitpack issue and not a gradle issue, but if anyone else has a resolution I'd like to hear it.
I no longer have access to any of the libraries dependencies. I can only use code and references from my library itself.
It is correct.
From the gradle docs :
dependencies {
api 'commons-httpclient:commons-httpclient:3.1'
implementation 'org.apache.commons:commons-lang3:3.5'
}
Dependencies appearing in the api configurations will be
transitively exposed to consumers of the library, and as such will
appear on the compile classpath of consumers.
Dependencies found in the implementation configuration will, on the
other hand, not be exposed to consumers, and therefore not leak into
the consumers' compile classpath. This comes with several benefits:
dependencies do not leak into the compile classpath of consumers anymore, so you will never accidentally depend on a transitive
dependency
faster compilation thanks to reduced classpath size
less recompilations when implementation dependencies change: consumers would not need to be recompiled
cleaner publishing: when used in conjunction with the new maven-publish plugin, Java libraries produce POM files that
distinguish exactly between what is required to compile against the
library and what is required to use the library at runtime (in other
words, don't mix what is needed to compile the library itself and what
is needed to compile against the library).
The issue seems to be related to the android-maven-gradle-plugin
Issue Report
It's has been fixed in version "2.0" of android-maven-gradle-plugin
just update to
dependencies {
classpath 'com.github.dcendents:android-maven-gradle-plugin:2.0'
}
or using the new syntax since Gradle 2.1
plugins {
id "com.github.dcendents.android-maven" version "2.0"
}
using api in your library module allows you to access the transient dependencies only in your library code; not the apps that consume it.
so to achieve the desired effect you need to change in your sample module.
implementation project(':core')
to
api project(':core')
note you don't need to use api in your library it's better to use implementation as it speeds up your build.

What does the ":" mean in gradle android dependency package name?

For example if I depend on the Android Support Library, I add this line in the build.gradle:
dependencies {
...
compile "com.android.support:support-core-utils:24.2.0"
}
My questions are:
Where does the "support-core-utils" and version code is defined in
the support library?
What's the benefit of specifying the lib name and version
code?
The : is a separator used in the shortcut definition of an external library.
dependencies {
...
compile "com.android.support:support-core-utils:24.2.0"
}
stands for
dependencies {
...
compile group: 'com.android.support', name: 'support-core-utils', version: '24.2.0'
}
Here is some documentation.
About the Support library, you can read the support library features list in order to know which part of the support library to add to your project (instead of adding everything and ending with a huge APK :) )
To my mind, the benefit of specifying the version code, is to allow a developer to only update to the last version of a library, when he is sure that his code is compliant with the last changes in this library.
What does the “:” mean in gradle android dependency package name?
Where does the "support-core-utils" and version code is defined in the support library?
: is a separator to enable you to declare a maven dependency group ID, artifact ID and version in a concise way. All three are required to identify a dependency in a maven repository.
Android SDK manager installs a local maven repository ("Android Support Repository") where the actual versions of the support libraries are found.
What's the benefit of specifying the lib name and version code?
The build tooling can find your dependencies and successfully build code that depend on such libraries.

How to include a dependency inside an Android library?

Currently i'm writing a library for android that needs Volley to function. Currently, the Volley dependency is declared in both the dependencies block for the library and whatever app uses the library. What do I need to do so that my Library can pull in its needed dependencies itself, instead of having the implementing app also declaring the dependency?
Gradle supports transitive dependencies.
For a local library, this works like this:
compile(project(:LIBRARY_NAME)) {
transitive=true
}
For remote libraries:
compile ('com.somepackage:LIBRARY_NAME:1.0.0'){
transitive=true //default, normally no need to specify explicitly
}

Categories

Resources