Search code examples
androidabstract-classproguard

Proguard, Android, and abstract class instantiation


"Abstract class instantiation," you say. "Impossible!"

Here's my code:

public static AbstractFoo getAbstractFoo(Context context) {
    try {
        Class<?> klass = Class
                .forName("com.bat.baz.FooBar");
        Constructor<?> constructor = klass.getDeclaredConstructor(
                String.class, String.class);
        constructor.setAccessible(true);

        AbstractFoo foo = (AbstractFoo) constructor.newInstance(
                "1", "2");
        return foo;
    } catch (ClassNotFoundException e) {
        // Ignore
    } catch (NoSuchMethodException e) {
        throw new InflateException(
                "No matching constructor");
    } catch (IllegalAccessException e) {
        throw new InflateException("Could not create foo", e);
    } catch (InvocationTargetException e) {
        throw new InflateException("Could not create foo", e);
    } catch (InstantiationException e) {
        throw new InflateException("Could not create foo", e);
    }
    return null;
}

com.bat.baz.FooBar is a private class that extends AbstractFoo. Without Proguard, this code runs on my Android device. With it, it fails on the NoSuchMethodException try/catch.

I continue to add statements to my Proguard config file like

-keep public abstract class  AbstractFoo
{public *;protected *; private *;} 

But that doesn't solve the problem. How can I get Proguard to accept that this is a valid way to instantiate the AbstractFoo object? At least, if it works without Proguard, it should work with it.


Solution

  • ProGuard is removing the constructor from the code, because it appears unused. ProGuard can't detect that the constructor is being called by reflection. So, you have to keep it explicitly:

    -keepclassmembers class com.bat.baz.FooBar {
      <init>(java.lang.String, java.lang.String);
    }
    

    Please note that you may have better chances with questions like these on ProGuard's help forum.