I'm developing some apis for android as a library project and I'd like to export them as an obfuscated jar.
I have various classes but the only public entities are:
MyInterface: An interface listing some methods that the user will have to implement;
MyUtilities: A class with some static methods;
MySingleton: A Singleton (implemented as an enum with a single INSTANCE);
MyObject: A class implementing a particular object I need to handle;
I am new with Obfuscation so I followed some tutorials and read android/proguard docs.
I successfully created a jar from my project and used it in an external application.
I also successfully obfuscated all the non-public classes (so every class apart from the above-mentioned) and it still continue working.
Now my problem:
One of the methods specifed in MyInterface is
public void getObject(HashMap<String, MyObject>);
before obfuscation the user could add implements MyInterface to his activity/class and (auto) generate the implementation of the the interface methods, in particular:
#Override
public void getObject(HashMap<String, MyObject> hashmap){
// User implementation
}
After having obfuscated the jar, when I add implements MyInterface to a user activity and auto-generate the methods implementations, I get:
#Override
public void getObject(HashMap hashmap){
// User implementation
}
So without HashMap types. I honestly don't know why this happens..
I expected to see also the HashMap types because both String and MyObject are kept.
It still works also without HashMap types, but I have to cast it to a Hasmap<String, MyObject>
This is my proguard conf file (generated by the proguard gui tool):
-injars inAPIs.jar
-outjars 'obfAPIs.jar'
-libraryjars /My/android/SDK/Path/platforms/android-15/android.jar
-libraryjars /My/android/SDK/Path/tools/support/annotations.jar
-libraryjars /My/android/SDK/Path/add-ons/addon-google_apis-google-15/libs/effects.jar
-libraryjars /My/android/SDK/Path/add-ons/addon-google_apis-google-15/libs/maps.jar
-libraryjars /My/android/SDK/Path/add-ons/addon-google_apis-google-15/libs/usb.jar
-overloadaggressively
-keep class my.package.MyObject {
public <fields>;
public <methods>;
}
-keep public class my.package.MyUtilities {
public <fields>;
public <methods>;
}
-keep interface my.package.MyInteface {
public <fields>;
public <methods>;
}
-keep public class my.package.MySingleton {
public <fields>;
public <methods>;
}
-keep,allowshrinking public class my.package.MyInterface {
public <fields>;
public <methods>;
}
-keep,allowshrinking public class my.package.MyObject
-keep,allowshrinking public class my.package.MyUtils
-keep,allowshrinking public enum my.package.MySingleton {
public <fields>;
public <methods>;
}
According to Proguard docs, you may want to add the following option:
-keepattributes Signature
Quoting their docs:
The "Signature" attribute is required to be able to access generic
types when compiling in JDK 5.0 and higher.
Related
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'm using proguard to obfuscate a (SDK) jar file I've created.
The SDK contains a Java Service, a statically compiled C++ lib and a SWIG (ver 2) interface via which the Service and the lib communicates.
I've added relevant '-keep' and '-keepclasseswithmembernames,includedescriptorclasses' statements to the configuration file.
But one file keeps getting (partially) obfuscated.
The first part of the proguard config looks like this (all collected from the net):
-libraryjars '/Library/DevTools/adt-bundle-mac-x86_64-20140702/sdk/platforms/android-21/android.jar'
-libraryjars 'libs/android-support-v4.jar'
-libraryjars "libs/armeabi-v7a/libnativesdk.so"
-dontskipnonpubliclibraryclasses
-injars bin/mysdklib.jar
-verbose
-dontshrink
-dontoptimize
-dontusemixedcaseclassnames
-keep public class * extends android.app.Activity
-keep public class * extends android.app.Application
-keep public class * extends android.app.Service
-keep public class * extends android.content.BroadcastReceiver
-keep public class * extends android.content.ContentProvider
-keep public class * extends android.app.backup.BackupAgentHelper
-keep public class * extends android.preference.Preference
-keepclasseswithmembernames class * {
native <methods>;
}
-keepclasseswithmembers class * {
public <init>(android.content.Context, android.util.AttributeSet);
}
-keepclasseswithmembers class * {
public <init>(android.content.Context, android.util.AttributeSet, int);
}
-keepclassmembers class * extends android.app.Activity {
public void *(android.view.View);
}
-keepclassmembers enum * {
public static **[] values();
public static ** valueOf(java.lang.String);
}
-keep class * implements android.os.Parcelable {
public static final android.os.Parcelable$Creator *;
}
My specific classes addition looks like this:
-keepclasseswithmembernames,includedescriptorclasses class com.company.MySdkIfJNI{
private final static native void swig_module_init();
public static *;
public final static native <methods>;
}
-keepclasseswithmembernames,includedescriptorclasses class com.company.MySdkWrapper{
public *;
}
-keep class com.company.IntWrapper
-keep class com.company.StatisticsParcel{
public *;
}
-keep class com.company.JNILibCallbacks
All the classes I keep works fine. The problem is with the 'MySdkIfJNI' class.
This is an Swig (http://www.swig.org/) auto-generated interface between the native lib and the Java service.
I tried various configurations in order to keep this class as is but proguard keeps obfuscating it.
I tried '-keep' , '-keepclasseswithmembernames,includedescriptorclasses', '-keepclasseswithmembernames'
-keepclasseswithmembernames,includedescriptorclasses class com.company.MySdkIfJNI{
private final static native void swig_module_init();
public static *;
public final static native <methods>;
*;
}
both with arguments and without arguments
But after proguard finishes (without any errors / warnings) I find out that only part of the methods has been obfuscated.
The native methods are kept, such as:
public final static native void JniMYSdkClient_setLogLevel(long jarg1, JniMYSdkClient jarg1_, int jarg2);
public final static native void delete_JniMYSdkClient(long jarg1);
But all the Java methods that starts with SwigDirector are obfuscated, such as:
public static void SwigDirector_JNIMyCallbacks_onEvent(JNIMyCallbacks self, int accountId, int eventId, String sessionId, String msg) {
self.onEvent(accountId, eventId, sessionId, msg);
}
This obfuscation causes the Native swig interface to fail finding this callback methods and my lib crashes.
Any ideas of how can I keep this specific class AS-IS ?
Thanks in advance,
Or Pol.
Well, I didn't find any solution to the particular SWIG methods but since the SWIG wrapping code is already really messy I have decided it doesn't have to be obfuscated with Proguard.
I moved the SWIG interface to an external JAR file and imported it as '-libraryjars'
Now the native layer finds this methods and everything works perfect.
Thanks anyway!
Best regards,
Or.
Swig callbacks need to be keep from obfuscation.
First try to keep all generated java files by swig and compile and see. Crash will fix. Like below
-keep com.custom.project** { *; }
-dontwarn com.custom.project**
Next maximize your files for obfuscation.
Hope it helps.
I'm trying to prevent proguard from obfuscating interface method variable names. My proguard.pro has the following configurations but still the method variables appear as a, b etc.
-keep public class * {
public *; }
-keepclassmembers class * {
public *; }
-keepattributes Exceptions,InnerClasses,Signature
-keepparameternames
-keep public interface com.test.listener.MyListener { *; }
-keep interface com.yourpackage.**{*;} is what you need. It will keep all your interface's name and methods.
-keep public interface com.yourpackqge.yourapp.**{*;}
This works for me
I am having a hell of a time with Gson and ProGuard. I have a simple object and when I parse tojson, save to sqllite and read back from the database in order to load the json back to my object, I get a java.lang.classcastexception. If I dont use ProGuard, everthing works fine.
I have verified that the json string being sent to and gotten from the database is the same. The exception is not thrown when it converts from json, but rather when I try to access the object.
Here is my simple object:
public class ScanLog extends ArrayList<SingleFrame>
{
private static final long serialVersionUID = 1L;
public ScanLog()
{
}
}
public final class SingleFrame
{
public int Position;
public int Time;
public Map<Integer,String> MainDataMap;
public Map<Integer,String> DataMap;
public SingleFrame(int position, int time,
Map<Integer,String> mainDataMap, Map<Integer,String> dataMap)
{
this.Position = position;
this.Time = time;
this.MainDataMap = mainDataMap;
this.DataMap = dataMap;
}
}
All other aspects of my app are fine, but something with proguard is causing this to happen....Ive tried all kinds of -keep commands in the proguard.cfg but I am not sure what Im doing is right.
EDIT - ADDING PROGUARD.CFG
-dontusemixedcaseclassnames
-dontskipnonpubliclibraryclasses
-dontpreverify
-verbose
-dontshrink
-dontoptimize
-keep public class * extends android.app.Activity
-keep public class * extends android.app.Application
-keep public class * extends android.app.Service
-keep public class * extends android.content.BroadcastReceiver
-keep public class * extends android.content.ContentProvider
-keep public class * extends android.app.backup.BackupAgentHelper
-keep public class * extends android.preference.Preference
-keep public class com.android.vending.licensing.ILicensingService
#keep all classes that might be used in XML layouts
-keep public class * extends android.view.View
-keep public class * extends android.app.Fragment
-keep public class * extends android.support.v4.Fragment
#keep all classes
-keep public class *{
public protected *;
}
#keep all public and protected methods that could be used by java reflection
-keepclassmembernames class * {
public protected <methods>;
}
-keepclasseswithmembernames class * {
native <methods>;
}
-keep public class org.scanner.scanlog.SingleFrame
-keepclassmembers class org.scanner.scanlog.ScanLog {
private <fields>;
public <fields>;
}
-keepclassmembers class org.scanner.scanlog.SingleFrame {
private <fields>;
public <fields>;
}
-keepclasseswithmembernames class * {
public <init>(android.content.Context, android.util.AttributeSet);
}
-keepclasseswithmembernames class * {
public <init>(android.content.Context, android.util.AttributeSet, int);
}
-keepclassmembers enum * {
public static **[] values();
public static ** valueOf(java.lang.String);
}
-keep class * implements android.os.Parcelable {
public static final android.os.Parcelable$Creator *;
}
-dontwarn **CompatHoneycomb
-dontwarn org.htmlcleaner.*
#-keep class android.support.v4.** { *; }
EDIT - Okay I got ACRA set up successfully in my app, pretty awesome feature!
Here is the stack trace:
java.lang.ClassCastException: java.lang.Object
at org.scanner.activity.ReaderMainActivity.AdvanceScanLog(SourceFile:1499)
at org.scanner.activity.r.onProgressChanged(SourceFile:271)
at android.widget.SeekBar.onProgressRefresh(SeekBar.java:89)
at android.widget.ProgressBar.doRefreshProgress(ProgressBar.java:507)
at android.widget.ProgressBar.refreshProgress(ProgressBar.java:516)
at android.widget.ProgressBar.setProgress(ProgressBar.java:565)
at android.widget.AbsSeekBar.trackTouchEvent(AbsSeekBar.java:337)
at android.widget.AbsSeekBar.onTouchEvent(AbsSeekBar.java:292)
at android.view.View.dispatchTouchEvent(View.java:3932)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:906)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:906)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:906)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:906)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:906)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:906)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:906)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:906)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:906)
at com.android.internal.policy.impl.PhoneWindow$DecorView.superDispatchTouchEvent(PhoneWindow.java:1784)
at com.android.internal.policy.impl.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1157)
at android.app.Activity.dispatchTouchEvent(Activity.java:2181)
at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchTouchEvent(PhoneWindow.java:1759)
at android.view.ViewRoot.deliverPointerEvent(ViewRoot.java:2336)
at android.view.ViewRoot.handleMessage(ViewRoot.java:1976)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:143)
at android.app.ActivityThread.main(ActivityThread.java:4263)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:507)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:839)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:597)
at dalvik.system.NativeStart.main(Native Method)
For the latest version of the recommended proguard configuraiton file, please see the gson supplied android proguard example at:
https://github.com/google/gson/blob/master/examples/android-proguard-example/proguard.cfg
These settings in the config worked for me in one of my apps:
# Add the gson class
-keep public class com.google.gson
# Add any classes the interact with gson
-keep class com.someapp.android.models.ChatModel { *; }
-keep class com.someapp.android.models.FeedModel { *; }
# Add the path to the jar
-libraryjars /Users/someuser/Documents/workspace/someapp/lib/gson-1.7.1.jar
Hopefully this helps you out.
Applying the changes found in the Android example in the Gson project worked for me
The lines needed were:
-keepattributes Signature
-keep class sun.misc.Unsafe { *; }
# and keeping the classes that will be serialized/deserialized
I know the original question was resolved by taking a different approach, but I was having a very similar issue using flexjson and Proguard on Android, and I've solved it, in case anyone runs into it themselves.
When converting back from JSON to my value object which included some ArrayLists, I would get the same ClassCastException. I got it to work by basically having obfuscation enabled but turning all parts of obfuscation off (-keep everything, -keepclassmembers everything and -keepattributes everything) and then working backwards by enabling things a bit at a time.
The result; keeping the entire flexjson library:
-keep class flexjson**
--keepclassmembers class flexjson** {
*;
}
and keeping the Signature and Annotation attribute:
-keepattributes Signature, *Annotation*
I was able to use the flexjson library without incident after that in a proguarded, release version of my app.
I was getting errors for Model classes with proguard If you look at
GSON Proguard you will find a line
# Application classes that will be serialized/deserialized over Gson
-keep class com.google.gson.examples.android.model.** { *; }
replace com.google.gson.examples.android.model. with your model package likewise in my case i replaced it with -keep class com.consumer.myProject.model.** { *; }
rest I copied as such
So, I ended up ditching the Gson library and instead of converting my object to json using gson, I created a custom class in my app to serialize and deserialize the object and store the data that way.
I am overall more happy, even though this has cost me over 12 hours of trying to figure it out. Apparently, PROGUARD and gson must not like each other too much?
As A HUGELY added benefit to not having to use GSON, I noticed that by taking out the GSON library, my app size is cut in half. My app was 577kb and is now only 260kb after removing the gson lib.
It does look like your are keeping everything from your class (fields, methods and the class itself). But to make sure you can add -printseeds outputfile.txt to the proguard.cfg file to verify that proguard really keeps everything you need once obfuscation is done.
BTW, you might think about adding something like ACRA or Android Remote stacktrace that allows you to inspect stacktraces on a built app.
Just to add to all of the other answers, if you guys reached here, it means that you want to obfuscate your code AND use Gson.
If, at the end, you chose to -keep class your instances, it means that these Gson classes WILL NOT BE OBFUSCATED and this solution (or even Gson in general, is not an optimal solution for you).
In this case I would advise to Serialize the classes yourself and store them See #Jessy's answer.
I'm developing apps for Android and using Proguard to obfuscate the code.
Currently i'm using ProGuard configurations:
-optimizationpasses 5
-dontusemixedcaseclassnames
-dontskipnonpubliclibraryclasses
-dontpreverify
-verbose
-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*
-keep public class * extends android.app.Activity
-keep public class * extends android.app.Application
-keep public class * extends android.app.Service
-keep public class * extends android.content.BroadcastReceiver
-keep public class * extends android.content.ContentProvider
-keep public class com.android.vending.licensing.ILicensingService
To maintain custom components names that are used on layouts XML:
-keep public class custom.components.**
To remove debug logs:
-assumenosideeffects class android.util.Log {
public static *** d(...);
public static *** v(...);
}
To avoid changing names of methods invoked on layout's onClick:
-keepclassmembers class * {
public void onClickButton1(android.view.View);
public void onClickButton2(android.view.View);
public void onClickButton3(android.view.View);
}
-keepclasseswithmembernames class * {
native <methods>;
}
-keepclasseswithmembernames class * {
public <init>(android.content.Context, android.util.AttributeSet);
}
-keepclasseswithmembernames class * {
public <init>(android.content.Context, android.util.AttributeSet, int);
}
-keepclassmembers enum * {
public static **[] values();
public static ** valueOf(java.lang.String);
}
-keep class * implements android.os.Parcelable {
public static final android.os.Parcelable$Creator *;
}
The question is (are):
Are any other tags recommended? Why and what for?
It's possible to make a comment on a proguard.cfg file? I would like to have it with comments for what some lines are doing so that other developers don't have doubts about why i added.
Also in proguard, is it possible to maintain the comment header of a file (with the copyright)? If it's not, or it's not a good policy where should i add the copyright?
Android SDK (r20 or higher)
Please check the predefined proguard.config refered in project.properties
proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt
More info: http://proguard.sourceforge.net/manual/examples.html#androidapplication
Here you can check a proguard "default" file that I keep updating: https://medium.com/code-procedure-and-rants/android-my-standard-proguard-ffeceaf65521
Android SDK (r19 or lower)
Based on my answer Enabling ProGuard in Eclipse for Android I've ended up with this generic file. I've added comments to remember what each line is for. It might help people out there so here it is:
-optimizationpasses 5
#When not preverifing in a case-insensitive filing system, such as Windows. Because this tool unpacks your processed jars, you should then use:
-dontusemixedcaseclassnames
#Specifies not to ignore non-public library classes. As of version 4.5, this is the default setting
-dontskipnonpubliclibraryclasses
#Preverification is irrelevant for the dex compiler and the Dalvik VM, so we can switch it off with the -dontpreverify option.
-dontpreverify
#Specifies to write out some more information during processing. If the program terminates with an exception, this option will print out the entire stack trace, instead of just the exception message.
-verbose
#The -optimizations option disables some arithmetic simplifications that Dalvik 1.0 and 1.5 can't handle. Note that the Dalvik VM also can't handle aggressive overloading (of static fields).
#To understand or change this check http://proguard.sourceforge.net/index.html#/manual/optimizations.html
-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*
#To repackage classes on a single package
#-repackageclasses ''
#Uncomment if using annotations to keep them.
#-keepattributes *Annotation*
#Keep classes that are referenced on the AndroidManifest
-keep public class * extends android.app.Activity
-keep public class * extends android.app.Application
-keep public class * extends android.app.Service
-keep public class * extends android.content.BroadcastReceiver
-keep public class * extends android.content.ContentProvider
-keep public class com.android.vending.licensing.ILicensingService
#To remove debug logs:
-assumenosideeffects class android.util.Log {
public static *** d(...);
public static *** v(...);
}
#To avoid changing names of methods invoked on layout's onClick.
# Uncomment and add specific method names if using onClick on layouts
#-keepclassmembers class * {
# public void onClickButton(android.view.View);
#}
#Maintain java native methods
-keepclasseswithmembernames class * {
native <methods>;
}
#To maintain custom components names that are used on layouts XML.
#Uncomment if having any problem with the approach below
#-keep public class custom.components.package.and.name.**
#To maintain custom components names that are used on layouts XML:
-keep public class * extends android.view.View {
public <init>(android.content.Context);
public <init>(android.content.Context, android.util.AttributeSet);
public <init>(android.content.Context, android.util.AttributeSet, int);
public void set*(...);
}
-keepclasseswithmembers class * {
public <init>(android.content.Context, android.util.AttributeSet);
}
-keepclasseswithmembers class * {
public <init>(android.content.Context, android.util.AttributeSet, int);
}
#Maintain enums
-keepclassmembers enum * {
public static **[] values();
public static ** valueOf(java.lang.String);
}
#To keep parcelable classes (to serialize - deserialize objects to sent through Intents)
-keep class * implements android.os.Parcelable {
public static final android.os.Parcelable$Creator *;
}
#Keep the R
-keepclassmembers class **.R$* {
public static <fields>;
}
###### ADDITIONAL OPTIONS NOT USED NORMALLY
#To keep callback calls. Uncomment if using any
#http://proguard.sourceforge.net/index.html#/manual/examples.html#callback
#-keep class mypackage.MyCallbackClass {
# void myCallbackMethod(java.lang.String);
#}
#Uncomment if using Serializable
#-keepclassmembers class * implements java.io.Serializable {
# private static final java.io.ObjectStreamField[] serialPersistentFields;
# private void writeObject(java.io.ObjectOutputStream);
# private void readObject(java.io.ObjectInputStream);
# java.lang.Object writeReplace();
# java.lang.Object readResolve();
#}
For standard builds with Ant or Eclipse, the Android SDK (r20 or higher) already provides a suitable configuration, referenced by the property proguard.config in the file project.properties (as Michal points out in his answer). In older releases, you always had to specify your own complete configuration, so older advice (like the first answer) can lead to some confusion.
For custom builds, you can find the latest recommended configuration in the ProGuard manual > Examples > A complete Android application. The Proguard distribution also contains a sample file examples/android.pro
Notably, you may want to preserve annotations, and setters in View extensions.
You can add comments after a hash character '#', as extensively done in the sample files.
In your project file called project.properties, set following value:
proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt
This will take the latest version of Proguard settings from Android SDK.