I have 3 projects that are used as libraries within a 4th (main project).
The 3 projects are complied within each other as follows (build.gradle):
Library Project:
Project A
compile project(":projectA")
compile project(":projectB")
Project B
compile project(':projectC')
Main Project:
compile(name: 'projectA', ext: 'aar')
compile(name: 'projectB', ext: 'aar')
compile(name: 'projectC', ext: 'aar')
I would like to do something to the "Library Project", so that from within the Main Project, if I click on any class from within the Library project, I should either not be able to see the code, or it should be encrypted.
So for example if there is InterfaceA in ProjectA, and the main activity of the Main Project implements that interface, if I "Ctrl-Click" into the interface, the result should be similar to what I specified above.
I understand Proguard does something similar, but that is only if you are building a release .apk, I need the same result for compiled libraries.
Many projects use ProGuard to achieve this protection.
You can use Gradle to build library components for Android
Libraries, just like apps, can be build in development or release build types
Proguard can be configured to run on a component (app or library), but only in the release build type. See here: https://sites.google.com/a/android.com/tools/tech-docs/new-build-system/user-guide#TOC-Running-ProGuard
If the component is minified (highly advised), then you need to tell Progaurd what the "root" classes are, otherwise it will minify the library to literally nothing. This can be achieved by adding a rule to the configuration file:
-keep class your.package.name {public *;}
A more extensive example is here: http://proguard.sourceforge.net/manual/examples.html#library
However there are some limitations:
ProGuard's main use is is removing as much debug information, line numbers and names as possible from the bytecode without changing what the bytecode actually does. It replaces the names of members and arguments, non-public classes with meaningless ones, for example vehicleLicensePlate might become _a. As any code maintainer will relate, bad member and variable names make maintenance really hard.
ProGuard can (slightly) modify bytecode by optimising as much as possible (computing constants defined as expressions, playing around with inlining, etc. The optimisations are listed here: http://proguard.sourceforge.net/FAQ.html#optimization)
ProGuard does not encrypt the bytecode - the JVM needs to see the actual bytecode otherwise it could not run the program.
So, obfuscation only makes it harder to reverse-engineer and understand a library, it cannot make this task impossible.
One last pointer: ProGuard dumps a file containing a list of what it has changed, in particular the line numbers. When you get stack traces back from your customers (or through online tools like Crashlytics) you can revert the obfuscation so you can debug. In any release-build process, you need to find a way to save this file.
This file is also needed when you make incremental releases of your library so the obfuscation is consistent to the previously released version. If you don't, the customer cannot drop-in replace your library and will have to do a complete rebuild (and link) of their app.
While ProGuard is a free-n-easy option which just works, there are other free and paid-for obfuscators. Some offer a few more features, but they are fundamentally the same, and the compatibility of ProGuard with IDEs, tools and services is excellent.
You could set all the methods you don't want to be public to default, so they can't be used outside of the original project. And also, you should separate the libraries from the app project, compile them, and use them as external dependencies. If you don't want the source code of the library published, just don't add it to the compilation options. If somebody else than you needs to use your library, publish it using bintray, or just add the compiled aar/jar files to the app project.
Here's a guide for the whole process: https://inthecheesefactory.com/blog/how-to-upload-library-to-jcenter-maven-central-as-dependency/en
Alternatively, you can build library projects using maven (I find it a lot easier than using gradle), take a look here for an example: https://github.com/simpligility/android-maven-plugin/tree/master/src/test/projects/libraryprojects
and a concrete project:
https://github.com/fcopardo/BaseViews-Android
2 steps:
add your libraries to local maven repo
use maven dependences instead of project dependences.
You cannot do that. A compiled library has .class files (bytecode), which can be de-compiled and viewed using various de-compilers like JD-GUI etc. Android Studio has a built-in de-compiler which makes it more easy for someone to just ctrl-click and view the .class file. The best option you have is to obfuscate your code. Here are some obfuscators you can use. But always keep in mind that it's never impossible to reverse-engineer something. Everything is hackable.
Related
So I took a Coursera course that had me work with external libraries. Two .jar files which most of the weekly projects depended upon.
I'm not entirely sure how eclipse compiles and runs the files, and how it links to these external libraries -- what is the proper way of organizing this? Do I put a copy of each .jar file in each project directory?
Is there another, cleaner way that I should be organizing this?
Thanks --
As a beginner programmer it is OK to put it in each project. But consider that this is ongoing work and at some time in future you want to upgrade to a new version of these external libraries. Then you would have to copy it everywhere.
Instead another option is to store them in one place and add it in classpath in each project. Now you have only one copy of it, which is always better.
Now, if and when you do get a new version then the file names might change, so you will still have to change the classpath of each project.
But I advise you to worry about these and other such problems later. For now, focus on programming related problems rather than configuration.
If you want to maintain your libraries professionally in a formal manor then you're better of using a build tool like Gradle of Maven.
I'd suggest you to use Gradle to maintain the project since it has a whole lot of useful build tools available to you to use. Eclipse has a Gradle plugin available which allows you to use Gradle projects with it. See link below.
To give you a idea of how Gradle is used professionally. Android uses it by default to maintain their projects now. So Android java projects uses the Gradle build tool to maintain its library sources, compilation processes and such.
The difference between a Gradle project and a normal java project is that a Gradle project has a list of pre-defined scripts available to you which fetches the libraries, compiles them and prepares them before exporting the final bundle (jar). So really all Gradle does in before hand is fetch the libraries and prepares the specified tools before compilation so you won't need to mess with them your self. It prepares your project directory and remotely maintains your libraries so if they're available from a repository then it'll make sure to prepare them appropriately in before hand and setup your projects directories.
So really the difference you'd physically notice is that instead of using the default Eclipse export button to create your bundle (jar) you'd instead use a button from the side menu which the Gradle plugin adds and also you'd cleanly list the libraries in a structured order in a file that gets added to your project root.
If you want to get a basic understanding of how it works and really want to start to proffesionally or formally structure your project then try to create a very basic android app in Android Studio. see link below
If this isn't what you want at all and don't want to take it to this advanced level yet then adding the library bundles into some kind of lib folder that's located in your project root is properly best practice.
If you wonder why? Well basically different projects might use different versions of the library which may add or remove support to them. So to keep the versions consistent and make sure to have the right version available to you, you have the direct source near the project it self.
Here's some useful link:
http://www.vogella.com/tutorials/EclipseGradle/article.html
http://developer.android.com/sdk/index.html
I'm with Jetbrains IntelliJ (or Android Studio if you prefer), and my project is built with gradle and some external java libraries from my company namespace. Thing is that is difficult to navigate trough classes as i cannot search text into the .jar files or resolve usages.
Do you have any idea of how to do this?, is there a plugin or something? a trick maybe?
Many thanks.
IntelliJ IDEA (as of 2017.2 or newer) knows how to decompile JAR files with no source attached, that is when you are in debug mode and you jump into the implementation. However this will not allow you full text search (such as looking for usages).
If it's just 1-2 JARs that you care for browsing, you may manually edit your Module properties in IntelliJ and add the source JAR files (that you need to download from your Library's website along with the binary JARs).
Another option is to use Maven, and have it download the source alongside with the binaries from the public Maven repository (if we're talking about open source libraries).
Yet another option, in an enterprise setting someone typically sets up an Artifactory (for instance https://www.jfrog.com/artifactory/ ), which is source for all the libraries and their source code.
If you use some up-to-date build script (for example Gradle), you can build an IntelliJ project with all the sources already linked in.
Hope this helps!
There is no easy way to do it. The only way to search for anything in library code is to attach source. The attached source can be code that you decompiled yourself, but IDE won't do it for you (but I think someone can write plugin that decompiles the whole library and attaches the decompiled source). So I guess that could be the "trick" you need to do.
Why is it impossible? I didn't write the IDE so I can't be sure why. But most likely the problem with finding text in jar files with no source attached, is that the text representation depends on the decompiler. There is no "best" way to decompile given class. Sometimes the decompilation may be even impossible (for example bytecode with a lot of goto/conditional jump instructions that don't nicely translate into loop/conditional constructs). In such cases decompilers can do anything from throwing an exception, putting raw bytecode, to just putting goto statements in the java code to at least show what the code is doing.
The only way that would allow to search in decompiled code (assuming you can't just download the code somewhere), would be to decompile it yourself (for example using the fernflower decompile, which is also used by intellij idea) and attach the decompiled source code.
While the above argument doesn't apply when finding usages of methods/fields, it's still not allowed, most likely because the IDE analyzes the source code to find usages, instead of analyzing the bytecode (compiled code).
I recently asked a very similar question, but was unsure how to phrase it. Having received some feedback and researched some of the potential solutions, I'm now asking again with what I believe to be a better explanation of the issue.
My Android App uses my Library (parentLib), this library is built referencing methods from another library (childLib). Therefore, the App itself uses parentLib (A .jar library), which in turn uses childLib (Another .jar library).
The problem here is that when the app attempts to use anything that involves the nested library (childLib), it receives a NoClassDefFoundError, which crashes the App. I believe that this issue is due to the App being unable to resolve the nested dependency.
I can't really use Android library projects, as I need the source code to be as obfuscated and difficult to understand as possible. I have also tried creating these libraries using Android Studio, only to sadly receive no better outcome.
My options (I think) are:
Combine the Libraries
I could potentially combine childLib and parentLib into a single .jar library, seperating them out into different packages. This would be difficult though, as in practise there are around 6 nested libraries for my intended App.
Insist the Client use multiple libraries
Instead of saying to the client, "Here's one simple library (parentLib) for you to use", I could instead say, "Here's 7 different libraries for you to import (parentLib, childLib, etc.), otherwise nothing will work". Not exactly professional!
Other Options
I would welcome any other suggestions anybody has!
Thanks in advance.
The NoClassDefFoundError means that the the class was present during compilation, but not available in the classpath when trying to execute it.
So, you need to tell gradle to compile those libraries and package them inside the apk.
Copy all the library jars you need to the libs folder in the root of you project. Then, edit the gradle.build file and add the following:
dependencies {
compile fileTree(dir: 'libs', include: '*.jar')
}
This will cause all the required libraries to be added to your apk. This way, the classes you need will be present in the classpath when you execute the code that needs them.
Resolved by moving to Android Studio (where such issues are not present).
Is there any posibility to cache java compilation like ccache does for C or C++ compilation?
I have a lot code to compile, and I compile the same code many times, so it took a lot of time. So I thought to cached it to speed up.
But the main problem is that, the whole source code has many files in many directories, and there are so many java files. Compilation is done by the ant scripts which are invoked by the make script. It has to be compiled by the Sun's JDK. And what is more... between compilations I have to clean all created *class files.
So I cannot use any of IDE's features.
Eclipse does incremental compile of classes (I guess others do this as well). Only the portion of your class that changes will be compiled. Everything else will not be changed. It works reasonably well in real world projects.
Build tools like Maven and Ant can be configured to compile only changed java files. These do not track dependencies in some scenarios they miss needed compiles. (For example change the signature in a super class.)
The best way would be to factor the shared classes into utility jars that you would simply include in your compile classpath, unless there is really a specific (and good) reason that prevents you from doing so (code duplication is evil and will lead you to doom :)).
There's no caching functionality in Sun's JDK itself, as far as I am aware.
Most Java IDEs however will cache compilation, so if you need "compilation on demand", that should do.
Eclipse and Netbeans definitely have this. They will only recompile changed classes (and their dependencies, which they figure out automatically). This is fairly fast for most changes.
I'm currently passing a very large classpath to javac to compile a java project.
I know that a number of those jar files aren't needed.
Is there a simple way of finding out which files aren't needed?
You need the Class Dependency Analyzer tool. To quote the introduction:
The purpose of this tool is to analyze Java™ class files in order to learn more about the dependencies between those classes.
True, it won't catch runtime dependencies - but short of running an exhaustive 100% coverage test suite you can never be sure you've caught all runtime dependencies.
If you expect runtime dependencies you should use the CDA as a first-pass, then do exhaustive testing of the resultant app to ensure that there are no jar files which were only referenced through runtime dependencies.
I guess that "remove them one by one and check if the application still compiles and works" is not the expected answer :)
(EDIT: While the approach suggested above can be a bit automated, it remains somehow painfull and there must be an alternative, at least for compile-time dependencies. After some googling, I found Jar Analyzer which seems to be a nice tool for this work as explained in this blog post:
Jar Analyzer scans for compile dependencies, meaning that it can create a tree of which JAR-files are needed to compile which JAR-files that are needed to compile these JAR-files, and so on. You get a very nice report/graph which shows you all the JAR-files and why they are in there.
You can also see the JAR-files that don't have any connection to your code, remove them and their children. What I found in our libs folder was that about 20% of the 150 JAR files in our libs folder were unused at compile time, and these were potential JARs to be removed.
The big aber is that you don't get any hint on which JAR-files are used only at runtime by means of discovery and reflection. And this is where the real work begins.
The only way to find out whether a JAR file is used at runtime is basically to take it out, start up your application and test every functionality. If you have an application of moderate size, performing a 100% regression test takes many hours. So in practice, I ended up doing alot of guessing, quick and dirty testing, and asking around to find out which of the runtime dependencies were actually in use.
It seems pretty easy to use: download, unzip and run the tool on a directory containing all jars. Or use the provided Ant task.)
You also have loosejar.jar which enables you to find the real jar dependencies of your project at runtime !
The compiler has a -verbose option, and it is quite verbose. It informs of each class that gets loaded and where it is loaded from!
While it's not quite user-friendly and it doesn't provide high-level analysis, I found it very useful for debugging classpath conflicts. This tells you the jars that get used (with help of grep), not the ones that don't get used.
The latest build of eclipse will warn you about unused imports in your source code
Check Classpath Helper