Android Proguard - is it best practice to -keep all 3rd party libs? - android

I'm configuring Proguard for an app that uses 3rd party libraries. Is it "best practice" (in order to avoid future hard-to-find bugs) to include the line:
-keep class 3rd_party_lib_name.** {*;}
for every single 3rd party open source library that doesn't have specific Proguard instructions from its developer?
Also, a related question: is there a general guideline for which cases I should use
-keep class
and in which cases i should use
-keep public class
many thanks

The major problem with proguard and code obfuscation in general is that classname, methods and fields name are modified. ( i.e. myExplicitMethodName() became a() )
When a classname, method name or a field is modified, you cannot access it using the reflection API (i.e. Class.classForName(...) , ... )
Knowing that, it's a best practice to -keep all classes and libraries that can be invoked using the reflection API.
For 3rd party libraries, if you don't know if they use or not the reflection API : then -keep
For your own code: hopefully, you know in which classes you use it. So use -keep for those classes.
Note that some popular framework like dagger or jackson use the reflection API on your own classes, so if you use them, be careful!

The fewer -keep options you can use, the better your results will be, in terms of optimization and obfuscation. If you don't have the time to find an optimal configuration, you can take a more conservative approach. The most conservative solution is to preserve all classes, fields, and methods in the library, so any internal reflection will continue to work:
-keep class 3rd_party_lib_name.** {*;}
Slightly less conservative, but typically sufficient: preserve all public API:
-keep public class 3rd_party_lib_name.** {
public *;
}
Even less conservative: only preserve public classes, but not necessarily their fields or methods:
-keep public class 3rd_party_lib_name.**
Some experimentation can go along way.
As ben75 mentions, this doesn't account for third party libraries performing reflection on your own code.

Since some libraries use reflection or json conversion for some classes, if you do not keep library classes, your app will not work properly. For a sample case,
I used honeywell rfid library with proguard. When some classes and enums are not kept, a strange case occurred. When trying to write an rfid tag, even if it has failed, library was returning that it was a successfull writing. All other methods was working properly. So what to do for protecting your own code.
Open the third party library file by double clicking it in Android Studio. Enter into the classes.jar file and determine which packages are used. Then keep these packages in the proguard file.
As an example :
[![third party packages to include][1]][1]
[1]: https://i.stack.imgur.com/lr2fb.png
proguard-rules.pro file must look like this.
-keep class com.honeywell.** { *; }
-keep class com.silionmodule.** { *; }
-keep class com.bth.** { *; }
-keep class com.communication.** { *; }
-keep class com.thingmagic.** { *; }
-keep class com.tool.** { *; }
-keep enum com.honeywell.** { *; }
-keep enum com.silionmodule.** { *; }
-keep enum com.bth.** { *; }
-keep enum com.communication.** { *; }
-keep enum com.thingmagic.** { *; }
-keep enum com.tool.** { *; }

Related

Missing class: com.google.android.aidl.BaseProxy

Occasionally after generating the Signed APK, the following warning would appear
Missing class: com.google.android.aidl.BaseProxy
Missing Class: com.google.android.aidl.BaseStub
However, the APK would be successfully generated. Only when released the warning would be detrimental to the app.
Fatal Exception: java.lang.NoClassDefFoundError
Failed resolution of: Lcom/google/android/aidl/BaseStub
What gradle dependancy is required so this class is found and resolved?
Here are links to my gradle files (shared on google drive):
build.gradle (module: app)
build.gradle (project)
Thanks.
Try to update your proguard rules with the following:
-keepclassmembers class com.google.android.aidl.** { *; }
EDIT: (from proguard documentation)
-keep: Specifies classes and class members (fields and methods) to be preserved as entry points to your code.
-keepclassmembers: Specifies class members (only) to be preserved, if their classes are preserved as well.
If you specify a class, without class members, ProGuard only preserves the class and its parameterless constructor as entry points. It may still remove, optimize, or obfuscate its other class members.
If you specify a method, ProGuard only preserves the method as an entry point. Its code may still be optimized and adapted.
So if you're not sure which option you need, you should probably simply use -keep. It will make sure the specified classes and class members are not removed in the shrinking step, and not renamed in the obfuscation step.
(below -keep includes all classes and class members from aidl)
-keep class com.google.android.aidl.** { *; }
In your case you are missing BaseProxy and BaseStub classes. You can specify only these classes in your -keep and -keepclassmembers and test which method is suitable for you with best code obfuscation for your release build.
(below -keep includes only BaseProxy and BaseStub)
-keep class com.google.android.aidl.BaseProxy { *; }
-keep class com.google.android.aidl.BaseStub { *; }
My suggestion is to specify the class names you don't want to remove and utilize the code obfuscation to reduce your app size.
The symptoms of your issue (only happens in release build means proguard is removing the class) leads me to suggest :
if the class missing is one of yours add this annotation to the that class
#Keep class TheClass { ... }
if the class giving you pain is in the third party lib (mostly you add lib via gradle file in your project ) then normally in the library readme file (from their website like Github repo readme etc ) there is a proguard rules note that you need to add something like :
# Parceler library
-keep interface org.parceler.Parcel
-keep #org.parceler.Parcel class * { *; }
-keep class **$$Parcelable { *; }

