Proguard and reflection in Android
SOLVED
For others that are having this problem you need to add the following to proguard.cnf
-keep public class * extends com.yoursite.android.yourappname.YourClassName
-keepclassmembers class * extends com.yoursite.android.yourappname.YourClassName{
public <init>(android.content.Context);
}
The first keep tells proguard to not obfuscate class names that extend YourClassName
The second one says to keep the constructor name (<init>
means constructor) un-obfuscated that has a single argument of Context
and extends YourClassName
In addition, for android developers that are using the onClick attribute in you XML layouts file you will also need to add the name of the function in your proguard.cnf file.
-keepclassmembers class * {
public void myClickHandler(android.view.View);
}
This says keep all methods named myClickHandler
with a single argument View
in all classes. You could further constrain this by using the extends keyword like above.
hope this helps.
Keep classes that use reflection Android Proguard
This did the trick for me.
# Bottom Navigation Helper
-keep class android.support.design.internal.BottomNavigationItemView{ *; }
-keep class android.support.design.internal.BottomNavigationMenuView{ *; }
Can I use Reflection with ProGuard obfuscated classes?
ProGuard documentation mentions the following:
It is generally impossible to compute which classes have to be
preserved (with their original names), since the class names might be
read from a configuration file, for instance. You therefore have to
specify them in your ProGuard configuration, with the same simple
-keep options.
However, there are SOME cases in which ProGuard automatically handles Reflection. Those are the following: (please refer to the documentation for the most recent list)
Class.forName("SomeClass") SomeClass.class
SomeClass.class.getField("someField")
SomeClass.class.getDeclaredField("someField")
SomeClass.class.getMethod("someMethod", new Class[] {})
SomeClass.class.getMethod("someMethod", new Class[] { A.class })
SomeClass.class.getMethod("someMethod", new Class[] { A.class, B.class })
SomeClass.class.getDeclaredMethod("someMethod", new Class[] {})
SomeClass.class.getDeclaredMethod("someMethod", new Class[] { A.class })
SomeClass.class.getDeclaredMethod("someMethod", new Class[] { A.class, B.class })
AtomicIntegerFieldUpdater.newUpdater(SomeClass.class, "someField")
AtomicLongFieldUpdater.newUpdater(SomeClass.class, "someField")
AtomicReferenceFieldUpdater.newUpdater(SomeClass.class, SomeType.class, "someField")
So, in my case, my error was that I was getting the class using getClass()
.
The following line did work great.
aMethod = MainActivity.class.getDeclaredMethod("myMethodName", SomeParameter.class);
How to keep java.lang.reflect when use proGuard?
The reasons behind getting runtime exceptions may vary depending on the code that you implemented.
One of the reasons behind getting the exception may be relying on field/classes/method names in your code using reflection - ProGuard renames your classes while obfuscating so in order to have them accessible after the obfuscation, they need to be prevented explicitly from the obfuscation.
-keep app.package.FancyClass { *; }
If it is the library itself that crashes the obfuscated app then I suggest finding the exact place and explicitly keeping the classes that the class where the exception occurs depends on.
The easiest case might be to keep the entire library:
-keep com.stone.pile.** { *; }
but you can very often configure ProGuard to be more aggressive than that. Nevertheless it's a good starting point.
I think -keep java.lang.reflect.**
rule does not help much here. The root cause is in the code that relies on class internals that need to be excluded from the obfuscation.
Locate the vulnerable code and try to keep the classes/methods/internals accessed via reflection.
EDIT:
It would be of great help if you pasted the class file with the place where the exception is thrown pointed. The exception message would also add up to the context. Can you do that please?
How to get class package after obfuscation for use in reflection with Proguard on Android
I found elegant solution. I store string constant into environment variable with value of needed class package. I can access any needed obfuscated data via static string key of environment variable. Even class name itself was obfuscated I would get always needed data. It is easy to access this data from any module in application since it is in environment variable.
static {
System.setProperty(Const.NEEDED_PACKAGE, NeededClass.class.getPackage()).getName());
}
Android Proguard/R8 reflection error: NoSuchFieldException
For anybody else who may have this problem in the future, turns out I needed to clean, rebuild, then invalidate cache and restart.
How to keep java.lang.reflect when use proGuard
Reflection will need to have absolute path the the classes and its respective methods. So, you need to tell proguard to leave the stuff you need alone. You can describe this in your proguard-rules.pro
file.
Example:
-keep public class fully_qualified_classname
-keepclassmembers public class fully_qualified_classname {
# will ignore all methods
public <methods>;
public static final String static_instance_variable_if_any;
}
Related Topics
The Specified Dsn Contains an Architecture Mismatch Between the Driver and Application. Java
Setting a Timeout for Socket Operations
How to Write Custom Exceptions
Didn't Find Class "Androidx.Core.App.Corecomponentfactory"
Transformexception Duplicate Entry for Common.Annotations.Beta
JPA Support for Java 8 New Date and Time API
Why Comparing Integer with Int Can Throw Nullpointerexception in Java
Boolean[] VS. Bitset: Which Is More Efficient
How to Get Country Phone Prefix from Iso
Sending Http Post Request with Android
Android Resource Not Found Exception
Leaking This in Constructor Warning
How to Find How Much Disk Space Is Left Using Java
Why We Can't Do List<Parent> Mylist = Arraylist<Child>();