androidproguardobfuscationandroid-proguard

Why some package-private classes are not obfuscated by Proguard?


Working with an Android project in Android Studio 3.2, having enabled Proguard and some specific rules, I'm not able to figure out the following:

a specific package (and its subpackages) in a library module, used by client code, is preserved through the rule:

-keep public class com.mylib.mypackage.** {
    public protected *;
}

Now, within this package there are also a number of package-private classes, which should not be picked by that rule. Some of those classes are effectively obfuscated, both in their own names and their member names, which is fine.

Instead there are some classes, implementing public interfaces, whose class names are not obfuscated, while I'd expect they should. For completeness, their member names, when not part of interface, are effectively obfuscated.

Example:

/* package */ class InternalComponent implements ExternalInterface {

  // ExternalInterface is kept: Ok
  // InternalComponent is kept: don't like, I'd like it renamed

  @Override
  public void ExternalMethod() {
    // this is kept: Ok
  }

  public void InternalMethod() {
    // this is renamed: Ok
  }
}

I'd like to highlight that InternalComponent is created within some other (kept) class and only returned to client code through the ExternalInterface.

How can I also obfuscate their class names as well, if possible?

Edit #1
After @emandt answer on Proguard output files, I double checked and com.mylib.mypackage.InternalComponent is listed in seeds.txt, which according to this blog post lists all items matched by keep rules. So, for some reason, the rule above also picks package-private classes, which still seems wrong to me.

Edit #2 In the meantime, I ended up doing exactly the same approach proposed by @shizhen. For completeness, in order to extend the exclusion to any package named internal, I modified my proguard rule as:

-keep public class !com.mylib.mypackage.**.internal.*, com.mylib.mypackage.** { 
    public protected *;
}

(note the first part before the comma, prefixed by !)

I'll mark @shizhen answer, though I'd like to be curious as to why the original rule is also picking package-private components.


Solution

  • Are you working on an Android Library project? Probably YES.

    In order to achieve your purpose, I am afraid that you need to re-organise your packages into something like below:

    Public interfaces

    com.my.package.apiforusers
    

    Private/Internal implementations

    com.my.package.apiforusers.internal
    

    Then for your obfuscation rules, you can have it like below:

    -keep public class com.my.package.apiforusers.** { public *; }
    

    So that only the public classes/interfaces are kept and all those ones inside com.my.package.apiforusers.internal will be obfuscated.

    Please note the double-asterisk at the end so that public classes/interface are also kept for the sub-packages.