when I sync my Android project, I keep seeing the following messages:
Gradle: Download https://s3.amazonaws.com/moat-sdk-builds/com/google/android/gms/play-services-ads-base/maven-metadata.xml
Gradle: Download https://s3.amazonaws.com/moat-sdk-builds/com/google/android/gms/play-services-measurement-base/maven-metadata.xml
Gradle: Download https://s3.amazonaws.com/moat-sdk-builds/com/google/firebase/firebase-iid/maven-metadata.xml
These libraries should be found in google() repo, which is the first one in my settings:
allprojects {
repositories {
google()
jcenter()
// ...
maven { url "https://s3.amazonaws.com/moat-sdk-builds" }
}
}
However, it looks into maven { url "https://s3.amazonaws.com/moat-sdk-builds" } and wastes a lot of time. What's going on here? And is there any way to debug it? Thanks.
You can try to customize dependency resolution behaviour or declare repository filters.
Declaring a repository filter is as easy as this:
allprojects {
repositories {
google()
jcenter()
// ...
maven {
url "https://s3.amazonaws.com/moat-sdk-builds"
content {
// Does only include this group
includeGroup "moat.sdk"
}
}
}
}
There is also the option to exclude groups and enhance for example the build performance.
Take care that "Matching repositories to dependencies is an incubating feature." The API documentation provide more information about filter options.
You can find more information on the specific behaviour you experience below. When it comes to dependency resolution Gradle does inspect repositories in order.
How dependency resolution works
[...]
Given a required dependency, Gradle attempts to resolve the dependency by searching for the module the dependency points at. Each repository is inspected in order. Depending on the type of repository, Gradle looks for metadata files describing the module (.module, .pom or ivy.xml file) or directly for artifact files.
[...]
But as i understand it gradle 'visits' each repository irrespective of whether it has already found the 'correct' artifacts or not.
Once each repository has been inspected for the module, Gradle will choose the 'best' one to use. This is done using the following criteria:
For a dynamic version, a 'higher' concrete version is preferred over a 'lower' version.
Modules declared by a module metadata file (.module, .pom or ivy.xml file) are preferred over modules that have an artifact file only.
Modules from earlier repositories are preferred over modules in later repositories.
When the dependency is declared by a concrete version and a module metadata file is found in a repository, there is no need to continue searching later repositories and the remainder of the process is short-circuited.
[...]
Introduction to Dependency Management - How dependency resolution works
Related
I have a library module where I used a dependency which is based on a private maven repository, I can use this dependency in my library and everything works well.
The problem occurs when I try to use the library module inside my application, the build is failing, for some reason is looking to get this dependency from a different maven repository (in this case, my personal one, which is available only in my app)
I've switched from implementation to api and viceversa, just so check if this might solve the issue, but it is not.
If I add the maven repository url also in my app, everything works well, but I don't what that. Is this the expected behaviour?
Thanks!
Yes, repositories declared in one subproject are not shared with other subprojects. Other than with Maven, repositories are also not taken from a dependency POM file or otherwise inherited from a dependency. On this topic, the Gradle docs state the following:
Strict limitation to declared repositories
Maven POM metadata can reference additional repositories. These will be ignored by Gradle, which will only use the repositories declared in the build itself.
However, you can probably centralize the repository declaration in your top-level settings.gradle(.kts) file:
dependencyResolutionManagement {
repositories {
// TODO Configure the shared repository here.
}
}
You can find more details on this centralization in the Gradle docs.
In the build.gradle of a module, I'm trying to execute the following line
if (!jsonFile.exists()) {
new URL(mapUrl).withInputStream{ i -> jsonFile.withOutputStream{ it << i }}
}
The build fails with the error:
Server returned HTTP response code: 401 for URL: https://artifactory.myurl.com/artifactory/myfile.json
I pass the credentials to my gradle script as follows:
buildscript {
repositories {
google()
jcenter()
maven {
url 'https://artifactory.myurl.com/artifactory/'
credentials {
username = "myuser"
password = "mypwd"
}
}
}
}
Well, there are several problems in your code:
First, withInputStream and withOutputStream are Groovy JDK enhancements on the Java classes URL and File. This is not related to any Gradle functionality and only works, because Gradle is built on top of Groovy. As far as I know, it is not possible to pass credentials to withInputStream, so it only works for resources that are publicly available.
Regarding the second part of your code snippet, lets first take a look at the buildscript block. It is a special Gradle block that always will be evaluated first (and must be at the top of a build.gradle file). The reason for this is that this block basically provides as a setup for your build script (aka the build.gradle file). Usually this block defines the repositories and the dependencies that need to be resolved for the build script to work (e.g. plugins). Regular project dependencies and their repositories may be defined outside of the buildscript block. They are resolved when other task (e.g. compilation tasks) need them.
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'example-plugins:my-fancy-plugin:0.0.1'
}
}
// the build script stops here to resolve my-fancy-plugin from jcenter
repositories {
jcenter()
}
dependencies {
implementation 'example-libraries:my-cool-library:0.0.1'
}
// this won't be resolved directly, only if a task that needs *implementation* dependencies is run
The repositories/dependencies mechanism is mainly used to resolve *.jar files that serve as dependencies of JVM-based projects. The repositories are usually Maven repositories. Maven repositories follow a specific layout, so the dependency descriptors (e.g. example-libraries:my-cool-library:0.0.1) will be mapped to URLs (e.g. example/libraries/my-cool-library/0.0.1/my-cool-library-0.0.1.jar). Gradle then tries to download the dependencies from this URL. Since your path does not follow the Maven repository layout, you can't download your file from a Maven repository.
For your use case you probably should not use the Gradle dependency resolution at all. There is a plugin that allows downloading files using a Gradle task (with support for authentication):
task downloadFile(type: Download) {
src 'https://artifactory.myurl.com/artifactory/myfile.json'
username = "myuser"
password = "mypwd"
dest buildDir
}
Alternatively you may define an Ivy repository with a custom repository layout.
I am trying to add an external dependency from jcenter
compile 'com.droidninja:filepicker:2.0.4'
but I keep getting these errors and I can't figure out what is going wrong.
I have seen the same errors come up in lot of projects but nobody seems to know whats going wrong.
The problem is not with the dependency you just added but the Android Support library's dependencies. The latest SDK updates move towards using the remote Google Maven repository instead of downloading everything to be available locally. In order to fix dependency resolution problems follow the Adding Support Libraries guide. Really briefly this is what you have to do:
Open your project's build.gradle (note that this is not the module's file!)
Add the Google Maven repo to the project repositories:
allprojects {
repositories {
jcenter()
maven {
url "https://maven.google.com"
}
}
}
It's also recommended to add the repo to the buildscript block too, so later on the Gradle plugins can be downloaded from there too:
buildscript {
repositories {
jcenter()
maven {
url "https://maven.google.com"
}
}
In the following simple build.gradle file, i have some basic questions.
1.In repositories, when i specify mavenCentral(), is it the repository where all the libraries that i specify like compile 'com.android.support:support-v4:21.0.2'will be searched? Is there anything else for this apart from mavenCentral()? And what is the url required for after that(oss.sonatype..)?
2.What are the items that should be specified in classpath? Why cant the classpath items be specified like we specify the support libraries?
3.And for using a third party library, i had to specify an Amazon AWS URL at the bottom in allProjects() section. Why is this URL required?
buildscript {
repositories {
mavenCentral()
maven {
url "https://oss.sonatype.org/content/repositories/snapshots/"
}
}
dependencies {
classpath 'com.android.tools.build:gradle:1.0.0'
classpath 'com.jimdo.gradle:gradle-apt-plugin:0.2-SNAPSHOT'
}
}
allprojects {
repositories {
mavenCentral()
maven {
url "https://s3-ap-southeast-1.amazonaws.com/abc-release/abc/"
}
}
}
1.In repositories, when i specify mavenCentral(), is it the repository where all the libraries
No, you also have an implicit local Maven repository (usually at ~/.m2) which can also be searched for locally installed packages. The newer Android Studio builds use jcentral rather than Maven central, but the concept is the same: a central repository for packages.
2.What are the items that should be specified in classpath? Why cant the classpath items be specified like we specify the support libraries?
These are build tool (i.e. gradle) dependencies. Your app's dependencies are outlined in the app module's specific build.gradle file.
3.And for using a third party library, i had to specify an Amazon AWS URL at the bottom in allProjects() section. Why is this URL required?
Because their libraries are not in Maven central. So you're effectively pointing Maven to an outside repository you wish to use for your app and any of its libraries.
1.In repositories, when i specify mavenCentral(), is it the repository where all the libraries that i specify like compile 'com.android.support:support-v4:21.0.2'will be searched?
Yes, but only if it isn't in buildscript block.
Everything inside buildscript is used by build system – gradle and possibly some libraries for it.
allprojects.repositories is place where you declare repositories where libraries used by your application will be searched.
Say I need to use some proprietary jars in my android library. I want my library to be conveniently available from Maven Central, but I can't just put dependencies there due to legal issues.
I figured it's possible to use Internal Repository to host dependencies so they would be resolved automatically.
I've used Github repo, just like this one, and declared it in library pom.xml
However Gradle doesn't seem to be resolving this dependencies. If I manually declare my repository in main build.gradle everything works fine. Am I doing something wrong here, or android gradle plugind just don't support internal repositories?
It's discouraged in the Maven community to have repository declarations in published POMs, and Gradle won't honor them. Instead, downstream builds will have to declare the internal repository in one way or another (which shouldn't be a big deal).
If you (only) publish POMs for proprietary dependencies to Maven Central (which is a common solution to this problem at least if you own the dependencies), downstream builds will need to declare the internal repository as follows:
repositories {
maven {
url "https://repo1.maven.org/maven2"
artifactUrls "https://some.internal.repo"
}
}
If you don't publish proprietary dependencies to Maven Central at all (not even POMs), downstream builds will have to declare the internal repository as another regular Maven repository:
repositories {
mavenCentral()
maven {
url "https://some.internal.repo"
}
}
Note however that last time I checked, one of the rules of publishing to Maven Central was that dependencies needed to be available from Maven Central as well.
PS: Whether you are publishing a Java or Android library shouldn't matter here.