21

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.

TejjD
  • 2,571
  • 1
  • 17
  • 37
  • I think you are asking about how to control/configure your IDE, not solve a programming problem. Just another pointer: Proguard *obfuscates*, not encrypts, and it does this on the bytecode. If you have your source files open in the IDE (or in a development AAR), then of course the IDE will help you by clicking through to the source.... – Andrew Alcock Aug 31 '16 at 11:56
  • You're clearly not understanding the question then. How my IDE is configured doesn't help the fact that if I distribute the library to an external entity,they will still be able to view the libraries code. You expect me to go configure their IDE's as well then? – TejjD Aug 31 '16 at 12:05
  • I see. Then you have to obfuscate your code using Proguard or similar tools. But that is only a partial solution - bytecode can be decompiled relatively easily into Java, and Proguard can only replace the *names* of things (variables, private members and methods, etc), not their implementation. – Andrew Alcock Aug 31 '16 at 12:09
  • Yeah, that is the issue. How do paid libraries do it? I would like to distribute the libraries for use, but do not want any implementation to be shown. It is not open source code. – TejjD Aug 31 '16 at 12:15
  • Possible duplicate - http://stackoverflow.com/questions/35360938/how-to-distribute-a-sdk-as-aar-file-without-exposing-the-source-code – F43nd1r Aug 31 '16 at 17:16
  • Check this answer. http://stackoverflow.com/questions/16437697/best-practice-to-hide-a-service-implementation – Pravin Divraniya Sep 06 '16 at 10:42

4 Answers4

10

Many projects use ProGuard to achieve this protection.

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.

Andrew Alcock
  • 19,401
  • 4
  • 42
  • 60
  • This still does not answer my question. If I am selling a library, that can be used in conjunction with your existing project, I want to completely restrict you from viewing ANY implementation at all. Only allow you to make use of the functionality. – TejjD Sep 06 '16 at 05:32
  • 2
    You simply cannot do that. The bytecode is machine-readable, otherwise you wouldn't be able to use the lib, and if it's readable, a proper decompiler can restore the implementation details. Even if there would be no decompiler, the JVM instructions would be visible to anyone. TL;DR: **there's no way to protect your implementation** other than obfuscating the code making it take too much time to get through it, so people give up. – Gergely Kőrössy Sep 06 '16 at 16:06
  • 1
    @tejjD Gergely (and the others below) are correct. At the end of the day, if the JVM has to be able to read the byte code in order to execute it. If the JVM can read it, so can the IDE and decompiler (which are using the JVM to read and execute the library). If the code can be read, it can be decompiled. Obfuscation makes it much harder for the customer to understand the implementation and reverse engineer your thought processes. While Java bytecode is relatively understandable when compared to compiled C++, even compiled obfuscated C++ code is still reverse engineerable. – Andrew Alcock Sep 07 '16 at 07:49
  • Alright thanks a lot. I will reconfigure my proguard, and then go toward uploading and using the lib through a maven url. – TejjD Sep 07 '16 at 07:54
2

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

Fco P.
  • 2,486
  • 17
  • 20
1

2 steps:

  1. add your libraries to local maven repo

  2. use maven dependences instead of project dependences.

Alex Klimashevsky
  • 2,457
  • 3
  • 26
  • 58
1

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.

Bhavit S. Sengar
  • 8,794
  • 6
  • 24
  • 34