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))).
Related
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.
I am optimizing my proguard configuration and I am still keeping some class names that are not compulsory.
After intensive reflection I finally find why.
My class implements Parcelable and I use some libraries which use this proguard configuration:
# Needed for Parcelable/SafeParcelable Creators to not get stripped
-keepnames class * implements android.os.Parcelable {
public static final ** CREATOR;
}
which seems to be keep the names of the class and the CREATOR field.
I think that just the CREATOR field is really required as it is possible to read in the official proguard-android-optimize.txt proguard file:
-keepclassmembers class * implements android.os.Parcelable {
public static final ** CREATOR;
}
As I am not the owner of the library, I cannot change it. Is there a way to override their proguard configuration file ? (which may be included with the consumerProguardFiles gradle keyword)
Thanks for the answers.
I finally came to a solution concerning proguard-android-optimize.txt.
In AndroidStudio, you have access to proguard-android-optimize.txt (⌘↑O on mac, or control + shift + N for windows/linux). Just copy the file content, and paste it to your project without the rules you want to remove. Finally use it as your own proguardFiles.
replace
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
with
proguardFiles 'proguard-android-optimize.txt', 'proguard-rules.pro'
Be aware that it is at your own risk and that you won't have the optimization from the latest embedded proguard files.
Concerning the consumerProguardFiles you have no choice to do pull request to them if you can, or ask for an evolve if you can contact the library author.
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.
I've met several proguard examples with these lines:
# Keep the BuildConfig
-keep class com.example.BuildConfig { *; }
I've run app with and without this line (of course, with my package) and haven't found any differences.
I've also looked in generated/.../BuildConfig.java and there are no changes too.
What for do I need to keep my BuildConfig in ProGuard?
Thanks!
BuildConfig contains a number of useful values that are set at compile time. Specifically these:
boolean DEBUG – if the build is debuggable.
int VERSION_CODE
String VERSION_NAME
String APPLICATION_ID
String BUILD_TYPE – name of the build type, e.g. "release"
String FLAVOR – name of the flavor, e.g. "paidapp"
You can also set your own config values, e.g. different urls for testing and production, and retrieve them from the BuildConfig file instead of maintaining your own Config.java file. This can be done by adding buildConfigFields to your gradle buildTypes like so:
buildTypes {
debug {
buildConfigField "boolean", "SOME_VAR", "true"
}
release {
buildConfigField "boolean", "SOME_VAR", "false"
}
}
So to answer your question, as far as I know you don't have to keep the file, but it's good practice to do so and to use it for your config needs.
As with any other class, you need to -keep the class if you're accessing it indirectly via reflection so ProGuard won't obfuscate it or optimize it away as unused.
Most often the access patterns with BuildConfig are direct without reflection so in those cases it's fine to have ProGuard process your BuildConfig, too.
Some crash reporter libraries like ACRA does access BuildConfig via reflection, so if you use one and want to have info from it in your crash reports, you should -keep it.
I am using the latest Android SDK (4.1) and I tried exporting a signed jar with Proguard enabled. However, after decompiling the optimized APK, I noticed that methods that I would have expected to be inlined were not.
I know that Proguard ran because the code was correctly obfuscated. So to confirm this, I added this method to my Activity:
private void testInlining()
{
mConfig = null;
}
This private method is called only once in my activity, and because it is private, it should be very obvious to the optimizer that it is called only once and that it should be inlined.
The documentation says that all optimizations are enabled by default, and that Proguard "Inline methods that are short or only called once".
Is there a specific flag I should give to Proguard to enable inlining?
EDIT
My proguard configuration file contains
-optimizationpasses 5
-allowaccessmodification
-overloadaggressively
-repackageclasses ''
-dontskipnonpubliclibraryclasses
EDIT
After using
-whyareyoukeeping class com.templatecompany.templateappname.EntryPointActivity {*;}
I get the reason why the method is not inlined:
[proguard] com.templatecompany.templateappname.EntryPointActivity: void testInlining() (20:21)
[proguard] is invoked by com.templatecompany.templateappname.EntryPointActivity: com.td.media.ivConnection.IvConfig getIvConfig() (14:15)
[proguard] implements com.td.widget.MainActivity: com.td.media.ivConnection.IvConfig getIvConfig()
[proguard] is invoked by com.td.widget.MainActivity: void onCreate(android.os.Bundle) (140:175)
[proguard] implements android.app.Activity: void onCreate(android.os.Bundle)
[proguard] is a library method.
But I am not sure to see how the fact that the method testInlining is used in the method getIvConfig which is in turn used by another method prevents the inlining on testInlining in getIvConfig.
This recent Android SDK disables all optimizations by default, see ${sdk.dir}/tools/proguard/proguard-android.txt:
-dontoptimize
The alternative optimizing configuration only disables a few optimizations, see ${sdk.dir}/tools/proguard/proguard-android-optimize.txt:
-optimizations !code/simplification/arithmetic,!code/simplification/cast,!field/*,!class/merging/*
You can specify your preferred configuration file in project.properties.
You can verify which complete configuration ProGuard is using by adding the option -printconfiguration.
Some optimizations have been disabled in order to avoid bugs in older versions of the Dalvik VM (!code/simplification/arithmetic,!code/simplification/cast), and some optimizations may have been disabled to avoid bugs in older versions of ProGuard (!field/*,!class/merging/*).
Note that -whyareyoukeeping refers to the shrinking step, which removes unnecessary classes/fields/methods as a whole. Methods that are not removed may be inlined in the optimization step (unless explicitly specified otherwise with -keep).
In your module's build.gradle file, you should look at:
buildTypes {
release {
minifyEnabled true
shrinkResources true
proguardFiles getDefaultProguardFile('proguard-android.txt'), file('proguard-project.txt')
signingConfig signingConfigs.release
}
}
and replace proguard-android.txt with proguard-android-optimize.txt, which doesn't include the -dontoptimize line while keeping the dalvik problems away (see Eric Lafortune's answer).