3

I want to build android library so that all its classes except of one will be not accessible for an application that will use this library. How I can do it?

Arina
  • 49
  • 4
  • Why would you want to do that? – Sufian Jan 21 '15 at 13:27
  • 1
    I want to separate internal APIs and public APIs. Like in android.jar there is an internal not accessible package. – Arina Jan 21 '15 at 13:31
  • Related - [Hiding classes in a jar file](http://stackoverflow.com/q/4759692/1276636) – Sufian Jan 22 '15 at 11:12
  • Also check the linked answer [How do I build the Android SDK with hidden and internal APIs available?](http://stackoverflow.com/a/9565020/1276636) – Sufian Jan 22 '15 at 11:15
  • Thank you. That clarifies the picture. So there is no ready java/android mechanism for internalizing of implementation, but I can either split a library to public jar and internal jar, or use some additional mechanism like OSGI to do it. – Arina Jan 23 '15 at 12:28

2 Answers2

1

If your SDK is bundled as JAR file (instead of AAR), you can mimic internal APIs hiding in the same way as it is done in Android SDK by creating two JAR files (one will be regular library, and second stripped - which will represent the API). Let's see an example.

Full library (I'll call it sdk-runtime.jar) will consist of a single class: Api.java:

package info.osom.sdk;

public class Api {
    public static void init() {
        System.out.println("Api.init()");
        anotherPublicMethod();
    }

    public static void anotherPublicMethod() {
        System.out.println("Api.anotherPublicMethod()");
    }
}

Stripped library (I'll call it sdk-api.jar) will hide the anotherPublicMethod(), and expose only the init() method:

package info.osom.sdk;

public class Api {
    public static void init() {
        throw new RuntimeException("stub!");
    }
}

Instruct your SDK consumers to configure their application dependencies as following:

dependencies {
    provided files('libs/sdk-api.jar')
    apk files('libs/sdk-runtime.jar')
}

According to documentation:

provided configuration adds the dependency to the compilation classpath only (it is not added to the APK).
Note: If you're creating an Android app module, you cannot use provided for AAR dependencies, only for JARs. In an Android library module, you can use it for both JARs and AARs.

apk configuration adds the dependency to the APK only (it is not added to the compilation classpath).
Note: You can use apk only for JAR binary dependencies. It does not support library modules or AAR binary dependencies.

Since I've stripped the anotherPublicMethod() from sdk-api.jar, it won't be available for SDK consumer:

enter image description here

I've created a simple application project that consumes the above SDK.

Alex Lipov
  • 13,503
  • 5
  • 64
  • 87
0

Mark them as private, the same as you would in a traditional Java JAR.

CommonsWare
  • 986,068
  • 189
  • 2,389
  • 2,491
  • They should be visible inside of library for all other classes and packages but not visible out of library. Like internal in .NET for example. – Arina Jan 21 '15 at 13:26
  • @Arina: You are welcome to stick with package-private scoping (i.e., the default for anything not labeled `public`, `protected`, or `private`) for the internal stuff. However, nothing is stopping a developer from writing their own classes in the packages you use and therefore accessing those APIs. Conventional app code, residing in its own package, would only be able to access the `public` (and, if subclassing, `protected`) stuff. – CommonsWare Jan 21 '15 at 13:35
  • A package-private scoping does not match, because my library includes many packages. I look for somethig similar to possibility do not export some packages or forbid access to them. – Arina Jan 21 '15 at 13:49
  • @Arina: Sorry, but I do not know of any way to accomplish that in Java. In Java, there is no concept of a JAR "exporting" things. Your code, the app's code, and the code from other libraries are all peers, subject to Java `private`, etc. scoping rules. You can try to use ProGuard on your library, to obfuscate the stuff that you do not consider to be your public API. That will not *prevent* developers from calling your internal implementation, but it will make it challenging enough that they will not do so accidentally. – CommonsWare Jan 21 '15 at 13:53
  • My purpose is not preventing from hacking or discovering of my code, but do it convenient for customers. The library has a little number of public APIs and very wide functionality. I would like that public interfaces were explicitely separated from internal implementation. – Arina Jan 21 '15 at 14:01
  • @Arina: Sorry, but there really isn't anything in Java that meets your needs. You are welcome to do anything that I suggested, or limit your documentation to whatever your public API is and leave the actual code alone. – CommonsWare Jan 21 '15 at 14:08
  • If you'll see in Java Build Path on android.jar, it has access rule that forbids an access to packages android.internal.*. How technically I can do it while packaging my library? – Arina Jan 21 '15 at 15:09
  • @Arina: I am not aware that there are any `android.internal` classes, and I certainly cannot find any in an `android.jar`. There are some `com.android.internal` classes in the source code, only one of which (an interface named `com.android.internal.util.Predicate`) appears in `android.jar`. You can certainly use `Predicate` in your code, though doing so would not be wise. – CommonsWare Jan 21 '15 at 15:49