Android Progaurd rules package names regex - android

I need to add my Json Model data classes to progaurd rules.
But my model classes are located in several packages.
Eg., assume model classes are present in the following locations
com.app.user.model.User
com.app.user.model.Profile
com.app.music.model.Song
com.app.music.model.Playlist
com.app.social.model.Media
.
.
.
I need to exclude all of the model class files alone
all model class resembles a pattern com.app.*.model.**
Is there any way to exclude all these files in a single rule?

We can use the same pattern as I mentioned in the question.
-keep class com.app.*.model.** { *; }

Related

Kotlin - Firestore toObject method not working as intended

I am using Firestore for my Android project and I am using the following code to convert the fetched document to a custom data class
val userData = user.toObject(UserData::class.java)!!
Now this line works perfectly when no code obfuscation is happening, however, with obfuscation, this line does not fail but rather does not copy the user document data to the userData. so I think the issue might be with Firestore and code obfuscation.
Does anyone else have had this issue before?
toObject() method uses reflection to fill up your UserData model from the user document. Now that your UserData class is getting obfuscated, Firestore is not able to map the values in document to the model class.
To fix this, you need to disable code obfuscation for all the data models that you are using in Firebase.
The easiest fix is to add a #Keep annotation to your data class.
#Keep
data class UserData(...)
If you have a lot of such models, you can disable obuscation for an entire file or package by adding more rules to your proguard-rules.pro.
For example, this statement will keep all the classes intact inside model package while code shrinking and obfuscation:
-keep class com.example.app.data.models.** { *; }
Check out the documentation for more such rules.

Meaning of -if in Proguard

For the following Proguard rule(take Kotlin Serialization)
-if #kotlinx.serialization.Serializable class **
-keepclassmembers class <1> {
static <1>$Companion Companion;
}
Here what is the meaning of -if in context with the above rule? I tried looking into official proguard documentation but couldn't find easy to any info around that
I wrote those ProGuard rules. :) The pull request discussion about these changes may provide relevant background.
I understand your confusion, the ProGuard rules documentation is quite sparse.
-if class_specification
Specifies classes and class members that must be present to activate the subsequent keep option (-keep,
-keepclassmembers,...). The condition and the subsequent keep option can share wildcards and references to wildcards. For example, you can
keep classes on the condition that classes with related names exist in
your project, with frameworks like Dagger and Butterknife.
As written in the comments of the rules you copied this from:
# Keep `Companion` object fields of serializable classes.
# This avoids serializer lookup through `getDeclaredClasses` as done for named companion objects.
-if #kotlinx.serialization.Serializable class **
...
So, -if #kotlinx.serialization.Serializable class ** should be read as: for all classes which have the #Serializable annotation applied (i.e., "serializable classes"). The <1> in -keepmembers subsequently refers to the ** wildcard, i.e., the fully-qualified class name.

How to keep fragment names in Firebase Analytics with Proguard?

I am using default Firebase Analytics implementation described here:
https://firebase.google.com/docs/analytics/get-started?platform=android
But when I check results in Firebase, name of fragments are "g,d,e,b". How can I fix this without hardcoding fragment names?
To keep the fragment names when using ProGuards, you should use -keepnames.
Lets assume you have a fragment with class identifier
com.example.app.fragments.frag1
To exclude that frag, you should add
-keepnames com.example.app.fragments.frag1 {}
To exclude all fragments including those that are in subfolders, use
-keepnames com.example.app.fragments.** {}
-keepnames is short for -keep,allowshrinking. If you use -keep only, you lose all ProGuards optimizations.
If you want properties to maintain their name, use
-keepnames com.example.app.fragments.** {*;}
For more information, you can check this.
Based on answer from #Abkarino, I came up with follwing solution:
-keep class com.packagename.fragments** { *; }
Where "com.packagename.fragments" is path to root of all fragments in project.

How to keep method names in Android Proguard R8?

