In my app's example, the debug apk is 20Mbs (from 13Mbs, after upgrading the Gradle version and Gradle Plugin version), and the release apk is just 5Mb. Why is that?
In the build.gradle file, the buildTypes part has remained unchanged, so there hasn't been any optimizations / shrinking from the R8 compiler or from ProGuard.
android {
...
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
RELEASE:
DEBUG:
You can see the big difference in size in the lib folder, among others.
There are more optimizations happen during the release builds besides ProGuard and R8. According to the documentation https://developer.android.com/studio/build/shrink-code.html
When you build you project using Android Gradle plugin 3.4.0 or higher, the plugin no longer uses ProGuard to perform compile-time code optimization. Instead, the plugin works with the R8 compiler to handle the following compile-time tasks:
Code shrinking (or tree-shaking): detects and safely removes unused classes, fields, methods, and attributes from your app and its library dependencies (making it a valuable tool for working around the 64k reference limit). For example, if you use only a few APIs of a library dependency, shrinking can identify library code that your app is not using and remove only that code from your app. To learn more, go to the section about how to shrink your code.
Resource shrinking: removes unused resources from your packaged app, including unused resources in your app’s library dependencies. It works in conjunction with code shrinking such that once unused code has been removed, any resources no longer referenced can be safely removed as well. To learn more, go to the section about how to shrink your resources.
Obfuscation: shortens the name of classes and members, which results in reduced DEX file sizes. To learn more, go to the section about how to obfuscate your code.
Optimization: inspects and rewrites your code to further reduce the size of your app’s DEX files. For example, if R8 detects that the else {} branch for a given if/else statement is never taken, R8 removes the code for the else {} branch. To learn more, go to the section about code optimization.
Related
I'm creating an app for android and ios, and i already know that it's theoretically possible to decompile an android app. The app contains sensitive information that i don't want users to have access to as the app interfaces with a webserver. If a user gained access to some information available in the source code, they could potentially spam my web server with requests.
Is there any way to authenticate a connection between the app and the server, assuming that the source code is accessible, or is there any way to obfuscate my code to prevent a malicious user from spamming my webserver.
Thankss
[UPDATE]
**
When you build your application using Android gradle plugin version > 3.4.0, the plugin chooses R8 to optimize and obfuscate the code. The rules can now be configured on proguard-rules.pro or proguard-app.conf files. the rules to indicate what to exclude from the obfuscation are similar to the ones in proguard.cfg used earlier.
You can import your proguard files in your build.gradle like
buildTypes{
...
release{
proguardFiles getDefaultProguardFile(
'proguard-android-optimize.txt'),
'proguard-rules.pro'
}
}
R8 picks up all the existing proguard rules files as long as they're included in the build.gradle. You can also configure what pieces to obfuscate for different product flavors that you may have.
**
[OLD BUT RELEVANT INFO]
Proguard is a tool that will help you obfusate your code. This comes as part of your android tools and you just need to activate it. This link and this will help further.
Proguard's default configuration (in proguard.cfg) will be enough to sufficiently obfuscate your code. However you might want to tweak your proguard configuration when you have methods/classes that are being dynamically accessed.
For instance, accessing classes/methods with Reflection will need you to have the code to be intact. You might sometimes experience ClassNotFoundException if proguard obfuscates it.
If you have classes that are being accessed in the AndroidManifest/ Layout Files, you should prevent proguard from obfuscating them.
This can be done by adding
-keep public class <MyPackage.MyClass>
to your proguard.cfg.
**
While Proguard makes static analysis harder, DexGuard protects from both static and dynamic analysis. DexGuard is specifially for android applications and is only commercially available while Proguard is open source and is for any java bytecode obfuscation / optimization.
You cannot prevent decompiling android apk, you can just increase the difficulty of decompilation, proguard is the best option.
DexGuard provides even better security then ProGuard but it is NOT free: https://www.saikoa.com/dexguard
DexGuard can even obfuscate String constants.
I've been doing Android development for a little bit and I'm getting to a point in one of my projects where I would like to use Proguard to shrink the size of my APk and help with the dex limit. Unfortunately, I am getting a few errors and stack overflow has answers but they seem to be targeted for those with more experience.
My question is what is the relationship with your proguard-android.txt and proguard-rules.pro? Why are there two separate files and why are they in separate formats? When are the statements in these files called and in what order? I am just looking for an explanation of the overall context of using Progurad in a development environment.
Thank you in advance.
ProGuard manipulates Java bytecode the way you tell it with your configuration files and the rules they contain. ProGuard can do many things. And it can completely break your app so you have to make sure to add the correct rules.
I assume you use Gradle based builds for your apps. Then you've probably encountered this snippet that enables ProGuard for release builds of your app (or Android library):
android {
buildTypes {
release {
minifyEnabled true
proguardFiles getDefaultProguardFile(‘proguard-android.txt'),
'proguard-rules.pro'
}
}
...
}
In the config the list proguardFiles tells the build what files that contain ProGuard rules it has to use. This list can contain any number of files.
Why are the files (proguard-android.txt and proguard-rules.pro) defined differently?
The magical getDefaultProguardFile(‘proguard-android.txt') loads file named proguard-android.txt from the standard location in the Android SDK (the location is ${ANDROID_SDK}/tools/proguard/).
Other config files are resolved locally, so file proguard-rules.pro is expected to be at the root of the current Gradle module.
Why are there two separate files? And what is the relationship between proguard-android.txt and proguard-rules.pro?
ProGuard configuration is additive. You can define some rules in one file and other in other files. The rules are internally concatenated into single list of rules.
File getDefaultProguardFile(‘proguard-android.txt') contains several general rules for all Android apps (check them yourself, in the file in your SDK). The local proguard-rules.pro is expected to contain rules specific for your own app. For example you want to make sure that a class is not stripped away when you use it only through reflection (I'll get to that later).
Note that having multiple local files is very useful. For example you can use two local config files for debug builds - one with the release rules for your app and the second containing rules disabling obfuscation.
Also note that the additive behaviour of the configurations can be a bit troubling. If you add a rule in one config file, you cannot remove it in another. So be careful with very general rules (e.g. imagine adding -keep class ** { *; }).
When are the statements in these files called and in what order?
You can define them in any order, there's no difference. And you can define the same rule in multiple files, it doesn't matter. The order of the specified files doesn't matter either.
ProGuard itself is run as a single job within the Android build (single Gradle task to be precise). The task is provided all the inputs:
classes to manipulate
library classes to use but not manipulate
output path for generated processed jar
ProGuard rules specifying the manipulation
output paths for various output information (what was removed, mapping, …)
And then it processes the files and generates an output which is further processed by the Gradle build.
How does ProGuard actually work? And why do I need the rules?
ProGuard traverses the whole call graph of classes/methods/fields/…. It starts with the classes/methods/… defined by the provided rules. Then traverses the call graph and marks classes/methods/fields/… as necessary and keeps them for the output. So if you call it with no matching keep rules it will generate an empty output (or maybe it will throw an error and tell you to define some, I don't remember now). ProGuard doesn't recognize calls done via reflection, so you have to add some rules to handle that. There are many other cases that require you to add some rules, check the documentation for that.
Final notes
If you check ProGuard documentation you can find various rules
you can use. But not all of the rules are good for Android (ProGuard is a general Java tool).
Some rules are generated by Android build itself, you don't have to define them yourself. There are 2 types of such rules:
General config rules like -injars, -libraryjars, …
Rules generated from AndroidManifest.xml and resources (layouts). Android build (aapt tool) generates rules to keep classes mentioned in the manifest (activities, services, receivers, …) and custom views used in layouts. You can check these generated rules in build/intermediates/proguard-rules/${PRODUCT_FLAVOR}/${BUILD_TYPE}/aapt_rules.txt
Some rules can come from aar libraries. The libraries can contain ProGuard config necessary for the library to work (there can be proguard.txt file inside).
When writing Android libraries yourself be extremely careful with the rules you want to add to the aar. Because of the additive nature of the rules, it can cause problems for the app that bundles the library.
I am using Android Studio version v2.1.2 and Proguard doesn't work when I try to sign the release build, the build fails dramatically.
According to this link from developer docs Jack does obfuscation automatically.
Handles shrinking, obfuscation, repackaging and multidex Using a
separate package such as ProGuard is no longer necessary.
I had to disable minifyEnabled flag and remove the line where we load proguard file; to get it working, after doing this; I inspected the apk file generated by doing the above and I cannot tell whether Jack really obfuscated and reduced redundant code as the release apk size is same as the debug apk size.
I need to understand how to make obfuscation work with the newer compiler as the documentation doesn't really help.
I am looking forward to understand the following questions.
Does Jack work without Proguard file?
Is there a way to specify Proguard file?
The Jack compiler has its own Shrinker and Obfuscator that re-uses existing Proguard rules (see supported directives).
The configuration should be the same as before, so you need to add the following to your buildType configuration:
minifyEnabled true
proguardFile getDefaultProguardFile('proguard-android.txt')
proguardFile 'your-proguard-file.txt'
I've got problem with very simple application. APK size is now 3 MB, but it contains a lot of useless for me files (I think that source of this files is Support Library). In my application I don't use any images, but all drawable directories contains a lot of icons, buttons, etc. Is it possible to delete this images by any rule in gradle or other method? I use Android Studio.
Already I added to build.gradle information about languages to include in APK. I had in Hello World 80 languages before it.
Screen of files:
The Gradle build system for Android supports "resource shrinking": the automatic removal of resources that are unused, at build time, in the packaged app. In addition to removing resources in your project that are not actually needed at runtime, this also removes resources from libraries you are depending on if they are not actually needed by your application.
To enable this add the line shrinkResources true in your gradle file.
android {
...
buildTypes {
release {
shrinkResources true
}
}
}
Check the official documentation here,
http://tools.android.com/tech-docs/new-build-system/resource-shrinking
I have never used Android Studio before. The size of a simple "Hello world" app generated by default is almost 800k, while it is less than 100k in eclipse. I find that there are too many pictures in the drawable files, they seem come from res/all under the build folder, they still exist even if I delete the folder res manually.
My question is how to shrink the apk size in this situation?
The difference is due to the appcompat library which is compiled in by default to New Project Wizard-generated projects in Android Studio if you target an API level lower than 14. When I ran a test, the size increase was 642k for a debug APK, and 411k for a release APK (with Proguard enabled -- that will strip out unused code but not unused resources).
There's not a lot you can really do about this, short of removing the appcompat library if you're not using any of its features (though you should probably be using its features).
I haven't used Android Studio yet (my understanding is that it's still beta), but, I know that with other IDEs, the size of the resulting executable will change based on if it's a Debug or Release version. Eclipse lets you specify one or the other. Does Android Studio do the same?
Try to use "shrinkResources" in (build.gradle app)
buildTypes {
release {
minifyEnabled true
shrinkResources true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
https://developer.android.com/topic/performance/reduce-apk-size