How can I resolve Android Studio 4.2 build errors after removing jcenter()?

Viewed 989

I have upgraded Android Studio from 4.1.3 to 4.2, using latest gradle and gradle plugin. Now references to using jcenter() in the build script are deprecated due to jcenter being end-of-lifed:

enter image description here

The suggestion is to "migrate" to mavenCentral(). I have various dependencies that are seemingly not on mavenCentral(), because gradle cannot find them, for example:

enter image description here

I Googled the artifact ("materialsearchview" in this case) and found it on the search platform "MVNrepository":

enter image description here

So here is what I have tried (all unsuccessful) to put a reference into my build script to have gradle find this artifact:

  1. I added a reference to the mvnrepository to my project level build.gradle file (which I didn't expect to work given that mvnrepository is a search mechanism) highlighted in the red box in the pic, i.e.:

    maven { url 'https://mvnrepository.com/artifact/' }

  2. I added a reference to the repository identified in the blue box at the bottom where mvnrepository says the artifact is located, i.e.

    maven {url 'https://repo.spring.io/plugins-release/'}

This generated a slightly different error:

Could not HEAD 'https://repo.spring.io/plugins-release/com/miguelcatalan/materialsearchview/1.4.0/materialsearchview-1.4.0.pom'. Received status code 401 from server: Unauthorized
  1. I found the .aar file for this dependency, added it to my 'libs' directory and updated my app module level build.gradle file like this:

    implementation fileTree(include: ['.jar','.aar'], dir: 'libs')

  2. I did an 'invalidate caches and restart' at this point, thinking AS needed to index the newly added .aar file before gradle would recognize it. No joy.

  3. I specifically added the .aar file to the libs directory, then added a reference to it in the app module build.gradle:

    implementation(name:'materialsearchview-1.4.0', ext:'aar')

then did another invalidate cache/restart. No joy.

So I guess I have three questions:

  1. Once I find a reference to an artiface in mvnrepository, is there a proper way to reference it in my gradle script so that the build system can reconcile what it needs?

  2. What other ways are there to find what other repositories that gradle CAN address to see if the item is there?

  3. Why is using the .aar file in the libs directory as I am doing it failing? Why can't Gradle see it there?

Thanks!

2 Answers

After discussing this with Mark Murphy of CommonsWare, I realized I was under a misunderstanding about the relationship between the repositories section of the project level build.gradle file, and the implementation statements of the module level build.gradle file.

Here is a good way to think of it thanks to Mark:

Project level build.gradle, i.e.:

repositories {
    google()
    mavenCentral()
    maven { url 'https://maven.preemptive.com/' }
    maven { url 'https://jitpack.io' }
    //jcenter()
}

Think of these as "Gradle, look into these repositories to reconcile all the 'implementation' statements."

Then in the module level build.gradle I had this:

implementation fileTree(include: ['*.jar','*.aar'], dir: 'libs')

Think of this as "Oh yeah, grab all these things too, even if I didn't mention them as specific dependencies".

My mistake #1 was in thinking I could have an .aar file in the libs directory which ALSO had a corresponding 'implementation' statement. You can't.

My mistake #2 was that I had an implementation statement that referenced a .aar file that was in maven (which is fine since maven is in my repositories block) which itself referenced an .aar file that was not in maven but only in jcenter (which is not since I just removed jcenter from the repositories block). When I removed the reference to jcenter in the repositories block this dependency ("transitive dependency") was not reconciled and the build failed.

So lessons learned:

Any resource referenced in an 'implementation' statement AND ANY RESOURCE THAT IS IN ITS POM THAT IT DEPENDS ON must ALL be in repositories that you define in the repositories block.

If ANY of the dependencies were in jcenter, since I got rid of jcenter then I must:

  1. Find another repository instead of jcenter that has the same resources needed to satisfy the ALL dependencies associated with the resource in question OR
  2. Gather all the .jar/.aar files that represent that resource (the one you want and all the ones it references), place them in the /libs directory (under the module you are building), make sure your have your fileTree statement correctly formed, and REMOVE references to all those same resources from your 'implementations' statements.

How does one identify all the dependencies you ask? Well you can do it the slow way (like I did at first) and keep finding/adding them until the build doesn't break anymore. Or you can be more clever about it and let Gradle tell you which it will do if you ask it (see the docs here).

Finally - don't forget that it is not enough to make sure the referenced .aar file is in libs. In other words, Gradle does not work like: "I will look first at the repositories to satisfy your implementation dependencies and any dependency they reference, and if they are not there then I will look through all the .jar and .aar files in the spot you told me to look in the fileTree statement". Instead, note that any dependency that is referenced by an item in an 'implementation' statement needs to ALSO be able to be found within the repositories. If it can't then your only choice is to use that dependency graph, determine ALL the dependencies, and put all the .aar files into /libs AND remove any from your 'implementation' statements.

Much easier if you can find another repository instead of messing with all the individual .aar files!

For those who want to try the easier way, just go here Android Studio Archive and download the Android Studio v4.1 (Oct 12, 2020) and install it. It is working fine, I have checked it myself.

Related