Proguard (R8) obfuscate custom view names - android

I am using R8 in my app and have several custom views (which are referenced in xml layouts) tho their names are not obfuscated at all. Is there any way to achieve this? I am using the standard Gradle rules:
release {
minifyEnabled true
shrinkResources true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
And also tried with android.enableR8.fullMode=true but it's the same.

I am using R8 in my app and have several custom views (which are referenced in xml layouts) tho their names are not obfuscated at all.
This is because the proguard-android-optimize.txt has the following rule:
# keep setters in Views so that animations can still work.
-keepclassmembers public class * extends android.view.View {
void set*(***);
*** get*();
}
So your custom views, or any views, will not have their names obfuscated by default.
Now the question is can you still have R8 rename the custom views in your app? And the answer is not really.
You could add an -applymapping myCustomMapping.txt by copying the contents of
<root_dir>/app/build/outputs/mapping/<build_variant>/mapping.txt and replacing all references to your custom views that are NOT obfuscated with obfuscated names.
Like this:
Copy contents of <root_dir>/app/build/outputs/mapping/<build_variant>/mapping.txt into a new file <root_dir>/app/myCustomMapping.txt
Before changing anything, it will look like this:
my.app.package.CustomView -> my.app.package.CustomView :
13:34:void <init>(android.content.Context,android.util.AttributeSet,int) -> <init>
15:16:void <init>(android.content.Context,android.util.AttributeSet,int,int,kotlin.jvm.internal.DefaultConstructorMarker) -> <init>
43:46:void customMethod() -> c
You need to change only this line, that has the top level class mapping. Notice that it is unchanged because of the android proguard rules. Change it to whatever obfuscated name you want, like this:
my.app.package.CustomView -> my.app.package.youcantseemeatall :
13:34:void <init>(android.content.Context,android.util.AttributeSet,int) -> <init>
15:16:void <init>(android.content.Context,android.util.AttributeSet,int,int,kotlin.jvm.internal.DefaultConstructorMarker) -> <init>
43:46:void customMethod() -> c
Finally, add these lines to your proguard-rules.pro file
-applymapping myCustomMapping.txt
-printmapping mapping.txt
Those above steps will change your .class files to obfuscate CustomView to youcantseemeatall, BUT your resource files will still reference the original CustomView name and your app will crash at runtime.
Conclusion:
Unfortunately there really isn't a way to do what your asking with proguard or any tooling that comes with Android Studio. There may be a custom Gradle Plugin that changes all custom view names before the app is assembled, but I couldn't find one just googling it now.

Related

Android R8 obfuscation with flexJson duplicate key issue

While obfuscating the android app using R8 and minifyEnabled true in build.gradle it adds duplicate key like below in one of webservice response.
Response: {"key1":"value1", ......., "key1":"value1"} it adds "key1" multiple time and flexJson throws exception and crashes the app
Caused by: flexjson.JSONException: Duplicate key "key1"
at flexjson.JSONTokener.putOnce(JSONTokener.java:498)
at flexjson.JSONTokener.parseObject(JSONTokener.java:471)
at flexjson.JSONTokener.nextValue(JSONTokener.java:357)
at flexjson.JSONTokener.parseObject(JSONTokener.java:471)
at flexjson.JSONTokener.nextValue(JSONTokener.java:357)
at flexjson.JSONDeserializer.deserialize(JSONDeserializer.java:197)
Everything works fine without obfuscation(minifyEnabled false).
Gradle Plugin Version used: 3.4.2, Also flexJson is used by one of the library included in the project.
In general you should ensure that all fields which are used for generating JSON through reflection are covered by a keep rule. Otherwise the name in the JSON can change from build to build. Also R8 use the property that the JVM and Android runtimes allow fields of different types to have the same name, you can end up in the situation described here.
One option could be to annotate all classes which are serialized, and use a keep rule like this:
-keep class #MyAnnotation ** {
<fields>;
}
or if all these classes are in a separate package:
-keep class com.example.mypackage.serialized_classes.** {
<fields>;
}

