Search code examples
javajarproguardinner-classes

Cannot access inner interface from a ProGuard-ed JAR


I created a Java class with an inner interface like this:

public class TaskManager {
    // other codes

    public interface TaskManagerListener {
        void onLoad();
    }

    // other codes
}

Then I wrapped it inside a JAR using ProGuard for obfuscation/shrinking.
I used the following ProGuard configuration:

-keepattributes InnerClasses
-keep public class package.name.of.TaskManager { *; }
-keep public interface package.name.of.TaskManager$TaskManagerListener { *; }

I verified from the JAR that the class and the inner interface are there: this image.

My problem now is when I try to access that inner interface from the code that uses the JAR. I can access the TaskManager class fine but the accessing TaskManager.TaskManagerListener raises a compile error.

These work:

  1. public class MyTaskManager extends TaskManager {..}
  2. TaskManager tm = new TaskManager();

But these do NOT:

  1. public class MyTaskManagerListener implements TaskManager.TaskManagerListener

  2. new TaskManager.TaskManagerListener() { @Override public void onLoad() {..} });

A "Cannot resolve symbol TaskManagerListener" error is raised.

I tried to access the TaskManager.TaskManagerListener from the original code of the JAR library and it's working OK. So I guess I only can't access it when it's inside a JAR..?

Is there a way to make this work?
Or is my expectation wrong?
I'm not sure if there's something missing from my ProGuard config or with my understanding of Java and inner interfaces.

I already checked this answer and I'm already considering the workaround to not use a nested interface.


Solution

  • I've made a dumb mistake.
    The ProGuard config that I used was actually correct, but another keepattributes !InnerClasses option was negating the config that I used (apparently, the order of the keepattributes options does not really matter).

    This is still correct:

    -keepattributes InnerClasses
    -keep public class package.name.of.TaskManager { *; }
    -keep public interface package.name.of.TaskManager$TaskManagerListener { *; }
    

    Which will produce the obfuscated JAR below:

    enter image description here

    Which now makes these work:

    1. public class MyTaskManager extends TaskManager {..}
    2. TaskManager tm = new TaskManager();