I would like to create a Jar out of an Android library project. It is set up the following way:
ProjectName
\- lib
| \- lib
| \- armeabi
| \- libNativeFirst.so
| \- libNativeSecond.so
\- src
\- main
\- java
\- com.package.sdk
\- PackageSDK.java
I would like for all of this to be packaged in a Jar, but without revealing the source code present in PackageSDK.java
.
I set up my build.gradle
file like so:
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:0.5.+'
}
}
apply plugin: 'android-library'
repositories {
mavenCentral()
}
android {
compileSdkVersion 18
buildToolsVersion "18.0.1"
defaultConfig {
minSdkVersion 10
targetSdkVersion 18
}
sourceSets {
main {
java {
srcDir 'src/main/java'
}
resources {
srcDir 'src/../lib'
}
}
}
}
task jar(type: Jar) {
from android.sourceSets.main.allSource
}
When I run gradlew clean jar
in the project's directory, a Jar file is created in ProjectName\build\libs
called ProjectName.jar
. It's structure is as follows:
ProjectName.jar
\- lib
| \- armeabi
| \- libNativeFirst.so
| \- libNativeSecond.so
\- com
\- package
\- sdk
\- PackageSDK.java
I would like for the compiled PackageSDK.class
to be included instead of the PackageSDK.java
file when executing the jar
task. What can I change to achieve this?
Per Ben Manes's suggestion, I changed the configuration of the sourceSets
to the following:
sourceSets {
main {
java {
srcDir 'src/main/java'
}
resources {
srcDir 'src/../lib'
}
output {
classesDir 'build/classes'
resourcesDir 'build/javaResources'
}
}
}
And the jar
task to the following:
task jar(type: Jar) {
from android.sourceSets.main.output
}
Gradle is now giving me this output:
Could not find method output() for arguments [build_25r1m0a3etn5cudtt5odlegprd$_run_closure2_closure9_closure10_closure13@138532dc] on source set main.
android - Gradle version 2.2 is required.
Gradle is one type of build tool that builds the source code of the program. So it's an important part of Android Studio, and needs to be installed before starting developing your application. We do not have to install it separately, because the Android Studio does it for us, when we make our first project.
Note: The answer has been edited. Please see the 07/28/2014 update below.
Here is a solution I ended up coming up with. There may be a better way available, but I have not found it yet.
android {
compileSdkVersion 18
buildToolsVersion "18.0.1"
defaultConfig {
minSdkVersion 10
targetSdkVersion 18
}
sourceSets {
main {
java {
srcDir 'src/main/java'
}
resources {
srcDir 'src/../lib'
}
}
}
}
task clearJar(type: Delete) {
delete 'build/libs/ProjectName.jar'
}
task makeJar(type: Copy) {
from('build/bundles/release/')
into('build/libs/')
include('classes.jar')
rename ('classes.jar', 'ProjectName.jar')
}
makeJar.dependsOn(clearJar, build)
Running gradlew makeJar
creates a ProjectName.jar
in the build/libs
directory. The structure of this jar is as follows:
ProjectName.jar
\- lib
| \- armeabi
| \- libNativeFirst.so
| \- libNativeSecond.so
\- com
\- package
\- sdk
\- PackageSDK.class
This is the exact result I needed. I am now able to use ProjectName.jar
successfully in other projects.
EDIT: While I am able to use the resulting jar in projects within Android Studio, I cannot do so in projects created in ADT due to a warning about native code being present inside a jar file. Supposedly there is a flag to turn off this check in settings, but it does not function correctly. Thus, if you want to create a library that uses native code, those using ADT will have to manually copy the armeabi directory into libs/.
As of Android Studio 0.8.0, Gradle output directories have been changed and the configuration outlined above will not work. I have changed my configuration to the following:
task clearJar(type: Delete) {
delete 'build/outputs/ProjectName.jar'
}
task makeJar(type: Copy) {
from('build/intermediates/bundles/release/')
into('build/outputs/')
include('classes.jar')
rename ('classes.jar', 'ProjectName.jar')
}
IMPORTANT: Please note that ProjectName.jar
will now be placed into build/outputs/
and NOT into build/libs/
.
Just to add a slight alternative to @BVB's answer (although heavily based on it) here's what I had to do to output a jar myapp-api.jar
which was for a Java only project that dealt with rest API interaction. It's dependant on Android.jar hence the need to use apply plugin: 'com.android.application'
rather than just apply plugin: 'java'
Calling ./gradlew build jar
from the myJavaAPIProject to build and generate the .jar to myJavaAPIProject/build/libs/myapp-api.jar
build.gradle
//Even though this is a Java project, we need to apply the android plugin otherwise it cannot find the SDK/android.jar and so cannot compile
apply plugin: 'com.android.application'
dependencies {
//this ensures we have gson.jar and anything else in the /lib folder
compile fileTree(dir: 'lib', include: '*.jar')
}
repositories {
mavenCentral()
}
android{
compileSdkVersion 21
buildToolsVersion "21.0.1"
defaultConfig {
minSdkVersion 10
targetSdkVersion 21
}
sourceSets {
main {
java {
//points to an empty manifest, needed just to get the build to work
manifest.srcFile 'AndroidManifest.xml'
//defined our src dir as it's not the default dir gradle looks for
java.srcDirs = ['src']
}
}
}
//enforce java 7
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_7
targetCompatibility JavaVersion.VERSION_1_7
}
}
//Actually created the .jar file
task jar(type: Jar) {
//from android.sourceSets.main.java
from 'build/intermediates/classes/release/'
archiveName 'myapp-api.jar'
}
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<!-- this is a dummy file needed to ensure gradle validates and builds ok -->
<manifest
package="com.myapp.android"
/>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With