How to keep class which implement an interface with annotation - java

I defined an annotation named #KeepAll.
I have an interface like
#KeepAll
public interface MainEntity {
//some methods
}
I want to keep all classes which implement this interface from obfuscation. Is this possible on ProGuard?
NOTE I know I can define it as
-keep public class * implements **.MainEntity
But I don't want to specify interface name but annotation name.

After a long trial and error process I get what I want. Here is the solution
Keep class names with annotation KeepAll;
-keep #com.package.name.KeepAll public class **
Keep class members of classes and interface with annotation KeepAll;
-keepclassmembers #com.package.name.KeepAll class ** { public <methods>; <fields>;}
Keep class members of a class which implemets a class that has KeepAll annotation. (This was what I want)
-keepclassmembers public class * implements #com.package.name.KeepAll ** { public <methods>; <fields>;}

You can tell ProGuard to keep everything with an annotation like this:
-keep #com.google.inject.Singleton public interface *
The above would keep the interface itself from obfuscation.
To get the implementations of the interface you can do something like this:
-keep public class * implements **.MainEntity
So Right now I am confused what you want to achieve. If you only annotate the interface it wont be a help for ProGuard. The classes would need this annotation.

Related

How to keep ProGuard from separating inner enum

I am trying to ProGuard a public-facing class (MyClass) file containing an inner enum (MyInnerEnum). However, after ProGuarding, the inner enum is separated out into its own class file MyClass$MyInnerEnum. How can I prevent ProGuard from separating out the inner enum? I need to be able to access the inner enum using dot notation, like MyClass.MyInnerEnum.ENUM_VALUE and not using the dollar sign like MyClass$MyInnerEnum.ENUM_VALUE.
My public-facing class:
package com.myclass;
public interface MyClass {
enum MyInnerEnum {
ENUM_VALUE
}
}
I've tried these ProGuard configuration options to no avail:
<option>-keep enum com.myclass.MyClass** { *; }</option>
<option>-keep enum com.myclass.MyClass$* { *; }</option>
<option>-keep enum com.myclass.MyClass$MyInnerEnum { *; }</option>
You can give it a try by keeping the outer class (in your case interface) and the inner enum. By adding the following lines to your proguard config, this should work:
-keep interface com.myclass.MyClass
-keep enum com.myclass.MyClass$MyInnerEnum
I meet the same problem. I resolve it by adding:
# don't proguard all inner enum, need to cooperate with "-keep enum com.companyname.abcd.ClassName$EnumName"
-keepattributes InnerClasses
...
-keep enum com.myclass.MyClass$MyInnerEnum

Android proguard, keep inner class of Inner class

Parent question: Android proguard, keep inner class
My problem is with inner class of inner class
One of the SDKs in my android project has a class A, which has two static inner class. They are found to be stripped after applying proguard.
public class A{
....
static class B{
...
static class D {
....
}
}
static class C{
...
}
}
My proguard looks like this
-keepattributes Exceptions, InnerClasses
-keep class com.xxx.A
-keep class com.xxx.A$*
Which prevents class B, C from proguard. But no luck with class D. I have tried -keep class com.xxx.A$** as well.
I think you're missing the Class specification as shown in the ProGuard manual.
Try replacing:
-keep class com.xxx.A
With:
-keep class com.xxx.** {*;}
I'm using that rule with the following file and it's working fine on Android Studio 2.2.3 with build tools 25.0.1 (just in case those might affect the version of ProGuard being used)
A.java
package com.xxx;
public class A {
....
public class B {
....
public class C {
....
}
}
}
As you can see the only real difference between my file and yours is that my inner classes are public and non-static.
If that doesn't work
You can always use a rule without wildcards. The following will do the trick:
-keep class com.xxx.A$B$D

How to stop ProGuard from stripping the Serializable interface from a class