R8 changes "protected" methods of abstract class to "public" without -allowaccessmodification flag

I have an issue with R8. In MyLib I have public abstract MyLibsClass in which I have protected methods. MyChildClass extends from MyLibsClass in MyApp and after R8's magic all protected methods (including protected abstract) in MyLibsClass are changed into public ones, and of course in MyChildClass I'm getting "attempting to assign weaker access privileges ('protected'); was 'public') issue as trying to override protected abstract methods.
Additional info
gradle-6.0.1
MyLib's build.gradle
release {
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'),'proguard-rules.pro'
}
proguard-rules.pro
-keep class com.example.mylib.*{
public protected *; }
-keep class com.example.mylib.*$*{
public protected *; }
Anyone had this kind of issue or know a way to fix this?
So based on discussion here ,
DON'T USE DEFAULT PROGUARD SETTINGS FOR LIBRARIES
as allowAccessModification is enabled in default proguard settings, which is located in Android SDK (\Android\Sdk\tools\proguard\proguard-android-optimize.txt) and my mistake was using this for my libraries.
Citation from proguard manual
you probably shouldn't use this option when processing code that is to
be used as a library, since classes and class members that weren't
designed to be public in the API may become public.
So if anyone has the same issue I will suggest to create your own base config file for proguard and copy past whole default configs without "allowAccessModification" into it.
Also if someone interested more, you can track this issue. Hopefully will get separate config file for libraries in near feature.
I faced the same problem, and thanks to #Hayk Nahapetyan's answer, I could resolve it.
Here is my solution with a little more detail.
In the library module's build.gradle, remove the default file from the buildTypes's release closure:
release {
minifyEnabled true
proguardFiles 'proguard-rules.pro'
}
R8 no longer uses the default file that is provided in the Android SDK. It generates one at build time, and puts it in the module's build directory at build/intermediates/default_proguard_files/global.
Copy the contents of proguard-android-optimize.txt-a.b.c (where a.b.c is the library version, if set) from that location to the top of the module's proguard-rules.pro. Then remove -allowaccessmodification; two times, if it originally appeared in both files.
This was also reported on the R8 bug tracker, and resolved there. See http://issuetracker.google.com/147447502.

How to obfuscate package name in android studio

I have successfully obfuscate class name and methods using following code
buildTypes {
release {
shrinkResources false
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
signingConfig signingConfigs.release
}
}
in app level build.gradle file
and
-dontwarn mypackage.**
-dontusemixedcaseclassnames
-dontskipnonpubliclibraryclasses
-verbose
-dontwarn
in proguard-rules.pro
but my problem is package name is not obfuscated.
So how can I achive it, please help.
Thanks
In Pro-Guard, package names can be obfuscated in various ways, with increasing levels of obfuscation and compactness. For example, consider the following classes:
mycompany.myapplication.MyMain
mycompany.myapplication.Foo
mycompany.myapplication.Bar
mycompany.myapplication.extra.FirstExtra
mycompany.myapplication.extra.SecondExtra
mycompany.util.FirstUtil mycompany.util.SecondUtil
Let's assume the class name mycompany.myapplication.MyMain is the main application class that is kept by the configuration.
All other class names except Main can be obfuscated.
By default, packages that contain classes that can't be renamed aren't renamed either, and the package hierarchy is preserved. This results in obfuscated class names like these:
mycompany.myapplication.MyMain
mycompany.myapplication.a
mycompany.myapplication.b
mycompany.myapplication.a.a
mycompany.myapplication.a.b
mycompany.a.a
mycompany.a.b
The -flattenpackagehierarchy option obfuscates the package names further, by flattening the package hierarchy of obfuscated packages:
-flattenpackagehierarchy 'myobfuscated'
Alternatively, the -repackageclasses option obfuscates the entire packaging, by combining obfuscated classes into a single package:
-repackageclasses 'myobfuscated'
The obfuscated class names then look as follows:
mycompany.myapplication.MyMain
mycompany.myapplication.a
mycompany.myapplication.b
myobfuscated.a
myobfuscated.b
myobfuscated.c
myobfuscated.d
Additionally specifying the -allowaccessmodification option allows access permissions of classes and class members to be broadened, opening up the opportunity to repackage all obfuscated classes:
-repackageclasses 'myobfuscated'
-allowaccessmodification
The obfuscated class names then look as follows:
mycompany.myapplication.MyMain
myobfuscated.a
myobfuscated.b
myobfuscated.c
myobfuscated.d
myobfuscated.e
myobfuscated.f
The specified target package can always be the root package. For instance:
-repackageclasses ''
-allowaccessmodification
The obfuscated class names are then the shortest possible names:
mycompany.myapplication.MyMain
a
b
c
d
e
f
Note that not all levels of obfuscation of package names may be acceptable for all code. Notably, you may have to take into account that your application may contain resource files that have to be adapted.
To obfuscate code
in Android studio just visit this post.
Or import your code into
NetBeans and use its build-in functional to compile, pre-verify, obfuscate and package the code))).

