I have a Project structure of the following form:
Root Project
+------ Module A
+------ Module B
Now Module B is a huge project, but I use an API to access it, so I would like to load the classes of Module B at runtime. As such I would like to compile it but in a separate DEX file. I am able to compile a separate DEX file by the following gist:
https://gist.github.com/nickcaballero/7045993
In the debug compile mode this work fine since one can change the libraries being DEXed via the buildscript in this form
def libraryFiles = new ArrayList<?>()
variant.dex.libraries.each {
File file ->
// Exclude Module B from Dex library list
if (!file.absolutePath.contains("ModuleB/unspecified/classes.jar")) {
libraryFiles.add(file);
}
}
variant.dex.libraries = libraryFiles
Now this works well since when not doing proguard, the AndroidBuilder simply uses variant.dex.libraries to create the DEX file and excluding it is easy. The pain comes when one needs to do proguard of the intermediate class. Since ModuleB is a compile time dependency (for the purpose of resource integration/layouts etc.) therefore its classes, get compiled into the build directory.
However when it is getting proguarded, the default proguard task defined in the Android Builder throws in the classes.jar file as libraryJars.
At the end of it, the task creates classes-proguard which contains all the classes from the above library Jars. This then gets DEXed, and the classes which were to be loaded via Runtime are present in it. Is there any way to exclude certain jars to not be fed into the default proguard task?
Related
I've written a utility library for a project I am working on in Kotlin. The project has a number of dependencies (such as AWS libraries). I want to package the library as a 'fat' .jar so that I can use the library in other projects without issue.
Currently, I am using the gradle shadow plugin. I am able to successfully use the .jar classes in Java code/projects without issue. However, when using the .jar classes in Kotlin projects/code (or attempting to) I am facing visibility issues (code does not compile b/c of unresolved references). I have no idea what I am doing wrong and am not sure if this is a common issue.
I've already tried:
Gradle Shadow plugin here
Modifying the gradle jar task to include all dependencies myself
The fat jar is successfully created in both cases, and usable in Java code, but Kotlin is not able to resolve the references. However, when I create a non fat jar, the classes are visible, but obviously broken (bc of missing dependencies). So, essentially, only when I create a fat .jar, only my Kotlin code cannot use the library.
Does anyone have any insight?
Most likely, your re-packaged JAR is missing the META-INF/*.kotlin_module files from the original JARs. These are the Kotlin package metadata files which the Kotlin compiler needs to be able to read top-level declarations from the classes.
If these files are lost, you will face visibility issues with top-level declarations and extensions.
You need to configure your fat JAR tools to also copy these files into the resulting JAR.
You would also need to add both the compile time and run time dependencies when you compile your library jar file.
One way to add them would be for example:
tasks {
jar{
from({
configurations.runtimeClasspath.get().filter { it.name.endsWith("jar") }.map { zipTree(it) }
configurations.compileClasspath.get().filter { it.name.endsWith("jar") }.map { zipTree(it) }
})
exclude ("META-INF/*.RSA", "META-INF/*.SF", "META-INF/*.DSA")
}
}
In my projects, I need to import third party jar file and Facebook SDK.
compile files('libs/SkinSDK.jar')
compile 'com.facebook.android:facebook-android-sdk:4.14.0'
Both include same BundleJSONConverter class. So, I cannot do generate signed APK. It always shows duplicate entry com/facebook/internal/BundleJSONConverter.
So, I want to exclude in Facebook or SkinSDK.jar. I tried like
compile ('com.facebook.android:facebook-android-sdk:4.14.0') {
exclude group: 'com.facebook.internal', module: 'BundleJSONConverter'
}
It's not working and showing same error.
The exclude method of the configuration closure for a dependency excludes transitive dependencies. So, if your module dependency depends on other modules, you can exclude them from your build. You can check out the transitive dependencies of the 'com.facebook.android:facebook-android-sdk:4.14.0' module on its Maven repository info page.
If the BundleJSONConverter class exists in a transitive dependency, you can exclude the specific module in the same way you are trying now. Just specify the group, the module and the version, like you do for dependencies.
If you just want to exclude one class for a dependency jar, take a look at the jar jar links tool and its Gradle plugin. It allows you to alter included jars, e.g. to change packages or remove classes.
The following (shortened) example shows the usage of the plugin and some methods to alter the dependency jar:
compile jarjar.repackage {
from 'org.apache.hive:hive-exec:0.13.0.2.1.5.0-695'
archiveBypass "commons*.jar"
archiveExclude "slf4j*.jar"
classDelete "org.apache.thrift.**"
classRename 'org.json.**', 'org.anarres.hive.json.#1'
}
Bumped into similar situation. This is what I did, not elegant as I hoped, but it works:
Rename the jar file (SkinSDK.jar in your case): .zip instead of .jar
Go "inside" the zip file (I'm using DoubleCommander, there are many other utilities for that), or extract it to a temporary folder.
Delete the duplicate class that causes the problem. Go "outside" the zip file.
Rename (or re-pack) the file from .zip to .jar . Compile.
Hope it works...
I had a similar problem with duplicated classes after importing a jar. In my case, the conflict was between a class in that jar and a class in my own project.
Below I share the solution you can use to discard classes that you have available in your own source tree, assuming the one in the jar is the right one to use:
android {
sourceSets {
main {
java {
filter.excludes = [
"com/package/Duplicated.java",
]
}
}
}
}
I am trying to use Sigar in a Gradle project. Sigar distribution is by default provided with 2 types of files:
a JAR that contains classes
some native files (.so, dylib, .dll)
My purpose is to repackage these files so that I can use them as dependencies deployed and downloaded on-demand from a personal Maven repository.
My first try was to define dependencies as files in order to check that my application is working as expected before to repackage. Below is the Gradle code I used for my first test that works:
dependencies {
compile files("${rootDir}/lib/sigar/sigar.jar")
runtime fileTree(dir: "${rootDir}/lib/sigar/", exclude: "*.jar")
}
Then, I have repackaged Sigar native files into a JAR and renamed the other one to match rules for maven artifacts since I want to deploy them in a Maven repository. Below is what I get:
sigar-1.6.4.jar (contains .class files)
sigar-1.6.4-native.jar (contains .dylib, .so, and .dll files at the root)
The next step was to deploy these files in my custom repository. Then, I have updated my build.gradle as follows:
dependencies {
compile 'sigar:sigar:1.6.4'
runtime 'sigar:sigar:1.6.4:native'
}
Unfortunately, when I do a gradle clean build, new dependencies are fetched but native libraries can no longer be found at runtime since now I get the following exception:
Error thrown in postRegister method: rethrowing <java.lang.UnsatisfiedLinkError: org.hyperic.sigar.Sigar.getCpuInfoList()[Lorg/hyperic/sigar/CpuInfo;>
Consequently, I am looking for a solution to fetch and to link native files to my Java app like for other dependencies. Any advice, comment, suggestion, help, solution, etc. are welcome ;)
A solution is to define a new gradle configuration that unzips JAR files at the desired location:
project.ext.set('nativeLibsDir', "$buildDir/libs/natives")
configurations {
nativeBundle
}
dependencies {
nativeBundle 'sigar:sigar:1.6.4:native'
}
task extractNativeBundle(type: Sync) {
from {
configurations.nativeBundle.collect { zipTree(it) }
}
into file(project.nativeLibsDir)
}
dist.dependsOn extractNativeBundle
Then, this location must be put in java.library.path for tasks that depend on native libraries:
systemProperty "java.library.path", project.nativeLibsDir
I am building an apk using gradle which includes multiple jars. Some of these jars have same classes, which is causing the conflict during build and giving error: duplicate entry of class.
So, how do i exclude *.class from library in this construction?
dependencies {
provided files('libs/myLibrary.jar')
}
For example, I want to exclude several classes from myLibrary.jar. I do not want to convert some *.class to dex format. How to prevent it?
I have two pure java projects (:java:libs:proj1, :java:libs:proj2) that produce two classes.jars when they are built. The two jars "combined" include the exact classes that I would like to convert into dex jar i.e. a JAR file with classes.dex in it.
Can someone help me with converting the two pure java projects into a single JAR with classes.dex in it?
Here is what I tried doing.
1) Create a separate Android Library project (apply plugin: 'android-library') and include the two java projects as dependencies.
apply plugin: 'android-library'
dependencies {
compile project(':java:libs:proj1')
compile project(':java:libs:proj2')
}
However, with this approach, it doesn't generate a dex file. Instead, it produces an ".aar" file which contains only the .class files of the two projects. If I can convert this .aar file to its dex, then this would be perfect but apparently the "android-library" plugin does not have a "dex" task.
2) Create an Android project (apply plugin: 'android') and include the two projects as depenendencies. (Similar to above but using 'android' instead of 'android-library').
apply plugin: 'android'
dependencies {
compile project(':java:libs:proj1')
compile project(':java:libs:proj2')
}
This approach does create the dex files that I need, however it also includes ALL the dependencies for my two pure java projects. So for example, my java projects depend on JUnit, BouncyCastle and some other external JAva projects. Inside of the classes.dex, I see that it has included everything. Is there a way to tell the "dex" task to not include dependencies "transitively"?
I only want the classes directly associated with my two java projects into dex. I wish there was an easy way :(
Thanks,
J
will modify compile in dependencies to provided help? please also check this
25.4.7. Excluding transitive dependencies
You can exclude a transitive dependency either by configuration or by dependency:
Example 25.14. Excluding transitive dependencies