Is there an explicit way to stop ProGuard from changing a class from implementing an interface?
I have a class that implements java.io.Serializable, let's call it com.my.package.name.Foo. I've found that after running through ProGuard, it no longer implements Serializable. I get null after I cast from Serializable to Foo and false if I check an instance with instanceof Serializable. I've made sure to set ProGuard to ignore this class:
-keep class com.my.package.name.Foo
I've also tried:
-keep class com.my.package.name.Foo { *; }
and I've also tried the whole package by doing this:
-keep class com.my.package.name.** { *; }
or:
-keep class com.my.package.** { *; }
and also just to keep all Serializable classes:
-keep class * implements java.io.Serializable { *; }
but to no avail. I have another class in a sibling package (roughly: com.my.package.name2.Bar) that also implements Serializable and is used similarly but has no issues.
I'm not sure it's relevant, but I'm packing this in a jar for use with Android. The code that uses these classes include putting them in Bundles which is why I need Serializable. I considered that perhaps somehow ProGuard thinks that Foo is never used as a Serializable but that seems unlikely given that I pass it as a parameter to Bundle.putSerializable(String, Serializable) and also I do an implicit cast: Serializable serializable = foo;. In fact, when I debug, I can see the Foo get put into the Bundle and I can examine the Bundle and see the instance of Foo there, but when retrieving it the cast fails.
I had the same issue fixed using below config.
-keepnames class * implements java.io.Serializable
-keepclassmembers class * implements java.io.Serializable {
static final long serialVersionUID;
private static final java.io.ObjectStreamField[] serialPersistentFields;
!static !transient <fields>;
private void writeObject(java.io.ObjectOutputStream);
private void readObject(java.io.ObjectInputStream);
java.lang.Object writeReplace();
java.lang.Object readResolve();
}
Official Documentation
http://proguard.sourceforge.net/manual/examples.html#serializable
ProGuard doesn't ever strip interfaces that are defined in libraries (like Serializable) from classes in code that is processed (like Foo). Library code may be casting to those interfaces, so they can't be removed.
I get null after I cast from Serializable to Foo
This means that the instance must be null to start with. Your analysis would be correct if you'd get a ClassCastException. You can check that Foo still implements Serializable with javap. The problem probably lies elsewhere. For tips on serialization, you can look at the ProGuard manual > Examples > Processing serializable classes.
Update:
In this case, it turns out to be a configuration problem. ProGuard can only process class files if it knows everything about their hierarchy (just like a compiler). You really have to specify the runtime classes:
-libraryjars <java.home>/lib/rt.jar
or for Android:
-libraryjars /usr/local/android-sdk/platforms/android-17/android.jar
The Android Ant/Eclipse builds automatically specify all necessary -injars/-outjars/-libraryjars options for you, but in a custom build process, you have to specify them yourself. Cfr. ProGuard manual > Examples > A complete Android application.
Note that the option -dontwarn makes the warnings go away, but not the problems. Only use it if really necessary.

Com4j and Proguard obfuscation

Com4j integration works fine in my Java application, but not when using Proguard obfuscation (other options turned off). What could I be doing wrong ?
Program hangs at at the COM4J.createInstance(...). I have seen this code stop at the same position before, namely when the Com4j library could not find the underlying com4j.dll native file. However, this code is indeed working without Proguard.
package mypackage;
public abstract class ClassFactory {
private ClassFactory() {}
public static MyInterface createMyComObjectInstance() {
return COM4J.createInstance(MyInterface.class, ComObject_idString );
}
}
The interface is defined thus:
public interface MyInterface extends Com4jObject {....}
Ditto ProGuard config file (tried several variants).
-libraryjars myPath\com4j.jar
-keep public class mypackage.** {*;}
-keep public interface MyInterface {*;}
-keep public abstract class mypackage.ClassFactory {
public static MyInterface createMyComObjectInstance();
//also tried this
*;
}
Note also that Proguard works just fine on the rest of the code, including some JNI/native modules.

Android Proguard Javascript Interface Fail

I use in my project a piece of code as described here
http://lexandera.com/2009/01/extracting-html-from-a-webview/
I create the .apk file, install it on my device and it correctly works. If I try to use the obfuscation with proguard the project fails, the method showHTML(String html) of MyJavaScriptInterface is not reached.
My proguard configuration regarding that
-keep public class com.mypackage.MyClass.MyJavaScriptInterface
-keep public class * implements com.mypackage.MyClass.MyJavaScriptInterface
-keepclassmembers class * implements com.mypackage.MyClass.MyJavaScriptInterface {
<methods>;
}
according to this this answer Android proguard Javascript Interface problem.
SOLVED.
As Eric suggested, I changed the Proguard configuration file like this:
-keep public class com.mypackage.MyClass$MyJavaScriptInterface
-keep public class * implements com.mypackage.MyClass$MyJavaScriptInterface
-keepclassmembers class com.mypackage.MyClass$MyJavaScriptInterface {
<methods>;
}
Now my project works perfectly.
For API 17+ you also need to preserve the #JavascriptInterface annotations:
-keepattributes JavascriptInterface
http://developer.android.com/reference/android/webkit/JavascriptInterface.html
If MyJavaScriptInterface is an inner class of MyClass, ProGuard expects a fully qualified name com.mypackage.MyClass$MyJavaScriptInterface. The naming convention with $ is used in the compiled class files on which ProGuard operates. Note that ProGuard mentions class names in the configuration that it can't find in the input jar, suggesting that these names may have been misspelled.
-keepclassmembers class com.mypackage.MyClass$JavaScriptInterface {
public *;
}
Use only this. It works for me.
Those Who are laze to provide the entire package path.
-keepclassmembers class **.*$PaymentJavaScriptInterface{
public *;
}
As suggested by edit in question,
out of those suggestions,
only using
-keepclassmembers class com.mypackage.MyClass$MyJavaScriptInterface {
public *;
}
with Important -
For API 17+ to preserve #JavascriptInterface annotations:
-keepattributes JavascriptInterface
(Which was stopping my app to work on Marshmallow)

Categories

Resources