Replacing ProGuard keep-rule with #Keep annotation obfuscates members names - android

Using ProGuard to keep an entry point in a library, and also not allow it to be obfuscated, I use the proguard keep rule:
-keep,includedescriptorclasses public class com.demo.api.** { *; }
I would like to replace this rule with a #Keep annotation like this:
#Keep
public class SomeClass {
public void someMethod() { /*..*/ }
}
If I analyze the aar library containing this class, the SomeClass was kept (not shrunk) and not obfuscated along with method someMethod, as expected.
If I build an app using this library, however, the class SomeClass is kept, but its members are still obfuscated. The app only has the default rules
and an empty local proguard_rules.txt:
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
How can I get the #Keep annotation behave in a similar way as the ProGuard -keep rule?

The #keep annotation is added to the class and it will not automatically inherit the keep behavior to all its methods. All the Keep annotation does is ensure the class is not minified (removed) and not obfuscated. So to ensure the methods are not obfuscated or minified the #Keep annotation has to be added to all the methods you want retained as well.

Related

Relase aar doesn't contain any code android?

I am using android studio bumble bee
I created a module library which has a single class
class Lib2 {
fun print(){
println("From lib2")
}
}
The proguard as
-keepclasseswithmembers class com.example.lib2.Lib2{
public <methods>;
public <fields>;
}
I create the release aar with minifyEnabled true
However when I integrate the aar with my app module I am not getting Lib2. What is wrong here?
From documentation:
Specifies classes and class members to be preserved, on the condition that all of the specified class members are present. For example, you may want to keep all applications that have a main method, without having to list them explicitly.
In English it means "Don't obfuscate classes that have the following methods and fields structure".
For example, keeping all classes which have constructors with single Context parameter:
-keepclasseswithmembers class * {
public <init>(android.content.Context);
}
Since, from my understanding, you simply want to keep the whole class, you can use:
-keep public class com.example.lib2.Lib2
In my opinion, it's better to use #Keep annnotation directly in the class, because:
The proguard rules is decoupled from source and as the time flies we forget that the rule is there. by using #Keep you know immediately what classes are being kept from obfuscation and it's much more readable.
This annotation is packed with your AAR so when you publish it, consumer apps won't obfuscate it as well. With proguard rules you must add another rules file to pack with your AAR that "tells" the consumer app to not obfuscate this class.
Much more simple:
#Keep
class Lib2 {
fun print(){
println("From lib2")
}
}

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 warning: the configuration keeps the entry point....but not the descriptor class

I've configured:
-keep ,allowoptimization,allowobfuscation,allowshrinking public class org.jf.dexlib2.dexbacked.** {
*;
}
but still getting the warning:
Note: the configuration keeps the entry point 'com.trusteer.trf.dex_parser { int get_strings_count(org.jf.dexlib2.dexbacked.DexBackedDexFile); }', but not the descriptor class 'org.jf.dexlib2.dexbacked.DexBackedDexFile'
I am using proguard version 4.7 (in Android SDK)
What should I do?
You have told Proguard to keep a certain method void foo(Bar bar); but to obfuscate the descriptor class Bar.
This is only a problem if you are going to invoke the method from an external source as the signature will be changed by the obfuscation (if you use Proguard to obfuscate a library and then use that library in another app).
So have the following choices:
Configure Proguard to also keep Bar.
Use the -dontnote directive to tell Proguard not to print notes like this.
Note: the configuration keeps the entry point '...', but not the descriptor class '...'
Your configuration contains a -keep option to preserve the given method (or field), but no -keep option for the given class that is an argument type or return type in the method's descriptor. You may then want to keep the class too. Otherwise, ProGuard will obfuscate its name, thus changing the method's signature. The method might then become unfindable as an entry point, e.g. if it is part of a public API. You can automatically keep such descriptor classes with the -keep option modifier includedescriptorclasses (-keep,includedescriptorclasses ...). You can switch off these notes by specifying the -dontnote option.
Add this line in your 'proguard-rules.pro' file to fix this problem .
-ignorewarnings
From the docuemnts:
allowshrinking Specifies that the entry points specified in the -keep
option may be shrunk, even if they have to be preserved otherwise.
That is, the entry points may be removed in the shrinking step, but if
they are necessary after all, they may not be optimized or obfuscated
So it appears that you need to remove the allowshrinking modifier.
In my case this problem appears when I add to build.gradle
minifyEnable true
Official instructions: https://flutter.dev/docs/deployment/android
Bug https://github.com/flutter/flutter/issues/19250
Sample proguard-rules.pro file:
#Flutter Wrapper
-ignorewarnings
-keep class io.flutter.app.** { *; }
-keep class io.flutter.plugin.** { *; }
-keep class io.flutter.util.** { *; }
-keep class io.flutter.view.** { *; }
-keep class io.flutter.** { *; }
-keep class io.flutter.plugins.** { *; }
I did some digging in the docs. You have not supplied your whole configuration file, but I'm guessing that that com.trusteer.trf.dex_parser is set to both keep and not to obfuscate.
This means that there is a refrence from com.trusteer.trf.dex_parser to a class called org.jf.dexlib2.dexbacked.DexBackedDexFile that was either shrunk or obfuscated. This means that the link is now broken - dex_parser can't import DexBackedDexFile.
So either disable shrinking and obfuscation for DexBackedDexFile, or allow optimization and obfuscation on dex_parser.

