Gradle multi-project android library set-up with maven local - android

I am trying to set-up a new project which includes two android library projects (aar). Let's call them foo and bar.
Since this is all new at the time of writing, I am using Android Studio 1.2.2, Android Build Tools 1.1, Gradle Wrapper 2.2.1.
foo depends on bar and in order to have the Gradle build work, I need to specify the dependency from sources like so:
dependencies {
compile project(':bar')
}
I need to publish at least foo to a local maven repository so that it can be picked up by a separate application project baz which depends on the foo. baz is in a completely separate project and Gradle build.
This I have achieved by using the maven plug-in and adding the following to foo's build.gradle:
task uploadArchives(type: Upload) {
repositories.mavenInstaller {
configuration = configurations.getByName(Dependency.DEFAULT_CONFIGURATION)
pom.groupId = "com.example"
pom.artifactId = "foo"
pom.version = "0.0.2-SNAPSHOT"
}
}
And including the maven dependency in the baz build as usual like so:
dependencies {
compile 'com.example:foo:+'
}
Now the problem I'm having is that the the baz application fails at runtime because it is missing the depencencies from bar! (ClassNotFoundException).
Inspecting the foo aar that is published into maven local I can see it doesn't have any of bar in it, neither is bar referenced in the pom for foo.
How does one go about getting Gradle to include the proper dependency information for foo in the pom from the information above?
I tried alternatively to change the build for foo by specifying bar as a maven dependency:
dependencies {
compile 'com.example:bar:+'
}
But in this case the Gradle build for bar and foo both fail at the configuration stage because of course bar can't be found on maven local yet (it hasn't been built!) - remember they are both in a multi-project set-up.
What is the proper way around this?
Are there any pointers for good practices for multi-project and android library project set-ups like this?
I am also confused by the existence of the maven and maven-publishing plug-ins. What is the most appropriate standard to be used for Android Library set-up?
I am sorry for including multiple questions in a single post, I hope as I gain clarity on the right direction I can edit and make this a more helpful question / answer that can help others who are lost as I am.
Thanks!

Well, after a TON of fighting and still not completely solid on the details, I think I found some light on the issue.
From what I gather, specifying bar as a source project dependency of foo is the right thing to do. In theory, the maven plug-in should be able to construct the proper dependencies in the pom file if everything is set-up correctly.
What I was having trouble with is in getting the maven publishing configured properly.
What I was able to conclude so far is that using mavenInstaller things work easily but the pom is incorrectly formed (missing dependencies). If on the other hand I use mavenDeployer, then the pom is generated with dependencies. It only took me much longer to get it to work because it fails with all sorts of exceptions if not set-up properly - and I don't know why.
The one combination that worked for me and hopefully can help others is this:
afterEvaluate { project ->
uploadArchives {
repositories {
mavenDeployer {
repository(url: mavenLocal().url)
}
}
}
}
I hope this helps other lost souls and helps bring more clarity on this issue

Related

How to find gradle dependency URL

For example, here is MikePenz MaterialDrawer library:
compile('com.mikepenz:materialdrawer:4.6.4#aar') {
transitive = true
}
Here's another one for the FancyButtons library
compile 'com.github.medyo:fancybuttons:1.5#aar'
Where did these compile lines come from? I ask because I just forked a project and made a slight change, and now I want to use this project in my app, but I don't want to download the project, import module into Android Studio, and then go from there (I haven't had much luck). How can I create a one-line snippet.
Here's the project I want to compile using this method
For the examples your listed, they likely come from jCenter or mavenCentral. Where you get them from is determined from your build.gradle repositories section. You might have something like:
repositories {
jCenter()
}
which is basically saying, when a line like compile ... appears in the dependencies section, go look for the required files on jCenter.
How did the files get there in the first place? The authors of the original projects published their aar files to these repositories. How do you get your modified libraries up there as well? Look up publishing. Here is the help page on publishing to jCenter.
Thing to note is that, you do not necessarily have to publish to a public repository. You can even host your own local repository or even just publish to a local filesystem folder. Which ever repo you publish to, make sure to include that repo in the repositories section of the other project that you want to consume your library from and the dependency will be automatically fetched from the repo with just a compile ... line.

How can I specify the latest commit version in Gradle

