Android Library Gradle release JAR

22,939

Solution 1

While I haven't tried uploading the artifacts with a deployment to Sonatype (or even a local repo), here's what I managed to come up with a few weeks ago when trying to tackle the same problem.

android.libraryVariants.all { variant ->
  def name = variant.buildType.name
  if (name.equals(com.android.builder.core.BuilderConstants.DEBUG)) {
    return; // Skip debug builds.
  }
  def task = project.tasks.create "jar${name.capitalize()}", Jar
  task.dependsOn variant.javaCompile
  task.from variant.javaCompile.destinationDir
  artifacts.add('archives', task);
}

Then run the following:

./gradlew jarRelease

Solution 2

Another way to generate a jar from a library project through gradle is as follows:

In your library's build.gradle:

def jarName = 'someJarName.jar'

task clearJar(type: Delete) {
    delete "${project.buildDir}/libs/" + jarName
}

task makeJar(type: Copy) {
    from("${project.buildDir}/intermediates/bundles/release/")
    into("${project.buildDir}/libs/")
    include('classes.jar')
    rename('classes.jar', jarName)
}

makeJar.dependsOn(clearJar, build)

What we are doing here is just copying the classes.jar generated by the Android Gradle plugin. Be sure to look into your build directory for this file and see if its contents are in the way you want.

Then run the makeJar task and the resulting jar will be in library/build/libs/${jarName}.jar

The will have the class files according to your configuration for release. If you are obfuscating it, then the files in the jar will be obfuscated.

Share:
22,939
Marek Sebera
Author by

Marek Sebera

Updated on December 28, 2020

