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.
In my application I have 3 public classes (with a lot of external dependencies)
that I want to convert to a Java library ( Jar ).
Problem is when I try to construct the Jar using the standard system they ask me for a main class, which my source does not have.
Am I doing something wrong here?
Can someone please guide me on how to build a library using IntelliJ IDEA without a main class and with external dependencies
I use maven in IntelliJ, but you could use ant or gradle. In all these cases, it is the default behaviour to not include a main.
BTW, having a main for a library is not a bad thing, you can use it to print out information about the library such as when it was built or where the developer using the library can get more information.
I've been researching for many hours about a possible solution to this but whatever I try it just fails. Here's the explained situation:
I have this library project on Android Studio which generates the app-debug.aar file.
Then I add this new module in the implementing project, following the wizard to import .JAR/.AARs I pick the .aar and update the dependency for :app in the Project Structure.
Once the project is cleaned (even using ./gradlew clean--Mac OS X) I can make references of this class and its methods in any of the activities.
Now at runtime, once built and installed on the real devices the app will crash throwing the aforementioned Runtime Exception.
Note: I'm importing the .aar because I would need to protect the code and it has resources so a .jar is out of the question. And if I import the library module (with source and all instead of an.aar) then the app has no issues at runtime.
I've tried everything and if anyone can throw some light on what this could be, it'll be highly appreciated.
The class extends ViewGroup and is instantiated at runtime in case that implies anything. The code was given to me so major changes might not be possible unless it's absolutely necessary.
Thanks beforehand to all!
Armando
For those, who are still looking for the solution, following two options worked for me to solve the exact same problem as OP has mentioned.
Include the (problematic) library dependency in the target module as well, i-e the in my case i was including the protobuf-lite as a dependency to my library module but getting noclassdefFound error when lib imported as .aar in app module. As a workaround, i added the protobuf-lite dependency to my app module too and it worked like charm.
Second option that worked for me that instead of adding the gradle dependency `compile 'com.google.protobuf:protobuf-lite:3.0.1', i downloaded the protobuf-jar from maven and added manually to the libs of my library module, and the problem got solved.
Don't know what's wrong with the gradle plugin, but hope it helps someone else looking for the same problem.
The NoClassDefFound error has actually happening to a backward-compatibility library being used by this class I mentioned on the question ("Class A"). No details were given other than Class A couldn't be found and later on found out that another class had a similar issue BUT was pointing at that compat lib with the same exception and I noticed that Class A was also calling its methods and implementing its callbacks. By bumping up the min version (to use the native API) I could overcome that issue. It was indeed a problem of including that backward-comp library in the .aar or so it seems. Should I understand this issue a lot better I'll update this "answer."
I am developing a library for Android applications which does not use native code (JNI). I have tried suppling the library as an external jar in my Android projects but this method does not include the library contents in the apk and thus throws class not found errors when run in the emulator or device. I have also tried creating the library as an Android project in itself and this does work, but only for public static properties (not methods). With the library and application both being in separate apk's I can see that the VM notices references to the library and can read some properties, but when an attempt to instantiate a class in the library is executed I get class not found even though I can read the public static properties from it (very frustrating!!).
I realize that Davlik byte code is not the same as Java byte code but I am having trouble even finding good information about how to solve what would seem to be a very simple issue in Android. I am looking into the old PlatformLibrary stuff right now but I am not convinced this will work either since the sample has been removed from the Android site :(
So help me out if you can, if I find the answer before this happens I will share it.
viva la Android!
I have tried suppling the library as
an external jar in my Android projects
but this method does not include the
library contents in the apk and thus
throws class not found errors when run
in the emulator or device.
Put the JAR in your libs/ directory, and it will automatically be included in the APK.
This sample project from one of my books shows using the BeanShell JAR this way. Also, all of the GitHub repos starting with "cwac-" on my GitHub page are projects designed to build JARs to be included in Android projects via the libs/ directory.
My project layout is
/ServerModule
/commonClasses
/AndroidClient
/needsToIncludeSomeCommonClasses
but as soon as i want to compile and build my AndroidClient IntelliJ adds the server libs to the compile classpath of my android project and I get a UNEXPECTED TOP-LEVEL EXCEPTION because of multiple classes that are present in android and normal java.
My question is how can i set up my project without duplicating the server code?
It seems to be a problem with the android-plugin.
It includes all the serverside libs in the build.
I found a solution.
I need to make a new module with common classes only and link this with the other two modules. Not very pretty but it works
I would ask IntelliJ support, http://www.jetbrains.com/support/idea/index.html they are usually very responsive or ask their Community Support Forum. http://www.jetbrains.com/devnet/