I'm using Gradle in my Android project,and I have added some dependencies in build.gradle file.For some reasons,I want to point to the latest commit for one of my dependencies.For example:
dependencies {
...
compile 'com.github.ozodrukh:CircularReveal:1.1.0#aar'
}
I'm specifying CircularReveal's version to be 1.1.0#aar,and I know currently it has fixed some bugs but have not released it yet.How can I specify a commit in Gradle?I know some basics about Cocoapods,and it can be done like this:
pod 'AFNetworking', :git => 'https://github.com/gowalla/AFNetworking.git', :commit => '082f8319af'
Can it be done in Gradle? Any help would be greatly appreciated.
You can not do this directly from Gradle, but there are Gradle plugins and tools you can use to achieve this.
You can do this using Jitpack, an external tool. All you need to do is specify Jitpack as a repository:
repositories {
maven {
url "https://jitpack.io"
}
// Define your other dependency repositories, if any
}
Then include your dependency:
dependencies {
compile 'com.github.ozodrukh:CircularReveal:25aeca505d'
// Include your other dependencies, if any
}
You can also use use the gradle-git-repo-plugin from Layer, but I haven't tried this one yet. An advantage(?) of this plugin is that it clones the repository on your local machine and adds it as a dependency from there.
Ugo response is probably the correct one, here's an alternative for some specific cases:
dependencies {
...
compile 'com.github.ozodrukh:CircularReveal:1.1.+#aar'
// or 1.+ or even just +
}
That puts you on the latest version, no matter which one it is. Now, if you repository builds on a CI environment and deploys snapshots to Sonatype or a similar service, you can do
repositories {
maven {
url "https://project.sonatype.io"
}
}
And along with the other change you'll end up in the -SNAPSHOT versions. This behaviour reports warnings on build because your builds will not be reproducible, but that's a given if you're targeting CI versions.

How to Build AAR and Sample Application

I'm running into a collection of gradle problems in setting up a multi-module project. I'm trying to produce an AAR that contains an SDK for our customers use. I'm also trying to produce a sample application that uses that AAR both as a development platform internally and as an example for our customers of how to use the platform.
settings.gradle:
include :sdk
include :SampleApplication
build.gradle:
...
// copy the AAR produced by the SDK into the SampleApplication
task import_aar(type: Copy) {
dependsOn ":sdk:build"
from(new File(project(':sdk').getBuildDir(), 'outputs/aar')) {
include '*-release.aar'
rename '(.*)-release.aar', '$1-v1.0.0.aar'
}
into new File(project(':SampleApplication').projectDir, 'aars')
}
...
SampleApplication/build.gradle:
...
repositories {
...
flatDir {
dirs 'aars'
}
}
...
dependencies {
...
// This causes gradle to fail if the AAR hasn't been copied yet
compile 'com.moxiesoft.netagent:moxieMobileSDK:+#aar'
compile project(':moxieMobileSDK')
...
}
So the biggest problem that I'm having right now is getting the import_aar task to run before the compileDebug/ReleaseSources tasks. I've tried adding explicit dependencies to the compile tasks, but I'm apparently not finding the right way to do it.
I've tried putting this in SampleApplication/settings.gradle:
tasks['compileReleaseSources'].dependsOn(':import_aar')
but gradle fails because there's no compileReleaseSources task, even though gradle :SampleApplication:tasks shows one.
I also tried putting similar stuff in settings.gradle, but it also failed with an error that the task compileReleaseSources didn't exist.
I did have limited success by putting this in my SampleApplication/settings.gradle:
tasks['build'].dependsOn(':import_aar')
But that only has the correct affect if I use "gradle build", which doesn't happen if I'm debugging or running from Android Studio.
I was finally able to get this to work by putting the dependsOn on the preBuild task, but I'm still not particularly happy with the solution, because:
It requires me to have the aar in place before gradle runs, which
means I wind up putting the .aar into git, which isn't a
particularly good idea.
I'd rather not have the AAR generation leaking into the
SampleApplication/build.gradle file, since that's intended for
customer usage.
Is there a better way of handling the problem in general?
I also had problem adding a dependency to compileReleaseSources task and described here a solution that worked for me. In short, the dependency need to be added in tasks.whenTaskAdded closure.

Best practice for buildscript tag in build.gradle of library projects

I'm wondering what is the best / intended way of defining build script repositories and dependencies for Android library projects.
Out in the wild (like Github) most of the repos define the following in there build.gradle
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:1.0.0'
} }
But if I create a library project in Android Studio this buildscript block does not get created, as it is already in the root build.gradle file, and therefore not necessary (I assume).
So what is the proper way, only defining it once in the root build.gradle or for each library project (which also means updating the version number for each library in case of new plugin versions). Or does it depend whether I want to release the library independently from my main application?
If you're developing a library, there isn't really a top-level build.gradle: that top level applies to all modules in a multimodule project, but a library is best implemented as a standalone single module.
Probably the best practice would be to have a single build.gradle file for your library module, and include a buildscript block in it with the repository and Android plugin Gradle version. That way it stands alone better, and it's not implicitly dependent on being in a project that has a top-level build.gradle file.
There's a huge caveat which kind of renders a lot of this moot, however -- if you include this module, with its own buildscript block, in a project that has a top-level build.gradle with a competing buildscript block, the top-level build file will win and it will ignore the block in your module.
This probably isn't much of a problem, but if your module relied on a specific version of the Android Gradle plugin, for example, and it was in a project that used a different version of the plugin, then your module would lose and it could run into problems. Another way of saying it is that it can only use one version of a plugin for all of the modules in a single build, and I believe the first one to specify it sets it for everyone.
In practice, this is only likely to be an issue if you rely on some feature specific to a later-than-1.0 version of the Android Gradle plugin, and it's included in a project that uses 1.0.
There are some subtleties here that I'll mention but won't answer (and I apologize for answering your question with more questions) -- if anyone else knows for sure, please answer yourself, or edit my answer, or mention it in the comments:
What if your buildscript block adds new plugins to the classpath? Do they get added or are they ignored?
What if your buildscript block adds new repositories to the search path? Will they get picked up?