Android ProGuard how to hide/obfuscate source code of exported library

I'm developing Android library and I want to hide/obfuscate the source code implementation of the library.
The way the user project app will use the library is:
startActivity( new Intent(context, LibraryActivityName.class) );
So I need to keep just the name of entry point Activity inside the library project, That's all.
When I used the default ProGuard settings:
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
as well as the suggested example for library - Nothing happened, and by clicking on the Activity name inside the user app (when he imports it) - One can see the source code.
Thanks,
As you do not have a typical library, you should not include the typical library example.
First of all, you need to enable Proguard execution, change this line:
minifyEnabled true
Second, you do not want to keep all public classes, but only the activity:
-keep class LibraryActivityName { public protected <methods>; }
The remaining classes can be fully obfuscated if I understand your question correctly, so there should be no need for further configuration, unless you use reflection somewhere.
It would also be good if you repackage the obfuscated classes into an internal package or something using
-repackageclasses my.library.package.internal
which might also required
-allowaccessmodification
btw. ProGuard will not obfuscate the code itself, only the class / method names.

ProGuard configuration for AndroidPlot

Since building a release version of my app with ProGuard enabled, my plot style is reset to the default and I see many warnings in Logcat informing me of unsupported parameters:
Error inflating XML: Setter for field "[...]" does not exist.
I've pinpointed this to be coming from AndroidPlot's Configurator, but haven't found any official ProGuard configuration for this project.
The mechanism through which AndroidPlot sets the configuration parameters relies heavily on reflection, and in that light I've decided it's useless to try to obfuscate anything inside this library:
-keep class com.androidplot.** { *; }
In my case, I had been using proguard for debug builds and it worked fine. Then I ran a release build (which adds obfuscation to the proguard configuration) and that crashed when it tried to inflate XYPlot in a view.
Binary XML file line #12: Binary XML file line #12: Error inflating class com.androidplot.xy.XYPlot
To fix it, I just configured proguard to not obfuscate the names of any androidplot objects:
-keepnames class com.androidplot.**
That did not work for me yet. For troubleshooting I set the switches -dontshrink -dontoptimize -dontobfuscate in the first step (if that doesn't help, the reason is probably not to be found in ProGuard).
After that you can step by step exclude single groups of classes, e.g. "-keep, includedescriptorclasses, includecode class my.path.to.R*{*;}". In my case the resource classes created by Android Studio had to be "-keep'ed":
-keep, includedescriptorclasses, includecode class com.androidplot.** {*;}
-keepclassmembers class **.R$* {
public static <fields>;
}
see https://www.guardsquare.com/en/products/proguard/manual/examples
"We're keeping the static fields of referenced inner classes of auto-generated R classes, just in case your code is accessing those fields by introspection. Note that the compiler already inlines primitive fields, so ProGuard can generally remove all these classes entirely anyway (because the classes are not referenced and therefore not required)."

Categories

Resources