Is it possible to tell the ProGuard to completely skip the class if there is native function in it ?
-keepclasseswithmembernames class * { native <methods>; }
Above doesn't work for me because it keeps the class names and the native functions names but obfuscates other members
I'd like to know if it's possible to keep everything in such classes without explicitly specifying every class
Thank you
Is it possible to tell the ProGuard to completely skip the class if there is native function in it
Use these rules:
-keepclasseswithmembers class com.your.packages.** {
native <methods>;
}
-keepclassmembers class com.your.packages.** {
native <methods>;
}
Note, that "completely skipping" class with Proguard is a always bad idea, because it may also indirectly keep some classes, used from code of your kept classes. Instead I recommend the following mode:
-keepclasseswithmembers,allowshrinking,allowoptimization class com.your.packages.** {
native <methods>;
}
-keepclassmembers class com.your.packages.** {
native <methods>;
}
It will allow shrinking and optimizing code of non-native methods, present in the same class.
You can do even better: if your native methods are resolved by names (e.g. they are called something like Java_com_your_packages_methodName), and you don't use RegisterNatives to register them explicitly, you may allow shrinking away unused native methods by removing the second rule, which will leave only
-keepclasseswithmembers,allowshrinking,allowoptimization class com.your.packages.** {
native <methods>;
}
If you want some of class members to be accessible from JNI (e.g. you have some static callback methods to be called from native code), you should keep them explicitly: annotate each such member with specialized annotation and use an annotation-based rule to keep them:
-keepclassmembers,allowoptimization,includedescriptorclasses class com.your.packages.** {
#android.support.annotation.Keep *;
}
You can use your own annotation in place of the one from Android support library — in fact, it is better to use your own in order to avoid interference from existing consumer rules, coming from Android Gradle plugin or other libraries.
In general, I recommend you to reduce the amount of friction between JNI and Java code as much as possible. If you have multiple related Java methods, called from JNI, try to put them together in the same method:
#Keep
public static void callback(int action, String arg) {
switch (action) {
...
}
}
Throw your exceptions from Java code (you was going to reflectively invoke their constructors anyway, so may as well invoke a static helper method instead):
#Keep
public static void throwException(int type, String message) {
switch (type) {
case 0:
throw new BadThingsHappenedException(message);
case 1:
throw new AllHopeIsLostError();
...
}
}
If you have a class, that has to be passed to JNI, try to pass individual fields instead of that class:
public final class DataClass {
int intField;
String stringField;
public void doSomeNativeOperation() {
JNI.doSomeNativeOperation(this);
}
}
public final class JNI {
public static void doSomeNativeOperation(DataClass arg) {
doSomeNativeOperation0(arg.intField, arg.stringField);
}
private static native void doSomeNativeOperation0(int intField, String stringField);
}
If you have a native peer class (a class, closely connected to some structure in native memory), you can keep a pointer to native structure in that class in long field, and pass that field to native methods. Then in native methods cast that long to pointer:
public final class Peer {
long pointer;
// constructor is invoked from JNI
#Keep
protected Peer(long pointer) {
this.pointer = pointer;
}
public void doSomeNativeOperation() {
JNI.doSomeNativeOperation(this);
}
}
public final class JNI {
public static void doSomeNativeOperation(Peer peer) {
doSomeNativeOperation0(peer.pointer);
}
private static native void doSomeNativeOperation0(long pointer);
}
And in native code:
void JNIEXPORT Java_com_your_packages_methodName(JNIEnv* env, jobject type, jlong ptr) {
struct my_struct peer = (struct my_struc*) (intptr_t) ptr;
...
}
These simple rules will allow you to fully obfuscate any huge application using JNI, except for a single small class, that contains all native methods.
I suggest you go even further and push for repackaging classes, referenced by native callbacks.
Instead of
#Keep
public static void callback(YourCustomType arg) {
...
}
You can omit a type of parameter by replacing it with Object:
#Keep
public static void callback(Object arg) {
// this cast won't make much difference in performance, but it makes huge
// difference for Proguard!
YourCustomType instance = (YourCustomType) arg;
...
}
This will let you obfuscate and repackage even types of callback arguments.
Use -keep instead of -keepclasseswithmembernames
-keep class * { native <methods>; }
For more info: https://jebware.com/blog/?p=418
-keep disables all of ProGuard’s goodness. No shrinking, no obfuscation; not for classes, not for members.
Related
I was using this keywords for obfuscation with proguard in my android-java project :
do
if
for
int
new
try
byte
case
char
else
goto
long
this
void
break
catch
class
const
final
float
short
super
throw
while
double
import
native
public
return
static
switch
throws
boolean
default
extends
finally
package
private
abstract
continue
strictfp
volatile
interface
protected
transient
implements
instanceof
synchronized
but I'm switching to Kotlin and now the question is what keywords should i use for Kotlin ?
I've found this but should i use all of them ?
You are misunderstanding what proguard obfuscates. Proguard operates on Java Bytecode. Giving it a list of keywords from a JVM language really doesn't do anything for your obfuscation.
I have the following code:
public class MyClass {
public void method1(Integer marks) {
}
private String method3(String name){
}
public interface interface1 {
void method4(Integer ID);
void method5(Integer rate, boolean status);
}
}
I have used progaurd-rules.pro
-keepattributes Exceptions,InnerClasses,Signature,Deprecated,SourceFile,LineNumberTable,*Annotation*,EnclosingMethod
-keepparameternames
-keep public class *
-keepclassmembers public class *{
public *;
}
-keep public interface packageName.MyClass$interface1 { *; }
Obfuscated code as below:
public class MyClass {
public void method1(Integer marks) {
}
private String a(String var1){
}
public interface interface1 {
void method4(Integer var1);
void method5(Integer var1, boolean var2);
}
}
I want the interface methods variables (ID, rate & status) not to obfuscate. i.e as below
public interface interface1 {
void method4(Integer ID);
void method5(Integer rate, boolean status);
}
How can it be possible?
You could keep method's arguments by adding extra flags to -keepattributes. They look like this:
-keepattributes LocalVariableTable,LocalVariableTypeTable
Unfortunately, this keeps arguments from obfuscation not only in the interface you want, but in the entire project. Maybe that's fine for you.
If you're using a default proguard configuration shipped along with Android SDK then you could also use a special annotation to prevent some classes from obfuscation. Check it out.
public interface SSOListener {
void sendDataToAnalytics(String event, JSONArray object);
}
// In my case JsonArray was obfuscated.
Solution :
-keep class org.json.JSONArray**, ** {
protected <fields>;
public <fields>;
<methods>;
}
-keepattributes LocalVariableTable,LocalVariableTypeTable
The above keepattributes didn't work for me. However -keepparameternames did. I added this to the internal Proguard config that our Android Library uses. The other non keot classes still have their params obfuscated.
Note: I'm using R8 to actually obfuscate which is the default when using the Android Gradle Plugin since 3.4.0 also we are enforcing source and target compatibility to 1.8 (due to unrelated okhttp dependency)
ProGuard uses the naming convention of Java bytecode, as seen in class file names and stacktraces. Therefore:
-keep public interface com.somepackage.SomeClass$someInterface {*;}
In case if your interface is not public.
-keep interface com.somepackage.SomeClass$someInterface {*;}.
I have a proguard.cfg file which contains several statements including optimization passes and logs suppression as :
-assumenosideeffects class android.util.Log { *; }
-assumenosideeffects class com.badlogic.gdx.Application {
public static void debug(...);
public static void error(...);
public static void log(...);
}
Calls to Log.* are correctly removed in the final output APK file. But gdx log calls are still in the code. For example I can still see things like that in the output :
Gdx.app.debug("debug()", "^");
Gdx.app.error("error()", "^");
Gdx.app.log("log()", "^");
I also tried to put this part of my config in a proguard-optimize.txt file as I have seen on similar questions and then setting the proper value in project.properties files like this : proguard.config=proguard-optimize.txt:proguard.txt but it doesn't work !
These calls get removed only if I put a general wildcard :
-assumenosideeffects class com.badlogic.gdx.Application {
*;
}
But I don't want to remove calls to other Application's static methods, like add* and get*() ones.
Optimization step is enabled (6 passes).
Gdx.app.debug is not static its an instance method (app is a static field of the Gdx class).
Try:
-assumenosideeffects class com.badlogic.gdx.Application {
public void debug(...);
public void error(...);
public void log(...);
}
Try something like this in your application's code:
Gdx.app.setLogLevel(Application.LOG_NONE);
That will prevent messages from being logged.
Cheers!
Conside the following code structure for android:
package blah;
class A{
class B{
public void foo(String s){
}
}
}
How can I tell proguard to not remove or obfuscate foo.
foo is unused function in code at compile time but is run at run-time from another code.
I have tried:
-keep class blah.A.B;
-keepclassmembers class blah.A.B {
public void foo(String s);
}
etc. but nothing stops Proguard from removing that function.
I do not want proguard to change name of 'foo'. Proguard may change the name of class A or class B but not the function name 'foo'.
Any suggestions?
Almost right. In java bytecode, the $ character separates the names of inner classes and their outer classes (to avoid ambiguities with package names). So, to keep just the method:
-keepclassmembers class blah.A$B {
public void foo(java.lang.String);
}
I have a method 'myClickHandler' referenced only in an xml file.
This
-keepclassmembers class * extends android.app.Activity {
public void myClickHandler(android.view.View );
}
stops it being removed in my application. Perhaps the extends .. will work for you
For my Android instrumentation test I need a few extra entry point into my classes. Those methods are not used in the actual application. My idea was to start them all with test_ and have a general rule to exclude them from being optimized away. This is how far I got:
-keepclassmembers class com.xxx.**.* {
public ** test_* ();
public ** test_* (**);
public static ** test_* ();
public static ** test_* (**);
}
But it still does not work. public static void test_destroy (final android.content.Context context) and private void dropTables (final SQLiteDatabase db) has just been removed from the code. And I have no idea why.
How is it properly used for wildcard patterns?
The solution is
-keepclassmembers class com.XXX.**.* {
*** test_* (...);
}
Another way to do this is to use an annotation (i.e. guava's #VisibleForTesting) to mark those methods. Then in proguard you can keep all entry points and members with that annotation:
-keep #com.google.common.annotations.VisibleForTesting class *
-keepclasseswithmembers class * {
#com.google.common.annotations.VisibleForTesting *;
}