Proguard runs every time with gradle; results not reused - android

I am building an Android app with gradle 1.8 and Android Gradle plugin 0.6.3.
android {
...
buildTypes {
...
release {
runProguard true
proguardFile 'proguard.cfg'
proguardFile getDefaultProguardFile('proguard-android.txt')
}
...
}
Every time I run gradle assembleRelease, the proguard step seems to run each time - the results of the previous assemble do not seem to be reused, despite no code changes. The compile step also says UP-TO-DATEfor subsequent runs, which seems to confirm this. Running proguard adds a significant amount of time to every build. In particular, running connectedInstrumentTest currently requires proguard to run each time.
Is this normal behavior when using proguard/gradle? If not, what are some things that could cause the proguard step to run each time?
Note: It is not actually possible for me to build my app without proguard shrinking anymore, the dex step fails with the following error:
trouble writing output: Too many method references: 67195; max is 65536.

This should be solved when the Android Gradle task upgrades to the ProGuard Gradle task version 4.10. The latter has the necessary annotations for Gradle to check if the output is up to date.

Related

Using minifyEnabled=true is NOT OK in development ;]

I just updated Android Studio to 3.5.
BTW updated the Gradle version and several libraries.
To my surprise, the application does not fit into a single DEX (uses over 73,500 methods, previously in debug version as far as I remember ~50K)
What changes have I made:
Kotlin 1.3.41 -> 1.3.50
classpath 'com.android.tools.build:gradle:3.5.0' from 3.4.2
classpath 'com.google.gms:google-services:4.3.1' from 4.3.0
implementation 'com.google.android.gms:play-services-ads:18.1.1' from 18.1.0
implementation 'com.google.firebase:firebase-core:17.1.0' from 17.0.1
The new release APK has fewer (60) methods (26760) than the previous one.
Other problem I got:
NDK Resolution Outcome: Project settings: Gradle model version=5.4.1, NDK version is UNKNOWN error
App using AndroidX.
app is compiling & work now OK when set
debug {
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
I imported settings from an older version of Android Studio. Maybe here is the problem?
Or there is no problem and I have to reconcile and use multiDEX (for development) and in release apk drop multiDEX?. Will multidex be better than minifyEnabled for debug version?
Changed:
debug {
// minifyEnabled true
// proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
multiDexEnabled true
}
And is working with multiDex when I run emulator with APK >=21.
Prior 21 API will test using release APK only.
BTW APK analyze my debug version show:
classes.dex 54806 methods
classes2.dex 1107 methods
classes3.dex 6725 methods
Total: 62638.
When I disable multiDex.
Cannot fit requested classes in a single dex file (# methods: 73883 > 65536) ;))
Something is not right ;)
set multiDexEnabled true globally or for both build-types - else the release build will exceed the 64k limit of a single DEX file. debug & release build can have different method count, because these are two merged source-sets - and unused classes may also be stripped (multiDexEnabled true also adds it's own library). While minifyEnabled true for debug builds is useless ...and I really don't understand why one would intend to do that. When the non-public class/method names in the APK do not match those class names in the IDE, one might find it difficult to debug that, because breakpoints will not catch; it's alike shooting oneself into the leg.
If a single library update introduces a new dependency, this can add lots of classes & methods.

Why Proguard runs despite having minifyEnabled in gradle config?

According to documentation setting minifyEnabled to false must disable ProGuard run
integration {
minifyEnabled false
versionNameSuffix "-int"}
But the ProGuard is still started by Gradle! Any ideas why?
You will need to change the Build Variant to use one of the integration build variants (from the bottom left in android studio), if you want to use the configuration for integration buildType.
From what you describe you appear to be using a different buildType. By default it is debug. Make sure an integration Build Variant is selected and you should be good.
As it often happens, I found and answer after posting my question.
"This is not a bug, this is a feature":
https://groups.google.com/forum/m/#!topic/adt-dev/iS_lyRH8hL8
This is not really a problem, but certainly annoying.
The output you are seeing is related to the way the Android gradle plugin determines the set of classes that must be in the main dex file when multidex is enabled. For this purpose it uses ProGuard internally, but it is unrelated to your configuration.
In order to disable the logging output of this task, you can add the following to your build.gradle file:
tasks.whenTaskAdded { task ->
if (task.name.startsWith("transformClassesWithMultidexlistFor")) {
task.logging.level = LogLevel.ERROR
}
}

Android gradle, about those methods that are deprected after updating

I have encountered this problem several time whenever I update my Gradle version & Gradle Android plugin. For example, I used to use:
Gradle 2.1
Gradle Android Plugin com.android.tools.build:gradle:0.13.3
With this version, my build script contains for example:
buildTypes {
release {
runProguard true
proguardFiles getDefaultProguardFile('proguard-android.txt'), \
'proguard.cfg'
}
debug {
runProguard false
}
}
Few weeks later, I saw a new Gradle version (2.2.1) was released, so, I updated my Gradle & Gradle Android Plugin to newer version:
Gradle 2.2.1
Gradle Android Plugin com.android.tools.build:gradle:1.0.0+
Then, I run command gradle clean build, suddenly, the build is not successful anymore, because with the newer version, I got error:
Could not find method runProguard()
My questions are:
(MAIN QUESTION) It seems everytime when the Gradle & Gradle Android Plugin are updated, there are always some methods are deprecated, it is understandable. BUT, I am really appreciate if there is a document summarizes all the deprecated methods & their replacements. So, where can I find such information? Seems Gradle & Gradle Android Plugin don't do a good job on this to facilitate developers to quickly migrate the build script to newer version.
How to get rid of the error: Could not find method runProguard() in my above case?
change
runProguard ****
to
minifyEnabled ****
you can get the deprecated methods or resources here http://tools.android.com/tech-docs/new-build-system for the android studio builds or releases
I really want to know where is the place to find out the replacements of deprecated methods in general when Gradle & Gradle Android Plugin are updated
That would be the documentation, particularly the release notes. 0.14.0 renamed runProguard to minifyEnabled, and 0.14.3 removed runProguard.
You should replace runProguard true with minifyEnabled true, there are a lot of question about this topic.
On your first question, I read some official statement here saying that, from now on, they'll try to stick to actual methods name and/or provide support info, to make the switch between gradle versions easier, so you shouldn't be worried.
From version 1.0.0 and going forward, we will strive much harder to not make incompatible changes, and if we do, we plan to write IDE support to help migrate the projects automatically.

Application too big? Unable to execute dex: Cannot merge new index into a non-jumbo instruction

I am getting the following error when I compile my app:
[2014-05-07 21:48:42 - Dex Loader] Unable to execute dex: Cannot merge new index 65536 into a non-jumbo instruction!
I am at the point that if I declare a new method anywhere in my package, I get this error. If I don't, the app compiles.
I would like to know what exactly (and accurately) does this error mean. My app is big, but I don't think its that big! So:
Does the error mean I have too many methods? public? static? package? members?
Is it related to the methods/members of my root package, or also to the included JAR libraries?
Is there a way to get more debug information about this?
I already know about that "jumbo" enabling flag addressed in the similar questions here in SO, however, I think jumbo mode is not available on the API level I'm targeting (ICS).
Your error is for the amount of strings (methods, members, etc) in a single dex file.
You need to compile you app using jumbo in dex with:
dex.force.jumbo=true
in project.properties
This increment the limit for strings in a dex files. And your project will probably compile.
Also with jumbo set, the is another limit of 64K only for methods in an single dex. If you get this limit in the future , you will need to remove some dependencies.
UPDATE: for build with Gradle:
In Gradle you can enable jumboMode also in the build.gradle file with:
dexOptions {
jumboMode = true
}
Check:
Android Build: Dex Jumbo Mode in Gradle
Also with Gradle you can avoid the 64K limit for methods using multidex build, tutorial here:
https://developer.android.com/tools/building/multidex.html
For gradle build, just add the dexOptions into build.gradle to enable jumbo mode:
android {
dexOptions {
jumboMode = true
}
}
Remember to run "gradle clean" before your new building.
It's related to the number of methods of libraries included in the project. For example if you have tracking in your app, just Google Analytics is ~7000 methods.
In one of my projects using Lombok (2MB of JAR) gave me these problem. Solved getting rid of this library.
It looks like the problem occurs because all the class files from your project and JAR files are packed together before DEXing. This may not be completely true but any way of controlling this in our project has proven to be quite difficult. Even removing stuff that initially caused this problem, cleaning and rebuilding didn't fix the issue for us in a consistent way.
So we took this opportunity to switch our project to Android Studio and managed to solve the problem by turning on ProGuard for debug builds as well. More precisely we only use the shrink phase of the ProGuard's processing chain.
Gradle makes it very easy to turn on ProGuard for debug builds:
buildTypes {
debug {
runProguard true
proguardFile 'proguard-project-debug.txt'
}
}
And here is the debug ProGuard config we use:
-keep class com.your.code.**
# Use -keep to explicitly keep any other classes shrinking would remove
-dontoptimize
-dontobfuscate
-ignorewarnings
This does increase the build time of the project but the good side is that the debugger still works.
The only faster alternative I can think of is that any JAR files are manually stripped of the unused class files. But this is not only difficult to do it is also inconvenient when you want to use a slightly larger part of a library at a later time.
I hope this helps other developers struggling with this issue. And perhaps in the future Google can improve the compiler that does this pruning by default. Our APK DEX file went from 8MB to 2.9MB.
Newer gradle (1.0.0+) versions
In newer Versions of Android studio (1.0+) the bundled Gradle got updated. There were some changes on how the build mechanism works so your project Gradle file can now take advantage of the minifyEnabled and shrinkResources parameters. Current version is 1.1.0.
Keeping up with changes on a fast moving platform like Android takes effort but it is often rewarded with new features, tools and faster build times. So updating Android Studio and (carefully) updating your projects is worth the time you invest.
buildTypes {
debug {
proguardFile 'proguard-project-debug.txt'
minifyEnabled true
shrinkResources true
}
}
Some interesting observations. Same error may appear if you have multi-flavor project. It's confusing. Turned out that I attempted run app with generic command: gradlew installDebug. When I've changed command line to look like this problem is gone. Don't forget to replace Flavor part with your actual one.
gradlew installFlavorDebug

Is it possible to use proguard in debug mode?

In my android app, i want to test some features with proguard on.
I don't need to really "debug" it, but i want proguard to run when i hit run in eclipse. I don't want to export the binary every time (so, in release mode) and save as apk and get it to the device to test.
Is there any way to run proguard in this way?
Update:
It seems like this is possible if you are not using Eclipse; as question title does not include Eclipse, there are multiple correct answers to this question.
If you want to make the whole build process easier for you, you should switch over to gradle and Android Studio IDE.
Then you could easily add the following to your build.gradle file to run ProGuard:
android {
buildTypes {
release {
}
debug {
minifyEnabled true
proguardFile 'proguard-android.txt'
zipAlignEnabled true
}
}
}
This will run ProGuard on your debug build, configured with the file "proguard-android.txt", which should be put at your project's root folder. And in addition your apk is being zip aligned (Just remove "zipAlignEnabled true", if you don't want that to happen). If you want to do the same for your release build, just add those three lines under "release".
Slightly off-topic: Stuff like adding dependencies, signing your apk or adding other custom tasks to your build process is also way more uncomplicated with gradle. In addition you'll be able to not only build your apk via Android Studio IDE, but also via a simple command on the command line (e.g. ./gradlew assembleDebug). So if you are working on a team, the setup process for new members is just one "./gradlew assembleDebug" away. Without the need for any IDE configuration at all. Importing your project including all dependencies is as simple as a one-click process
EDIT:
As of Gradle Android Build Tools version 0.14.0 the property names have changed (http://tools.android.com/tech-docs/new-build-system):
BuildType.runProguard -> minifyEnabled
BuildType.zipAlign -> zipAlignEnabled
I've updated the above code.
Old Answer :
http://developer.android.com/tools/help/proguard.html
ProGuard runs only when you build your application in release mode, so you do not have to deal with obfuscated code when you build your application in debug mode.
When you build your application in release mode, either by running ant release or by using the Export Wizard in Eclipse, the build system automatically checks to see if the proguard.config property is set. If it is, ProGuard automatically processes the application's bytecode before packaging everything into an .apk file. Building in debug mode does not invoke ProGuard, because it makes debugging more cumbersome.
Update: 13-3-2016
It is possible with the new gradle build system. You need to set minifyEnabled to true in your build.gradle file. Generally you have pro-guard running in release mode. There are other options available like shrinking resources. You can find some useful info # http://tools.android.com/tech-docs/new-build-system
Also do have a look #
http://developer.android.com/tools/building/configuring-gradle.html
android {
...
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
debug {
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
Regarding custom Ant builds (and based on Victor's answer), adding the following to my build.xml file works for me:
<target name="-debug-obfuscation-check">
<!-- enable proguard even in debug mode -->
<property name="proguard.enabled" value="true"/>
<!-- Secondary dx input (jar files) is empty since all the jar files will be in the obfuscated jar -->
<path id="out.dex.jar.input.ref" />
</target>
Notice that I had to override (actually pre-set) the out.dex.jar.input.ref; otherwise, the later running of dx will attempt to merge non-disjoint jars and throw the DexException: Multiple dex files define Xxx.
It is possible if you build with Ant. See Android custom build using Ant on how to build your project with ant. Then, simply override in the project's build.xml the target "-debug-obfuscation-check" and set proguard.enabled to true:
<target name="-debug-obfuscation-check">
<!-- proguard is never enabled in debug mode -->
<property name="proguard.enabled" value="true"/>
</target>
With Android Studio you can use -dontobfuscate option in your Proguard rules file and debugger will work fine. I'm not sure if it works with Eclipe as well.
If you are using AGP (Android Gradle Plugin) 7.2.0 or newer, beware that we have a bug open without a solution so far. Workaround as of now is to downgrade AGP to 7.1.3 so you can obfuscate your debug APK.
https://issuetracker.google.com/issues/242214899?pli=1

Categories

Resources