Proguard configuration when using Android Studio's Google Cloud Endpoints template

We need to store and retrieve the content that users generate with our app online. To do so, we decided to use Android Studio's integrated Google Cloud Endpoints template to quickly create an API (official usage example here).
It works fine in debug, but in release mode, with Proguard enabled, it fails. Worse still, I've failed to find any documentation or samples about using Proguard with the Android Studio's Endpoints templates.
After an hour or so of poking around and trying to make it work, the proguard-rules.pro now looks like this:
-keep class com.google.api.** { public *; }
-dontwarn com.google.api.**
-keep class com.google.common.** { public *; }
-dontwarn com.google.common.**
# Not allowed to post company and app names, but this line is correct in the real file
-keep class com.companyname.appname.application.backend.** { *; }
With this configuration, I'm getting a class cast exception in my ArrayAdapter:
java.lang.ClassCastException: com.google.api.client.util.ArrayMap cannot be cast to com.companyname.appname.application.backend.messageApi.model.Message
It seems the conversion of returned data isn't performed somewhere and, instead of a List of Message objects, I get a List of com.google.api.client.util.ArrayMap objects (they do contain valid data, by the way).
I COULD check whether the app is running in release mode and do the conversion manually, however, it's a hacky way and I'd prefer to do it properly. So, can someone please tell me what I'm missing in the Proguard configuration file?
I do similar things with endpoints in one of my apps. I had some problems with Proguard as well (can't remember exactly what).
This section of my Proguard rules seems applicable:
# Needed by google-api-client to keep generic types and #Key annotations accessed via reflection
-keepclassmembers class * {
#com.google.api.client.util.Key <fields>;
}
-keepattributes Signature,RuntimeVisibleAnnotations,AnnotationDefault
I don't know if it is necessary, but I also have this section:
# Play Services
-dontwarn com.google.android.gms.**
-dontwarn com.google.common.cache.**
-dontwarn com.google.common.primitives.**
-keep class * extends java.util.ListResourceBundle {
protected Object[][] getContents();
}
-keep public class com.google.android.gms.common.internal.safeparcel.SafeParcelable {
public static final *** NULL;
}
-keepnames #com.google.android.gms.common.annotation.KeepName class *
-keepclassmembernames class * {
#com.google.android.gms.common.annotation.KeepName *;
}
Hope it helps.

Proguard and Netty 5 on Android

I've seen a couple questions regarding this issue, but they are for older versions of Netty.
I have tried their answers, switching org.jboss.netty out with io.netty, but the same error occurs.
I'm trying to compile an Android app that uses Netty 5.0.0Alpha2 (build #16) with Proguard enabled.
Without Proguard, the app runs fine.
As soon as I enable Proguard, I get this exception when it tries to use Netty:
java.lang.IllegalStateException: unknown type parameter 'I': class io.netty.channel.SimpleChannelInboundHandler
at io.netty.util.internal.TypeParameterMatcher.find0(Unknown Source)
at io.netty.util.internal.TypeParameterMatcher.find(Unknown Source)
at io.netty.channel.SimpleChannelInboundHandler.<init>(Unknown Source)
at io.netty.channel.SimpleChannelInboundHandler.<init>(Unknown Source)
...
This is my Proguard config:
# billing
-keep class com.android.vending.billing.**
# butterknife
-dontwarn butterknife.internal.**
-keep class **$$ViewInjector {
*;
}
-keepnames class * {
#butterknife.InjectView *;
}
# admob
-keep public class com.google.android.gms.ads.** {
public *;
}
-keep public class com.google.ads.** {
public *;
}
# logging
-assumenosideeffects class android.util.Log
# netty (partial)
-dontwarn io.netty.**
-dontwarn sun.**
I have tested it without the -dontwarn options to see if the warnings would point me in the right direction, but it's all missing optional dependencies like slf4j and Tomcat.
I have also tried excluding all the Netty classes like so:
-keep class io.netty.** {
*;
}
...but that does not appear to fix it either.
I have fixed this issue with some carefully* applied Proguard rules after reading through parts of the rather huge Netty sources:
-keepattributes Signature,InnerClasses
-keepclasseswithmembers class io.netty.** {
*;
}
-keepnames class io.netty.** {
*;
}
My original exception was caused by the type variables being removed from the bytecode, which Netty uses via reflection. Signature in -keepattributes keeps this information.
You get a slightly different exception if you only do Signature on -keepattributes - adding InnerClasses fixes this one by bringing back even more information in the class files.
Later, I got java.lang.NoSuchFieldException: ctl; that's what -keepnames is for. This way, the field is still called ctl like Netty expects.
Finally, some members (like ctl, seen earlier) were being removed by Proguard because Netty only uses them via reflection. The final rule, -keepclasseswithmembers, makes sure Proguard doesn't remove them.
If you take this approach, I strongly recommend you use only the Netty jars you need, instead of the -all jar. Switching from -all to just the required Netty jars brought my method count way down after I had gone past the 65k limit. Reducing your jars requires bit of trial-and-error though as the separation is unclear and there's not really any resources saying what's what.
* not carefully at all, I just slapped rules into the file and removed them if they did nothing. There's probably a better way to do this that doesn't keep this information in the entire program, but instead just Netty.
Una's answer keep too many classes, which makes my app 1MB larger than usual. So I use the rules below:
# netty
-keepclassmembernames class io.netty.buffer.AbstractByteBufAllocator {
*;
}
-keepclassmembernames class io.netty.buffer.AdvancedLeakAwareByteBuf {
*;
}
-keep public class io.netty.util.ReferenceCountUtil {
*;
}

Is there any way to obfuscate just real code, and not ofuscate Libraries?

I'm having some issues while obfuscating code with ProGuard. Basically GSON library is giving me a pain.
So I thought about obfuscating just com.mypackages.* and do not obfuscate used libraries.
Is it possible?
How is this called? I'm kinda lost at obfuscation atm, and I couldn't find any examples about that.
Any tips are soo appreciated.
Edit:
java.lang.AssertionError
at com.google.gson.internal.bind.TypeAdapters$EnumTypeAdapter.<init>(Unknown Source)
at com.google.gson.internal.bind.TypeAdapters$26.create(Unknown Source)
at com.google.gson.Gson.getAdapter(Unknown Source)
After adding
-keepnames class com.google.gson.** {*;}
Edit2:
I kept trying new things like:
-keep class com.google.**
-keepnames class com.google.** {*;}
-keepnames enum com.google.** {*;}
-keepnames interface com.google.** {*;}
And no luck so far.
The simplest way I can think of to keep the GSON library from being obfuscated is to add something like this to your ProGuard config:
-keepnames com.google.gson.** {*;}
With -keepnames, ProGuard's obfuscation step preserves the names of the specified classes, fields, and methods. ProGuard's shrinking step and optimization step may still remove the classes, fields, and methods themselves, if they appear unused. You want to use the more common -keep option:
-keep class com.google.gson.** { *; }
This line keeps the matching classes, fields, and methods, with their original names. It also matches interface classes and enum classes.
See the ProGuard manual > Usage > Overview of Keep Options
I too spent time struggling with this. In my case, it was not on the Gson side of things, but the enum that it was trying to deserialize (MyClass.MyEnum in this case). I used this:
-keep class com.google.gson.** { *; }
-keep enum com.abc.MyClass$MyEnum { *; }
Adding the second line above caused my code to make it past the problem and the application was functional again. Hope this helps!

Enable Proguard for only two packages in large Android application

Background
I am developing an Android application that relies on multiple external libraries (8 added as library project dependencies, 14 added as jar dependencies).
Some of these jar libraries are closed source an have already been obfuscated and some of them rely pretty heavily on reflection.
The application uses ZXing for QR code scanning/recognition and, without Proguard optimization, ZXing is quite slow (at least on Android).
At first, I only needed to optimize the com.google.zxing.** package using Proguard. In order to do that I've added the following Proguard options in my config file (the best I could figure out from this question):
-keep class !com.google.zxing.** { *; }
-keep interface !com.google.zxing.** { *; }
-keep enum !com.google.zxing.** { *; }
-dontwarn !com.google.zxing.**
I exported my application and it works like a charm.
Problem
Now, I want to use Proguard to obfuscate the application's classes.
I've tried changing the above to:
-keep class !(com.google.zxing.**, com.example.app.**) { *; }
-keep interface !(com.google.zxing.**, com.example.app.**) { *; }
-keep enum !(com.google.zxing.**, com.example.app.**) { *; }
-dontwarn !(com.google.zxing.**, com.example.app.**)
-keep com.example.app.activities.** { *; }
-keep com.example.app.receivers.** { *; }
-keep com.example.app.services.** { *; }
-keep com.example.app.views.** { *; }
The problem is that Proguard does not accept !(package.one.**, second.package.**) { *; } as a valid option for a -keep rule.
Another approach would be to put a -keep rule for every package in my application.
This approach has two big disadvantages:
adding or swapping libraries would require changing the Proguard config file
it makes updating libraries a pain, as some of them are obfuscated and, when recompiled by the library's developer, will change package names.
Obviously, I would like to avoid this approach as much as possible (because of the high number of external libraries).
Question
Is it possible to use Proguard to obfuscate just two packages, without defining a -keep rule for each of the other packages in my app? If so, how can I do this?
The correct syntax is a comma-separated list without any parentheses:
-keep class !com.google.zxing.**,!com.example.app.** { *; }
See the ProGuard manual > Usage > Filters.
Note that this single line already implies the two other lines for interfaces and enums. You can imply the -keep options for all subpackages by not letting the last wildcard match subpackages:
-keep class !com.google.zxing.**,!com.example.app.* { *; }

Categories

Resources