Exclude a method to Proguard obfuscation

Proguard obfuscation renames the methods and classes of my android source after the exportation, I need that a specific method in a specific class mantain is name also after the build with proguard.
How could I perform this?
For example:
assuming that I want to preserve the name of the method myMethod in the class MyClass of package my.package.android.com How should I write the -keep modifier?
You should create ProGuard config file using -keep option with specified class name you want to be ommited during obfuscating.
See ProGuard docs: http://proguard.sourceforge.net/index.html#manual/usage.html
-keep [,modifier,...] class_specification
Specifies classes and class members (fields and methods) to be preserved as entry points to your code.

Dagger cannot create object graph although it can produce dot file

I'm struggling with the setup of Dagger (1.0.1), in a existing application. It was configured to use ProGuard but I disabled it for this test with -dontobfuscate.
When I enable dagger-compiler it's able to successfully generate a dot file with the dependencies graph, but when I remove the compiler and build the app in Release mode it crashes during startup, complaining that it's unable to create the object graph.
java.lang.RuntimeException: Unable to start activity
ComponentInfo{com.corp.myapp/com.corp.myapp.ui.activity.MainActivity}:
java.lang.IllegalStateException: Errors creating object graph:
No injectable members on com.corp.myapp.core.services.ConnectionMonitor. Do
you want to add an injectable constructor? required by
com.corp.myapp.core.services.ConnectionMonitor
com.corp.myapp.ui.activity.MyAppBaseActivity.connectionManager
No injectable members on com.corp.myapp.ui.crouton.CroutonManager. Do you want
to add an injectable constructor? required by
com.corp.myapp.ui.crouton.CroutonManager
com.corp.myapp.ui.activity.MyAppBaseActivity.croutonManager
No injectable members on com.corp.core.assembler.ResourceAssembler. Do you want
to add an injectable constructor? required by
com.corp.core.assembler.ResourceAssembler
com.corp.myapp.ui.activity.MyAppBaseActivity.resourceAssembler
I see MyAppBaseActivity and it's dependencies with CroutonManager or ConnectionMonitor being displayed in the generated dot file, so according to this comment I expected this to work. AFAIK if there was something wrong it should be detected by the compiler-enabled build that I used to generate the dot file.
UPDATE:
I previously stated that
In Debug mode it never fails
but it's not really true after further testing: In Debug mode it doesn't fail because ProGuard is disabled, whereas in Release mode it is enabled by default. If I build the app in Release mode but skip ProGuard, I don't get the errors either and the app successfully starts. So the problem is definitely related to my ProGuard configuration.
Dagger relies a lot on reflection and class names that are hard-coded and manipulated as strings. This makes the code difficult to shrink/optimize/obfuscate.
The following configuration works for the sample dagger/examples/simple in Dagger 1.1.0:
-keepattributes *Annotation*
-keepclassmembers,allowobfuscation class * {
#javax.inject.* *;
#dagger.* *;
<init>();
}
-keep class **$$ModuleAdapter
-keep class **$$InjectAdapter
-keep class **$$StaticInjection
-keepnames !abstract class coffee.*
-keepnames class dagger.Lazy
The configuration keeps all fields and methods with javax.inject or dagger annotations, and all parameterless constructors. ProGuard might otherwise remove them if they appear unused, but Dagger is actually injecting/accessing them through reflection. This is similar to RoboGuice.
It also has to keep all adapter classes generated by Dagger.
It also has to keep all class names related to these adapter classes, so the names still match. In this sample, those are almost all classes in the package coffee, so the easiest way is to use a wild-card. This line will be different for other applications.
Finally, it also has to keep the name of the class dagger.Lazy, since its name is hard-coded as a string in the generated code.
I got the app to start after adding -dontshrink to the ProGuard config file. Having -dontobfuscate at the beginning was not enough.
In fact, if I remove -dontobfuscate it also works.
I definitely need finer control for this but it's a starting point. My current ProGuard setup for Dagger is:
#############
# Dagger #
#############
-keep class dagger.** { *; }
-dontwarn dagger.internal.codegen.**
Dagger doesn't require #Inject to be on a class to be passed into graph.inject(myActivity) because some activities may not have any injections to make. However, these seem like upstream dependencies, which means that they need to be provided to ComponentInfo, and therefore need to be provisioned by Dagger. It cannot do this if it cannot create these classes, and it can't do so if these are not annotated, unless it provides them via a #Provides method.
So, you either need to create an #Module-annotated class which returns these types from #Provides-annotated methods, or you need to add #Inject to their constructor.
-keep class * extends dagger.internal.Binding
That said, in this case, are you using proguard in "release" mode? And not proguarding in debug mode? If so, I suspect Proguard to be stripping away annotations. You'll need to do some variant of:
-keep class javax.inject.** { *; }
... to ensure that Proguard doesn't remove the annotations.
I ended up burning a week+ trying to get this to work. In the end I failed and decided to give DexGuard a shot. It worked beautifully right out of the box. Yes its a commercial product but DexGuard has great support and because of such we were able to finally ship. Id definitely recommend DexGuard if you absolutely need to solve this issue.

Categories

Resources