Gradle: package libraries into .aar?

3,155 views
Skip to first unread message

Pavel Dolgov

unread,
Aug 27, 2014, 8:45:19 PM8/27/14
to adt...@googlegroups.com
I have a library project with dependencies like:

LibraryProject
--\LibraryA
--\LibraryB
--\LibraryC

What I want to achieve is a LibraryProject.aar with all dependencies compiled and included, so when used in an application, there is no need to add any dependencies for LibraryA, LibraryB and LibraryC. What is the best way to achieve the goal? Thanks.

William Ferguson

unread,
Sep 1, 2014, 9:03:17 AM9/1/14
to adt...@googlegroups.com
As an AAR artifact deployed to your artifact repository with a POM that lists the 3 libraries as dependencies.

William

Pavel Dolgov

unread,
Sep 2, 2014, 5:26:54 PM9/2/14
to adt...@googlegroups.com
Thank you for the reply! But with such an approach resulting LibraryProject.aar will not have all dependencies packaged, unless I'm missing something.
What I'm doing right now is manually adding compiled classes to libs before packageLibrary task. Works in my particular case, but obviously ugly, looks like a hack does not work with resources, manifests and etc. What is the better gradle/android-library way?

android.libraryVariants.all { variant ->

        Action copyClassesAction = new Action() {
            @Override
            void execute(Object o) {

                String variantLibsDir = getBuildDir().absolutePath + "/intermediates/bundles/" + variant.name + "/libs"
                String explodedDir = getBuildDir().absolutePath + "/intermediates/exploded-aar/library-project/"
                String[] dirs = new File(explodedDir).list()
                for (int i = 0; i < dirs.length; i++) {
                    File source = new File(explodedDir + dirs[i] + "/unspecified/classes.jar")
                    File destination = new File(variantLibsDir + "/" + dirs[i] + ".jar")
                    destination.bytes = source.bytes
                }
            }
        }
        variant.packageLibrary.doFirst(copyClassesAction)

William Ferguson

unread,
Sep 2, 2014, 6:14:55 PM9/2/14
to adt...@googlegroups.com
On Wed, Sep 3, 2014 at 7:26 AM, Pavel Dolgov <pavel....@gmail.com> wrote:
Thank you for the reply! But with such an approach resulting LibraryProject.aar will not have all dependencies packaged, unless I'm missing something.

Correct. But when your AAR is consumed as a dependency it's dependencies can be brought in transitively, so it's not like the are lost. This means that you are free to upgrade or exclude one of those transitive dependencies when you have a version conflict with another dependency.

William

Jeffrey Decker

unread,
Feb 4, 2015, 4:53:51 PM2/4/15
to adt...@googlegroups.com
Hi Pavel,

Have you found any good way of doing this? More specifically I'm looking to include all dependencies for my android library project in the classes.jar, do you know if this is possible. I've set this up to work in ant but have yet to find any way of doing the same with gradle.

Thanks,
Jeffrey

Pavel Dolgov

unread,
Feb 5, 2015, 2:59:47 PM2/5/15
to adt...@googlegroups.com
Hi Jeffrey,

Unfortunately no, I didn't find any good way. What I'm having now is two branches, one for fast and easy development that have all dependencies as sources
dependencies {
      compile project(':internalLibraryA')
compile project(':internalLibraryB')
}

--
You received this message because you are subscribed to a topic in the Google Groups "adt-dev" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/adt-dev/Zh_2NOUQevo/unsubscribe.
To unsubscribe from this group and all its topics, send an email to adt-dev+u...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.



--
Best Regards,
Pavel Dolgov

Pavel Dolgov

unread,
Feb 5, 2015, 3:19:58 PM2/5/15
to adt...@googlegroups.com
Hi Jeffrey,

Unfortunately no, I didn't find any good way. What I'm having now is two branches, one "develop" for fast and easy development that has all dependencies as sources


dependencies {
    compile project(':internalLibraryA')
    compile project(':internalLibraryB')
}

and another "release" that has dependencies as jars and looks like this

ext.includeLibsFolder = 'libs-include'
dependencies {
    compile fileTree(dir: includeLibsFolder, include: '*.jar')
    includeLibs 'internalLibraryA:0.0.1'
    includeLibs 'internalLibraryB:0.0.1'
}
task copyLibs(type: Copy, dependsOn: 'cleanLibs') {
    from configurations.includeLibs
    into includeLibsFolder
}

task cleanLibs(type: Delete) {
    delete includeLibsFolder
}

When I ready to release my aar library, I compile all dependencies (internalLibraryA and internalLibraryB) and push it to the repository (Archiva in my case). Then checkout "release", copy libs to includeLibsFolder (gradle copyLibs), then build the library with all sub libraries included and obfuscated if needed.
Not the fastest solution, but does what I need. Let me know if you'll find a better solution.

Pavel

On Wed, Feb 4, 2015 at 4:53 PM, Jeffrey Decker <deckerj...@gmail.com> wrote:

--
You received this message because you are subscribed to a topic in the Google Groups "adt-dev" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/adt-dev/Zh_2NOUQevo/unsubscribe.
To unsubscribe from this group and all its topics, send an email to adt-dev+u...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Jeffrey Decker

unread,
Feb 5, 2015, 7:03:01 PM2/5/15
to adt...@googlegroups.com
Hey Pavel,

Thanks for the response. I have yet to find a better way but I'll make sure to let you know if I do. What I'm doing is a little different because I need to end up with a .jar instead of an .aar but I believe what you described should work for now. Either way it seems to me that this is a pretty common requirement, it seems a little silly how difficult it is to accomplish.

Thanks,
Jeffrey

William Ferguson

unread,
Feb 5, 2015, 7:22:44 PM2/5/15
to adt...@googlegroups.com

On Fri, Feb 6, 2015 at 10:03 AM, Jeffrey Decker <deckerj...@gmail.com> wrote:
Either way it seems to me that this is a pretty common requirement, it seems a little silly how difficult it is to accomplish.


Packaging up external dependencies into your own component that is designed for consumption within another component or application is generally a *really* bad idea as it leads to unresolvable conflicts between included libraries. 

Hence the rise of dependency management solutions such as that used by Maven over the last 15 years.

By all means do it, just do it knowing full well the pain that you may be causing your clients.

William
 

Jeffrey Decker

unread,
Feb 5, 2015, 8:12:11 PM2/5/15
to adt...@googlegroups.com
Hi William,

I appreciate the input and understand the problems that can arise here, those concerns vanish though if no 3rd party library is being included that the consumer of our library could include in their project. The main thing I'm trying to do is include a separate internal library in the library I want to distribute to a partner.

Example:

Lets say I have a library that I use strictly for handling api calls. I also have another library that will consume the original one and add an implementation layer to access the apis plus some code that conforms to a specific protocol for communication with the partners application. Our partners application will ultimately consume the full library containing the code from both the api library and implementation of non generic code. The api library is internal and used across many applications so it needs to be shared and not specific to this one implementation and including the source code in every consumer of this library isn't scalable.

Because there is 0 risk involved in a scenario like this, it seems a little strange that it isn't something that's easily doable. This is a pretty standard use case in my opinion and a pretty major miss from a user perspective.

Anyways, Pavel's solution of including the resulting jar from the other library build works as long as I do some more work to make sure it all gets packaged nicely. I understand that we could distribute both libraries separately but we originally used ant for our build and even minor changes for or partner like asking them to include 2 libraries instead of 1 is often a pain point. 

As an engineer I'd prefer to have all options available instead of being pigeonholed into doing something a certain way because it's been decided by someone else who Isn't in my shoes that it's the right way. People should be able to make their own mistakes and learn from them. Training wheels are only helpful for so long before they become a detrimentJust my two cents. I appreciate the words of caution though because I've run into and understand the issues that arise if someone isn't smart about what libraries they include with their own.

Thanks again,
Jeffrey

William Ferguson

unread,
Feb 5, 2015, 8:44:24 PM2/5/15
to adt...@googlegroups.com
OK, I under your scenario.

The way that is typically handled would be to create a artifact repo visible to your partner containing both artifacts. The same repo  could also be used by internal builds.

The alternative (what you are after): if your artifact (let's call it B) that consumes internal artifact A is the artifact that needs to be shared, then package up A inside B's build, is not supported by Gradle nor the Android-Maven-Plugin at this point.

But if you submit a PR to AMP then I'll review.

--

Jeffrey Decker

unread,
Feb 6, 2015, 1:06:14 PM2/6/15
to adt...@googlegroups.com
Thanks William,

Hopefully at some point I'll be afforded the time to add this in.

Thanks
Jeffrey

Edward Fleming

unread,
Jul 9, 2015, 12:49:21 PM7/9/15
to adt...@googlegroups.com
I'm a little confused.

I have three projects -- a Core, a Java EE Library, and an Android Library.

I am trying to package the Android Library as an AAR, and it needs to contain the Core.  The Core is useless by itself (all abstract classes/interfaces), and needs either the Java EE or the Android library with it to function.

I don't want to confuse our users and upload the Core to maven, I just simply want to include the Core.Jar inside the aar.

Is the consensus still that I have to manually copy the jar into the aar by hooking into the build task?  I can't believe this is that special of a use case, but I will do that hack if need be.

Thanks!
Reply all
Reply to author
Forward
0 new messages