I'm developing an Android Library and I'd like to have this result for Proguard.
I want to keep all package names, which I'm using "-keeppackagenames" to achieve.
I want to keep all class names.
I want to keep method names and method argument names for all public methods.
Other than that, I'd like to obfuscate and shrink everything else, including but not limited to all of non-public methods and even the body of the public methods.
How can I achieve that result?
Thank you very much beforehand for your help!
R8 itself is distributes as a library which has been run through R8. For that library we want to achieve exactly what you ask to ensure that developers using the library will not by accident use any APIs which are not supposed to be public (this has nothing to do with protecting IP as the project is open source).
The rules can be found here and I will explain the rationale for them below.
We try to be indirect and use annotations, so the main rules are:
-keep #com.android.tools.r8.Keep class * { public *; }
-keep #com.android.tools.r8.KeepForSubclassing class * { public *; protected *; }
All API classes are then annotated with #Keep or #KeepForSubclassing.
Then a number of attrubutes are kept
-keepattributes SourceFile, LineNumberTable, InnerClasses, EnclosingMethod, Exceptions, Signature
SourceFile and LineNumberTable are kept to get retracable stack traces. The rest for javac compilation and IDE integration for library users.
Then
-keepparameternames
is there for IDE integration getting the names of arguments in the API, and
-keeppackagenames com.android.tools.r8
-repackageclasses com.android.tools.r8.internal
to move as many classes as possible into the internal name space so the renamed classes does not show up in IDE's.
There are a few additional rules in the file to handle cases not covered by the annotation based approach.

Android Data Binding: Wrong BR class generated for obfuscated AAR

I'd like to provide an obfuscated AAR library which makes use of Android data binding. When I use the library from a test app, everything works fine as long as the library isn't minified by ProGuard. However, after enabling ProGuard the test app doesn't compile any more since BR fields in the generated data binding classes can't be found.
Since I couldn't find any official documentation on this "specific" subject, I tried to understand the magic behind Android data binding. The mechanism seem to be like this (please correct me, if I'm wrong):
In order to use data binding within an AAR lib, the embedding app must enable data binding, too.
This is because the the layout resources that contain data binding instructions are included without modification in the AAR.
It's therefore the embedding app's responsibility to generate the corresponding data binding classes for the layouts in the lib. (That's why the lib's view model classes must not be obfuscated, BTW.)
The challenge for the Android data binding generator is to tell the package names apart from both library and embedding app: The BR class for the library must be generated in the library's package (e. g. com.example.lib.databinding), since this class is accessed from the library's view model classes. On the other hand, the BR class of the embedding app should normally be generated within the app's package (com.example.app.databinding).
And this is exactly where my problems begin. I don't know Android exactly rises to this challenge, I only know that in my case, it works with an unobfuscated lib, and it doesn't with an obfuscated one. When I look into the generated source of the embedding app, I see:
When using the unobfuscated lib, both the BR and all *Binding.java classes are generated within the library's package, and the app compiles.
When using the obfuscated lib, both the BR and all *Binding.java classes are generated within the apps's package. Even worse, the BR only contains constants for the model variable names in the XML resource, not for the properties in the view model classes. Consequently, the app doesn't compile.
I tried to set the package of the data binding classes explicitely to the lib's package in the XML declaration, but this doesn't solve the problem with the incomplete BR class.
I have no clue where these differences come from and I' already fearing that the only solution could be removing all my nice data binding stuff from the lib ... Does anybody made similar experiences and could give me a hint, please?
These are the ProGuard exceptions I've already added to my lib:
-keep public class **.BR { public *; }
-keep public class **.BR$* { public *; }
-keepclassmembers class **.BR$* {
public static <fields>;
}
-keepclassmembers class **.R$* {
public static <fields>;
}
-keep class android.databinding.** { *; }
-keep class * extends android.databinding.** { *; }
-keep class com.example.lib.databinding.** { *; }
I managed to make it run in the meantime, but the "solution" is so weird that I really don't want to take it over to a productive version ...
When comparing the AAR files of the obfuscated and unobfuscated lib, I noticed that the classes.jar of the unobfuscated one contained these three files:
/com/example/lib/com.example.lib-br.bin
/com/example/lib/com.example.lib-layoutinfo.bin
/com/example/lib/com.example.lib-setter_store.bin
These binary files contain some of my data binding class names and are apparently important for the code generation process. I just tried to copy these files into the corresponding place of my obfuscated AAR and ... it worked!!!
But this cannot be the final solution. At least it would be more reliable than coping if I can convince ProGuard to simply keep these non-class-files within the classes.jar. Any ideas how to do this?
Much more I would appreciate to get some information on the backgrounds of this mechanism and whether it is possible to avoid such ugly low-level operations for solving a problem that actually should be standard.
Thanks in advance for any answer!
Apparently Google has resolved the issue with Gradle plugin 2.3.0, see https://code.google.com/p/android/issues/detail?id=229684.

Categories

Resources