Comments

  • Marek Sebera
    Marek Sebera over 3 years

    How can I release Jar packaging of android-library project?
    I've found, classes.jar is located under build/bundles/release/classes.jar and I suppose this is correct Jar package (contains *.class files).

    Is there some official way, to release library as JAR instead of AAR ?

    Edit
    I use Gradle to release Maven artifacts, and I'd like to release JAR along with AAR package. So JAR with signature, md5, manifest, ...
    based on https://chris.banes.me/2013/08/27/pushing-aars-to-maven-central/

    apply plugin: 'maven'
    apply plugin: 'signing'
    
    configurations {
        archives {
            extendsFrom configurations.default
        }
    }
    
    def sonatypeRepositoryUrl
    if (isReleaseBuild()) {
        println 'RELEASE BUILD'
        sonatypeRepositoryUrl = "https://oss.sonatype.org/service/local/staging/deploy/maven2/"
    } else {
        println 'DEBUG BUILD'
        sonatypeRepositoryUrl = "https://oss.sonatype.org/content/repositories/snapshots/"
    }
    
    if(!hasProperty('nexusPassword')) {
        ext.set('nexusPassword', System.console().readPassword("\n\$ Type in password for Sonatype nexus account " + nexusUsername + ": "))
    }
    
    if(!signing.hasProperty('password')) {
        ext.set('signing.password', System.console().readPassword("\n\$ Type in GPG key password: "))
    }
    
    afterEvaluate { project ->
        uploadArchives {
            repositories {
                mavenDeployer {
                    beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) }
    
                    pom.artifactId = POM_ARTIFACT_ID
    
                    repository(url: sonatypeRepositoryUrl) {
                        authentication(userName: nexusUsername, password: nexusPassword)
                    }
    
                    pom.project {
                        name POM_NAME
                        packaging POM_PACKAGING
                        description POM_DESCRIPTION
                        url POM_URL
    
                        scm {
                            url POM_SCM_URL
                            connection POM_SCM_CONNECTION
                            developerConnection POM_SCM_DEV_CONNECTION
                        }
    
                        licenses {
                            license {
                                name POM_LICENCE_NAME
                                url POM_LICENCE_URL
                                distribution POM_LICENCE_DIST
                            }
                        }
    
                        developers {
                            developer {
                                id "loopj"
                                name "James Smith"
                            }
                            developer {
                                id "smarek"
                                name "Marek Sebera"
                            }
                        }
                    }
                }
            }
        }
    
        signing {
            required { isReleaseBuild() && gradle.taskGraph.hasTask("uploadArchives") }
            sign configurations.archives
        }
    
        task androidJavadocs(type: Javadoc) {
            source = android.sourceSets.main.java.srcDirs
        }
    
        task androidJavadocsJar(type: Jar) {
            classifier = 'javadoc'
            from androidJavadocs.destinationDir
        }
    
        task androidSourcesJar(type: Jar) {
            classifier = 'sources'
            from android.sourceSets.main.java.srcDirs
        }
    
        artifacts {
            archives androidSourcesJar
            archives androidJavadocsJar
        }
    }
    

    using

    task androidJar(type: Jar) {
        from android.sourceSets.main.java.srcDirs
    }
    

    will package only java files, not compiled and linked against android sdk

  • Marek Sebera
    Marek Sebera over 10 years
    I'm afraid, this is correct answer :-) Thanks, I'll post final edit I've made to get it work
  • CommonsWare
    CommonsWare over 10 years
    I can also confirm that this works. Note that the generated task does not show up when running gradle tasks, only with gradle tasks --all. Thanks again!
  • Sam
    Sam about 10 years
    Thanks this does help, but it still doesn't generate the class files for dependencies. I'm trying to make an SDK jar basically that will be a single jar to pass out, but this compile does not include module projects that it is dependent on and does not pull down jars from the dependency section etc.. Do you have any suggestions to accomplish this where it compiles the library projects into the jar as well so I don't have to hand out 4 jars, one for each library project. Then it would be nice to figure out how to include the maven dependency jars too like Gson or Otto.
  • Kevin
    Kevin almost 10 years
    This seems to break for me when I add flavors because it tries to create several of the same named tasks without a flavor included. I'm no Groovy guy and cannot figure out how to add the flavor to the task name. I'd appreciate any hints on how to do that.
  • Piklor
    Piklor almost 10 years
    I had a small addition to Jake's solution that accounts for any java resources - add task.dependsOn variant.processJavaResources and task.from variant.processJavaResources.destinationDir (sorry, couldn't work out how to format this properly)
  • MikeL
    MikeL over 9 years
    Can someone point out how can I use proguard with this configuration? It seems that defining the buildTypes with proguard does not apply.
  • dbm
    dbm over 9 years
    @Kevin, I exchanged the "jar${name.capitalize()}" part with "jar${variant.name.capitalize()}" to make the task account for the flavour name too (the variant.name is composed from both buildType name and productFlavor name)
  • Jani
    Jani over 9 years
    @SamDozor please follow the link for proguard support survivingwithandroid.com/2014/05/…
  • keno
    keno about 9 years
    @Piklor, I tried adding your lines for getting the resources included but it didn't work. Could you mention the entire task code you used please
  • Piklor
    Piklor about 9 years
    @keno, unfortunately I can't locate the code in question.
  • 2cupsOfTech
    2cupsOfTech over 8 years
    it seems this is not going to package a .png resource into the .jar, is there a way to package an image resource into the jar ?
  • 2cupsOfTech
    2cupsOfTech over 8 years
    @CommonsWare any thoughts on packaging images with gradle into jar?
  • CommonsWare
    CommonsWare over 8 years
    @2cupsOfTech: Well, you can't put Android resources into a JAR, only an AAR. You're welcome to play around with classic Java resources in the JAR, but I have not tried it, and it's not commonly done.
  • 2cupsOfTech
    2cupsOfTech over 8 years
    @CommonsWare this script doesn't produce an obfuscated jar I believe, is that possible to do?
  • CommonsWare
    CommonsWare over 8 years
    @2cupsOfTech: Beats me
  • 2cupsOfTech
    2cupsOfTech over 8 years
    @jake-wharton how to build an obfuscated jar using your script?
  • Olinasc
    Olinasc over 8 years
    @2cupsOfTech to generate an obfuscated jar I used the alternative method of copying the Jar that is already generated by the library build in /build/intermediates/bundles/release (as mentioned by Jani). I guess Jani should an alternative answer here. It works for both obfuscated and non obfuscated libraries and seems simpler to me.
  • Olinasc
    Olinasc over 8 years
    @Jani you should post an answer here with your alternative method. It would help others as it also handles obfuscated cases.
  • 2cupsOfTech
    2cupsOfTech over 8 years
    @Olinasc I ended up writing a small shell script to convert a jar to an obfuscated jar using proguard
  • Olinasc
    Olinasc over 8 years
    @2cupsOfTech I understand. This seems though as more work than is needed. I will post the alternative answer here if Jani does not reply.
  • 2cupsOfTech
    2cupsOfTech over 8 years
    @Olinasc its a 1 line script, look into command: 'java -jar -outjars -injars', my script is not general otherwise I would post, this link could be helpful: proguard.sourceforge.net/manual/examples.html
  • Jani
    Jani over 8 years
    @2cupsOfTech I no longer have access to the build.gradle file that I used this alternative method. Please post the answer. I'm sorry for the inconvenience.
  • Jasper de Vries
    Jasper de Vries over 2 years
    I'm getting WARNING: API 'variant.getJavaCompile()' is obsolete and has been replaced with 'variant.getJavaCompileProvider()'. When I replace it, destinationDir is not found.