I am using Guava in a Android project. I am hitting the 65k method limit which fails the gradle build. I found that this could be resolved by using proguard. I run Proguard on release build and it works fine. I do not want to run proguard on debug build as it makes debugging hard. I was wondering if there is a way to resolve this? One option I am considering is to build a local guava.jar and defining that as a dependency instead of pulling it from maven central. Is there a better way to do this?
Latest Android build tools support MultiDex option. This allows to build apps with over 65k methods. Just follow the official guide.
Also you can enable automatic resource shrinking alongside with ProGuard:
android {
buildTypes {
release {
minifyEnabled true
shrinkResources true
}
}
}
According to the official doc of Guava, you can use the following:
-injars path/to/myapplication.jar
-injars lib/guava-r07.jar
-libraryjars lib/jsr305.jar
-outjars myapplication-dist.jar
-dontoptimize
-dontobfuscate
-dontwarn sun.misc.Unsafe
-dontwarn com.google.common.collect.MinMaxPriorityQueue
-keepclasseswithmembers public class * {
public static void main(java.lang.String[]);
}
This will keep your methods with the same name without obfuscating. Meaning that you can still debug properly with all the appropriate names written as is.
Related
I already made a Flutter app. The release apk is about 14MB. I searched methods to minify this and found this ons: https://flutter.io/android-release/#enabling-proguard
But my question is, how can I get to know all my used additional libraries for step 1? Are there any commands to know them or is it just all the dependencies that I added to the pubspec.yaml ?
How do I need to implement them in this file /android/app/proguard-rules.pro?
First, we will enable shrinking and obfuscation in the build file. Find build.gradle file which sits inside /android/app/ folder and add lines in bold
android {
...
buildTypes {
release {
signingConfig signingConfigs.debug
minifyEnabled true
useProguard true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
Next we will create a configuration which will preserve entire Flutter wrapper code. Create /android/app/proguard-rules.pro file and insert inside:
#Flutter Wrapper
-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.** { *; }
Note: Use signingConfigs.release instead signingConfigs.debug to build a apk or appbundle
I will leave this answer here as an addition for any poor soul that has to deal with this issue and encounters this thread.
As of December 2021 with the latest Android Sdk, Studio and Flutter versions, if you try to douseProguard true it will not work because it's obsolete.
Sadly, Gradle will not tell you this, instead, you will get an error like this:
A problem occurred evaluating project ':app'.
> No signature of method: build_7cqkbrda1q788z3b02yxbvrx9.android() is applicable for argument types: (build_7cqkbrda1q788z3b02yxbvrx9$_run_closure2) values: [build_7cqkbrda1q788z3b02yxbvrx9$_run_closure2#41108b15]
Which as you can see it is complete gibberish and not useful. The secret is to just not use useProguard at all. By default Flutter is setup to use R8 which handles minification now on Android.
Here is a so post about this for reference: Gradle : DSL element 'useProguard' is obsolete and will be removed soon
If you are using firebase, see Flutter build crashes using ProGuard with Firebase Auth
Next, you need to consider the dependencies in pubspec.yaml You can immediately ignore any pure Dart packages - you are just looking for plugins. Of these plugins, you are just interested in ones that make use of existing libraries. You will likely have added these to gradle. Those are the ones you need to protect from name shortening.
The simplest approach may just be to try it and see what package names pop up in the NoClassDefFoundError and keep iteratively adding them.
As Remi says, your gain will be minimal, so is it really worth the hassle. You should see some improvements in APK sizes over the coming releases.
From this reference:
https://github.com/codepath/android_guides/wiki/Building-your-own-Android-library
I have the following gradle file:
android {
compileSdkVersion 25
buildToolsVersion "26.0.2"
buildTypes {
release {
minifyEnabled true
consumerProguardFiles 'consumer-proguard-rules.pro'
}
}
}
And the following proguard file:
-dontobfuscate
-optimizations !code/allocation/variable
-keep public class * {
public protected *;
}
However all of my classes in the aar are missing when I run the 'assembleRelease' task to build my release aar file.
Any ideas?
You should set minifyEnabled to false (the default value) :
consumerProguardFiles is not used for immediate minification (i.e. when building the library itself). It it used when the consumer of the library (e.g. an application) is build.
Minifying the library before consumption is not recommended, because you can not know what parts will actually be used before the final build. Libraries usually don't do it. e.g. LeakCanary, ACRA, Butter Knife
in general, a library must keep the all the methods and method names, required to operate it; eg:
-verbose
# -libraryjars ../app/libs
# -dontpreverify
# -dontobfuscate
# -dontshrink
# -dontoptimize
# keep class BuildConfig
-keep public class **.BuildConfig { *; }
# keep class members of R
-keepclassmembers class **.R$* {public static <fields>;}
the answer to the question should probably be:
# keep all public and protected method names,
# which could be used by Java reflection.
-keepclassmembernames class * {
public protected <methods>;
}
there are most likely some more rules required, while the -verbose flag tells one what to write into there. when building the library against other code (as suggested above), one nevertheless needs to add more or less the same rules for the library. there are also quite some, not open source, libraries with obfuscated class names.
a library's build.gradle might look about like this:
android {
defaultConfig {
consumerProguardFiles 'proguard-consumer-rules.pro'
}
buildTypes {
release {
minifyEnabled false // don't proguard the library itself.
}
}
}
the default proguard-consumer-rules.pro explains it:
The Android Gradle plugin allows to define ProGuard rules which get embedded in the AAR.
These ProGuard rules are automatically applied when a consumer app sets minifyEnabled to true.
The custom rule file must be defined using the 'consumerProguardFiles' property in your build.gradle file.
When a library is not being processed itself, it still can bring it's ProGuard rules - in order to be consumed, when building the whole project.
I am not getting what you actually want to do, but I can suggest you one thing that is just don't do assembleRelease instead import in your another project, clean project and build then use the generated aar from the /build/outputs/aar/ directory. And must check you are not using reference of obfuscated class anywhere.
I am following this tutorial and there is one section that says:
If you use Picasso as your image engine, add rules as Picasso's README says. And add extra rule:
-dontwarn com.bumptech.glide.**
am confused on how to add -dontwarn com.bumptech.glide.**?
I tried compile '-dontwarn com.bumptech.glide.** and compile 'com.bumptech.glide.** but both attempts failed.
Please can anyone guide me through it?
I am sorry for the beginner question
this rule is related to proguard
so you should add it to proguard-rules.pro file
you can read more here https://developer.android.com/studio/build/shrink-code.html
proguard change the references and the structure (obfuscating names specially ) of your code, for shrinking and security reasons, but that's not good for 3th party libraries.
Application projects obfuscate the entire code base, including any referenced libraries, so they need proper configuration for the application code and for the library code.
glide in your case
So the rules tell proguard to keep the code as it is (Keep command).
Sample code from gradle
minifyEnabled true
shrinkResources false
debuggable false
proguardFiles getDefaultProguardFile(
'proguard-android.txt'),'proguard-rules.pro'
so as you see the rules are written in two files, proguard-android is the default file that can be found in your SDK folder.
the proguard-rules is in you app folder.
by minifyEnabled true you enable proguard.
so your main issues is you don't know how to add the rules.
Here are ProGuard Rules for most of the famous android libraries here
but it always better to check library page, just google it for example glide + proGuard
here is sample code from one of my projects for glide , write it inside proguard-rules.pro
-keep public class * implements com.bumptech.glide.module.GlideModule
-keep public class * extends com.bumptech.glide.GeneratedAppGlideModule
-keep public enum com.bumptech.glide.load.resource.bitmap.ImageHeaderParser$** {
**[] $VALUES;
public *;
}
Every project I've previously worked on where Proguard was specified it was eventually abandoned as enabling it caused so many problems it was unusable and an enormous drain on resources. But my current project really does require obfuscation to make reverse-engineering more difficult. As I'm using Android Studio and Gradle I enabled it in the build config:
release {
runProguard true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
signingConfig signingConfigs.release
}
I then build a release build and see 292 warnings and build failure. Most are as follows and relate to libraries (Retrofit, Joda Time, Butterknife etc)
Warning:butterknife.internal.ButterKnifeProcessor: can't find referenced class javax.lang.model.element.TypeElement
OK, so I assume it is optimising away portions of the libraries. So I tried adding lines like this to the proguard-rules.pro file (specified in the Gradle file and auto-created by Android Studio):
-keep class butterknife.internal.** { *; }
No difference. OK, so I'll try disabling ALL shrinking and optimising to hopefully only benefit from obfuscation (even if admittedly a little less obfuscation benefit). I added these line to the Proguard config file:
-dontshrink
-dontoptimize
I recompile, and absolutely nothing changes, I'm still left with 292 fairly meaningless compilation warnings. Now I'm really confused.
How can I make 100% certain Proguard is actually reading my Proguard config file? Or is it using it but I've set an incorrect option?
What can I add to the Proguard file to reduce its work to JUST obfuscation so I have a Proguard-enabled build config that works as a starting point (without breaking my app) and does not optimise away any code.
I would appreciate any help to assist in reducing my hatred of Proguard.
put the following in your proguard config so that it wont mung up your butterknife library.
-keep class butterknife.** { *; }
-dontwarn butterknife.internal.**
-keep class **$$ViewInjector { *; }
-keepclasseswithmembernames class * {
#butterknife.* <fields>;
}
-keepclasseswithmembernames class * {
#butterknife.* <methods>;
}
here is a github discussion link about the same issue, https://github.com/JakeWharton/butterknife/pull/117#issuecomment-51292624
I have a problem that Proguard strips out methods of my debug APK (I need to run proguard on debug beccause of method dex file limit), even if they are used in the Test apk. E.g. i use GSON addProeprty method in Unit test, but not in the App apk. This method gets stripped away and causes the test to fail. But i do not want to configure proguard to just keep all of GSOn because of the dex file limit, but also do not want to list all methods seperately. is there a way to tell rpguard to consider the unit tests as source code entry points?
This is what I did.
Add a custom proguard rules file.
/project/app/proguard-test-rules.pro
# Proguard rules that are applied to your test apk/code.
-ignorewarnings
-keepattributes *Annotation*
-dontnote junit.framework.**
-dontnote junit.runner.**
-dontwarn android.test.**
-dontwarn android.support.test.**
-dontwarn org.junit.**
-dontwarn org.hamcrest.**
-dontwarn com.squareup.javawriter.JavaWriter
# Uncomment this if you use Mockito
#-dontwarn org.mockito.**
The add the following to your build.gradle for your app. To use the proguard file when testing.
/project/app/build.gradle
android {
debug {
minifyEnabled true
testProguardFile 'proguard-test-rules.pro'
}
}
None of the above answers did the trick for me. I had two issues: I needed to also use the default proguard file for testing, and my default proguard file was wrong.
To use the default proguard file, in addition to your own:
android {
debug {
minifyEnabled true
testProguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-project-test.pro'
}
}
The default proguard file (and all of the tools/proguard folder) is apparently not replaced by default when you update the SDK tools through Android studio. My machine was using an outdated config file, which was causing weird proguard issues. To update proguard's default config, replace ~/Library/Android/Sdk/tools/proguard/proguard-android.txt with this.
Instrumentation tests (and others?) do not use the same proguard file as your debug/release apk's. You might try setting the testProguardFile option inside the debug and release blocks. This test-specific proguard file can be very permissive because it's not being used for the debug/release apk's.
I've solved this problem in my build by having an additional "dev" buildType where I enable proguard, but configure it to keep all code in my own package, and a few specific library classes that happen to be used from tests only. I also disable obfuscation in the dev buildType so that it can be debugged from an IDE.
For debug and release builds I use my "real" proguard settings including obfuscation and optimizations.