android gradle -- compile two pure java projects to dex - java

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

Related

Kotlin Library Exported As Jar Usable In Java Code, But Not In Kotlin Code

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")
}
}

Exclude one class file in gradle Android Studio

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",
]
}
}
}
}

Gradle: multiple JARs without multiple projects

I have a library which is used to build a number of CLI tools using Gradle. Each CLI tool is a separate JAR. At the moment every tool requires a separate Gradle project, with an associated set of directories, like this:
Having all of this structure is resulting in the whole collection of tools becoming very unwieldy and difficult to work with. Is there any way to collect all of the different Mains into a single folder (suitably renamed) and configure Gradle to turn each one into a separate JAR?
FWIW, the JARs are currently created using https://github.com/johnrengelman/shadow . JAR size doesn't matter.
Thanks in advance.
Jars are just zip files with META-INF folder inside. Use Zip tasks to create them and dependsOn to run tasks as part of your build sequence.
I had the code like below for changing jar files:
task changeJar (type: Zip) {
baseName project.name
extension 'jar'
destinationDir new File('build')
entryCompression ZipEntryCompression.STORED
from { zipTree(new File(core.libsDir, core.name + '.jar')) }
from ( <somewhere else> ) {
exclude 'META-INF/'
}
}
I'm not sure if it's a good fit but you might be interested in my gradle-java-flavours plugin.
eg:
apply plugin: 'com.lazan.javaflavours'
javaFlavours {
flavour 'tool1'
flavour 'tool2'
}
dependencies {
compile 'a:a:1.0' // common to all tools
compileTool1 'b:b:2.0' // compile deps for tool1 only
runtimeTool2 'c:c:2.0' // runtime deps for tool2 only
}
Directories
src/main/java, src/test/java, src/main/resources, src/test/resources - common code & tests
src/tool1/java, src/testTool1/java, src/tool1/resources, src/testTool1/resources - tool1 only sources
src/tool2/java, src/testTool2/java, src/tool2/resources, src/testTool2/resources - tool2 only sources
Jars
projectName.jar
projectName-tool1.jar
projectName-tool2.jar

Gradle: What is the difference between classpath and compile dependencies?

When adding dependencies to my project I am never sure what prefix I should give them, e.g. "classpath" or "compile".
For example, should my dependencies below be compile time or classpath?
Also, should this be in my applications build.gradle or in the module specific build.gradle?
Current build.gradle (at application level):
apply plugin: 'java'
repositories {
mavenCentral()
}
dependencies {
compile 'org.hibernate:hibernate-core:5.0.5.Final'
compile 'mysql:mysql-connector-java:5.1.38'
}
If buildscript itself needs something to run, use classpath.
If your project needs something to run, use compile.
The buildscript{} block is for the build.gradle itself.
For multi-project building, the top-level build file is for the root project, the specific build file is for sub-project (module).
Top-level build file where you can add configuration options common to all sub-projects/modules.
Do not place your application dependencies in top-level build file, they belong in the individual module build.gradle files
I'm going to guess that you're referencing compile and classpath within the dependencies {} block. If that is so, those are dependency Configurations.
A configuration is simply a named set of dependencies.
The compile configuration is created by the Java plugin. The classpath configuration is commonly seen in the buildScript {} block where one needs to declare dependencies for the build.gradle, itself (for plugins, perhaps).
If I understand correctly, you're confusing Project.dependencies script block with the Project.buildscript.dependencies script block (just like I did when I reached this question).
I'll try to answer this with what I found.
I think you should be already familiar with the Project.dependencies script block. In this block, we declare dependencies that are required by our source code. There are several ways to declare a dependency that we need for the project. See Gradle Tutorial: Dependency Types. I'll only mention the part that is the most relevant to this problem:
compile 'org.hibernate:hibernate-core:5.0.5.Final' is a module dependency declaration. The compile configuration (which is now deprecated by the implementation configuration.) is merely a keyword for Implementation only dependencies. It is not a keyword describing which type of dependency it is (by type here I'm following the three types defined in the tutorial, i.e. module, file, and project.)
In Gradle Tutorial: Organizing Build Logic it says:
If your build script needs to use external libraries, you can add them
to the script’s classpath in the build script itself. You do this
using the buildscript() method, passing in a closure which declares
the build script classpath.
This is the same way you declare, for example, the Java compilation
classpath. You can use any of the dependency types described in
Dependency Types, except project dependencies.
Having declared the build script classpath, you can use the classes in
your build script as you would any other classes on the classpath.
I hope things are getting clear to you now.
With classpath "com.android.tools.build:gradle:${Versions.android_gradle_plugin}" we're setting classpath method with com.android.tools.build:gradle:${Versions.android_gradle_plugin} which is a module dependency that is used by the build script itself rather than the source in your project.
On the other hand, with compile 'org.hibernate:hibernate-core:5.0.5.Final' we're declaring a module dependency required for your project with the compile configuration.
tl;dr: The classpath, compile, and implementation are all keywords that can be used against dependencies under different circumstances. The former is used when you want to pass in a dependency to the build script, and the latter is one of the configuration you may want to declare.
Android:
classpath in project build.gradle —— the implementation after classpath is only used by gradle it self, used in build script. So if i add the implementation (such as retrofit) in the project build.gradle classpath 'retrofit...', i can't get retrofit in my code!! Because —— my code can't see it, only the buildscript can see it.
implementation in app build.gradle —— add the implementation your code can use!!

Excluding certain modules from proguard Android Gradle Buildscript

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?

Categories

Resources