Gradle create multi project Jar

2020-06-30 04:22发布

问题:

So I've been playing in Gradle and Android Studio now since the early days of their inception. However, I find myself banging my head on the walls far more times then it is worth at times :(.

I have spent a day and a half trying to resolve my current dilemma.

Where I work we use a lot of shared library projects. This means that unlike Gradle's native assumption, my projects are NOT all nested under one parent project. (BUT this is NOT my question) I have gotten this working.

After our projects have become complete and ready to go, it has been asked to create an SDK for the current project infrastructure for external use. Now in the old IntelliJ I would simply generate some JavaDocs and create an Artifact that includes all dependencies, then another on that does not include the dependency jars and name them respectfully.

However, in Gradle this appears to be very difficult, maybe even unsupported, and I can't find anyone else that has done it after more then 10 hours of Googling and trial and error, I finally decided to make a demo project to show exactly what I'm doing and what I'm trying to accomplish.

I need to do a few things.

  1. Generate a Jar file that includes ALL module dependency code and dependent Jar files
  2. Generate a Jar file that includes ALL module dependency code and ZERO dependent Jar files
  3. Generate an AAR file that includes All module dependency code and dependent Jar files as well as resources for launching our Activity if they want to use it.
  4. Generate an AAR file that includes All module dependency code and ZERO Jar files as well as resources for launching our Activity if they want to use it.

So there in lies my problem. Each module when running a Task with (type: Jar) simply generates it's own code. I'm managed to get the dependent Jar files to compile in once, but then there is no regular source code, but I have NEVER been able to get a Module's source code to be included in the Jar file which is my biggest hurdle right now.

Here is a list of Tasks that I have tried without accomplishing this simple task yet.

    evaluationDependsOn(':dependencyModule')


task myJar(type: Jar){
    appendix = 'myJar'
    from android.sourceSets.main.allSource.files
}

task uberJar (type: Jar){
    from(configurations.compile.collect { it.isDirectory() ? it : zipTree(it) }) {
        exclude "META-INF/*.SF"
        exclude "META-INF/*.DSA"
        exclude "META-INF/*.RSA"
    }
}

task fatJar(type: Jar, dependsOn: 'compileJava') {
    from {
        sourceSets.main.output.classesDir
    }

    // Add all dependencies except for android.jar to the fat jar
    from {
        configurations.compile.findAll {
            it.getName() != 'android.jar'
        }.collect {
            it.isDirectory() ? it : zipTree(it)
        }
    }

    archiveName = 'fatJar.jar'
}

task jarFat(type: Jar) {
    appendix = "fat"
    from android.sourceSets.main.java
    from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } }
}

task sourcesJar(type: Jar) {
    from android.sourceSets.main.allSource
    classifier = 'sources'
}

task clearJar(type: Delete) {
    delete 'build/libs/myCompiledLibrary.jar'
}

task makeJar(type: Copy) {
    from('build/bundles/release/')
    into('build/libs/')
    include('classes.jar')
    rename ('classes.jar', 'myCompiledLibrary.jar')
}

makeJar.dependsOn(clearJar, build)

task jar(type: Jar) {
    from android.sourceSets.main.allJava
}

task deployJar(type: Jar, dependsOn: jar) {
    baseName = project.name + '-deploy'
    deps = configurations.runtime + configurations.archives.allArtifactFiles
    depClasses = { deps.collect { it.isDirectory() ? it : zipTree(it) } }
    from(depClasses) {
        exclude 'META-INF/MANIFEST.MF'
    }
}

task modelJar(type: Jar) {
    from sourceSets.main.output
}
task jarWithDependency(type: Jar){
    from android.sourceSets.main.classesDir
    from {configurations.compile.collect {zipTree(it)}}
}

task androidJavadocs(type: Javadoc) {
    source = android.sourceSets.main.allJava
}

Nothing has quite done the job yet. Any help would be greatly appreciated!! Thanks in advance for taking the time to look at this. I have the full functioning Sample Project if anyone would like it, but I don't see an option to upload here so is the link to the Demo project I built. It is very small and very easy to follow. One class or method basically per Project.

Demo Project

回答1:

Using the application plugin, you can just call "distZip" to get a zip with all the libraries. By default you get a bin directory with a batch file and a shell script to run the program and a lib directory with all the jar files.

You probably want to update the Manifest to include all the necessary libraries like the following (I have additional stuff in mine).

EDIT I removed the references to "project" because it should not be necessary in this instance.

 jar.doFirst
 {
     // aggregate all the jars needed at runtime into a local variable (array)
     def manifestClasspath = configurations.runtime.collect { it.name }

     // remove duplicate jar names, and join the array into a single string
     manifestClasspath = manifestClasspath.unique().join(" ")

     // set manifest attributes - mainClassName must be set before it is used here
     manifest.attributes.put("Main-Class", mainClassName)
     manifest.attributes.put("Class-Path", manifestClasspath)
 }

I'm not an Android developer, so you would have to add some additional code for the AAR stuff.



回答2:

Update from Author. Ok as time has gone on, I have learned that the best practice is to allow dependency management tools to do their job and not try to package these files as such.

You can create fat jars and fat aar files, there are plugins to help, but it is hacky and doesn't allow the user to exclude transitives properly if they are nested in the compiled product. the exclude is intended for maven server pom files to include or exclude dependency files.

So using a Maven Repo Server is the best way to manage this instead as the FAT compiler plugins are unreliable and break with each gradle update and more importantly limit your user's ability to exclude "some and not all" when it comes to transitives.

So stay away from doing this if you can avoid it and do it the right way I recommend it. I'll leave this post up in case anyone else was heading down this bad path as well and hope you move to the right path of dependency management servers with transitive dependency managed by pom files.