Studio failed to download library from gradle repository

I already saw this question, but it is not helping me. First of all, I tried to add google play services in my project using:
dependencies{
compile 'com.google.android.gms:play-services:6.5.87'
}
It was showing me error:
Then I updated my studio to 1.0.1 and gradle to 1.0.0. And then I again synced the project with gradle. And it worked! It showed me another option despite of two options shown in above screenshot. It was "Install the library"(something like that). I clicked it and it popped up a dialog, and I installed the library(it was like downloadind using SDK manager and not like gradle downloads).
Now, I tried to download this library using:
compile('com.fortysevendeg.swipelistview:swipelistview:1.0-SNAPSHOT#aar') {
transitive = true
}
And it gives me error:
My android repository is updated:
Also, my internet connection is working fine. I tried to sync project many times, but same error all the time. I am not running gradle in offline mode:
How to fix this? And what is the permanent solution? And why is all this happening?
I found this question: Studio failed to download library from gradle repository which describes the exact same error, and that question had this bit of build script that you need to add to the build file that has the dependency statement in question:
repositories {
maven { url 'http://clinker.47deg.com/nexus/content/groups/public' }
}
When I do this, it works for me.
As to the general question of why this happens (and the better question of why the solution is different for different libraries):
Gradle, the build system that Android Studio uses, has the ability to automatically download library dependencies from the Internet. By and large this is a big boon for developers, because instead of having to manually download archive files, put them in the right place in your project, check them into source control, and repeat the process for new versions, now you just have to add a line of build script and the build system takes care of the housekeeping for you. The major downsides are Internet connectivity woes, which affect different developers to different degrees, and some added confusion about what it means when you get an error.
How does Gradle know where to download dependencies? Most Gradle build scripts contain a block that looks like this:
repositories {
jcenter()
}
or it may be mavenCentral() instead of jcenter(). This tells the build system to look in the JCenter or Maven Central global repositories (and JCenter is in a simplistic way of thinking about it a value-added mirror of MavenCentral); these contain archives of many versions of many, many, many libraries and are very convenient to use.
You can specify other repositories as well. This swipelistview library hasn't been uploaded to Maven Central, so the developer has made a repository for it available via a URL: if you add that URL to your repositories block, it will look for it there.
I was worried about the fact that you're accessing a SNAPSHOT version of the library -- these are supposed to be unpublished by definition. But adding a dependency on the snapshot version of the library in my test project worked for me, and looking around that URL in a web browser reveals that there's only a "1.0-" (trailing dash included) version of the library, so there's some subtletly there I'm missing; if you know more, please edit my answer or comment.
In any event, there are a couple caveats to this explanation. Some libraries aren't on Maven Central or on any Internet-accessible archive (at least they're not officially published by Android), but are instead published as part of the Android SDK download and maintained via the SDK manager. The Android support libraries and Google libraries fall under this category. If you get errors about those not being found, you have to fix it via the SDK manager.
How does the build system know to look in the SDK for those, since you didn't tell it via the repositories block? This behavior is hardcoded into the Android Gradle plugin.
The other caveat is that there's a detail that trips up a lot of people, which is that you actually have two repositories blocks, though with the usual Android Studio setup they're often in different files. One is in a buildscript block, which usually lives in the top-level build.gradle file and looks like this:
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:1.0.0'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
The other often also lives in the top-level build.gradle, but you can augment it with another block in your module's build.gradle file. The top-level one looks like this:
allprojects {
repositories {
jcenter()
}
}
and a module-level one would look like one of the previous examples in this answer. What do all of these mean?
The buildscript block tells Gradle where to find build system plugins. These are plugins that enhance the functionality of the build system itself but don't say anything about your actual project. In Android projects, the Android Gradle plugin is in this category, and unlike the Android/Google libraries, this one does live on Maven Central. The repositories block (in coordination with the dependencies block, which is not the same as the dependencies block for your project, keep reading) in buildscript tells the build system where to go look for these plugins.
The allprojects block in the top-level build file tells the build system to apply the bit of contained script to all build files in the project. In this example, it's telling it to add a repositories block pointing to JCenter to all subprojects. This is a convenience so you don't have to copy/paste it into multiple build files in your modules.
In your modules, you also have a repositories block, which in conjunction with the allprojects thingy, tells the build system where to go to get library dependencies for your project, as was previously discussed.

Categories

Resources