What does 'minifyEnabled=true' do when all configuration options are disabled? - android

I have a complicated build setup for an android app which basically consists of a normal android app fused together with a Xamarin/Mono project in order to include an important C# library (like this: https://github.com/royd/KotlinAppWithXamarinDependency)
Everything is working fine except if I enable minification in my app/build.gradle via minifyEnabled true the app instantly crashes on startup because the Mono-runtime can't find native assemblies that are definitely contained in the apk.
This is the message I get in Logcat:
A/monodroid: No assemblies found in '(null)' or '<unavailable>'. Assuming this is part of Fast Deployment. Exiting...
With minifyEnabled false everything is working fine so I tried disabling all config options in my proguard-rules.pro:
-dontobfuscate
-dontoptimize
-dontshrink
And I also added the following lines to my app/build.gradle
packagingOptions {
doNotStrip "*/armeabi/*.so"
doNotStrip "*/armeabi-v7a/*.so"
doNotStrip "*/x86/*.so"
}
Unfortunately all this doesn't help.
I also decompiled a working and a broken apk with dex2jar to compare the bytecode. It seems to be exactly the same except for some enum-optimizations that shouldn't matter.
According to the error message in Logcat the error seems to be thrown from the native library libmonodroid.so.
So my question: What does minifyenabled flag do when all these config options are disabled?
Edit:
I have found out that minification works as intended when I use version 4.0.1 of Android Gradle Plugin (from July 2020). Upgrading the version to 4.1.0 (August 2020) breaks my app. Now the question is what changed between these two versions?

When you set the minifyenabled as true. The r8 will choose the configuration files but not only the proguard-rules.pro and the app/build.gradle to shrink, obfuscate, and optimize your app.
There are some others files such as AAR libraries: <library-dir>/proguard.txt and
JAR libraries: <library-dir>/META-INF/proguard/ and so on. So this error may be caused by the native library losing when you set the set the minifyenabled as true.
If you need more information, please check the official document:https://developer.android.com/studio/build/shrink-code#enable
In addition, you can check the 'proguard-android-optimize.txt' and when you add the -dontoptimize to proguard-rules.pro may cause a conflict.

I found out, that in the Android Gradle Plugin versions 3.6.0 to 4.1.0 they switched to a more performant tool for building apks called zipflinger.
This tool can be disabled by adding this line to my gradle.properties:
android.useNewApkCreator=false
When building the apk zipflinger stores the external .NET assemblies as DEFLATED zip entries instead of STORED and thats why monodroid cant read them.
References:
https://github.com/xamarin/xamarin-android/issues/6838#issuecomment-1110816027
https://copyfuture.com/blogs-details/20210119115509664T

Related

Resource shrinker cannot be used for multi-apk applications

So today I decided to try my hand at making at making a dynamic feature module. I have R8 enabled with both minifyEnabled and shrinkResources set to true. Trying to compile gives me the following error.
Resource shrinker cannot be used for multi-apk applications
Affected Modules: app
Has anyone else seen this? There are similar questions around stack but nothing directly related to DFMs.
I would love to keep this flag enabled to avoid library bloat
Gradle Plugin: 4.0.0
Gradle Wrapper: 6.1.1
This feature is implemented starting Android Gradle Plugin 4.2.0 and can be enabled by setting android.experimental.enableNewResourceShrinker=true flag in gradle properties.
Details are available here.

where is the proguard mappings.txt file generated when using JACK?

I have been trying to use the latest JACK and JILL build system to for my android project. I know that JACK process includes the proguard processing.
But after that i couldn't locate the mappings.txt file for back-tracking stack-trace of bugs provided on google play developer console.
Please help me LOCATE mappings.txt.
Another related question is if the shrinkingResources still works while JACK because shrinkingResources requires minifyEnabled true but JACK requires minifyEnabled false.
Project Config--
compileSdkVersion 24
buildToolsVersion "24.0.0"
classpath 'com.android.tools.build:gradle:2.1.2'
UPDATE--
Answer posted by T. Neidhart is NOT a working solution.
To enable obfuscation/shrinking with JACK you need to set minifyEnabled to true. It was unsupported in earlier versions, but now JACK has its own obfuscation and shrinking implementation (not using ProGuard at all) that can process some of the original ProGuard rules (for a complete list of supported options refer to Jack obfuscation and shrinking).
Once the configuration is properly setup, the mapping.txt file will be located in the same place as before: build/outputs/mapping/<buildtype>/mapping.txt
There is nowhere to find that mappings file as JACK internally process proguard and there are some issues pointed on android tools site while enabling JACK.
So for now not using JACK is the best option if you care tracing back exceptions in your apps.

How to perform minification and obfuscation with the JACK compiler?

Google has released a test version of their new JACK compiler for Android developers with Android Studio 2.1.
My question is, how do we enable obfuscation for the APK with JACK? The article below says that JACK performs obfuscation natively and eliminates the need for Proguard:
Compiling with
Jack
Whereas the following article says that JACK makes use of Proguard configuration files (i.e. the .pro file) for performing obfuscation:
Experimental New Android Tool Chain - Jack and Jill.
It also says that
During this process Jack also handles any requested code minification (shrinking and/or obfuscation).
What exactly does this mean? Do we have to use the minifyEnabled option and define a .pro file containing the Proguard options?
In Summary:
How exactly do we go about enabling obfuscation with JACK? Can we
bypass the use of Proguard, or does Proguard play a de-facto role in
the obfuscation process, even if we compile with JACK?
Does JACK currently support obfuscation or not, and is it available
in a stable (i.e. non-beta/canary) version of Android Studio?
Note:
I have already referred the following posts:
How to enable Jack (Java Android Compiler Kit) in android studio.
Error:Jack is required to support java 8 language features.
Further References:
An Introduction to Jack and Jill on X86.
The dark side of Jack and Jill.
Java 8 Language Features.
Update:
The answer by Matt Insko is helpful, but I would like more detail, and a more precise, canonical answer.
J.A.C.K. obfuscation does not appear to be supported in the latest released Gradle Plugin (v2.1.0).
If you enable JACK when using the latest v2.1.0 plugin, it will tell you Jack requires Build Tools 24.0.0 or later requiring you to use the preview tools.
Using android gradle v2.2.0-alpha1, Build Tools-v24rc4, Platform Tools-v24rc3, and Sdk Tools-v25.1.7rc1 I was able to get obfuscation to be performed by JACK.
When enabled inside defaultConfig it complained Minifying the variant used for tests is not supported when using Jack., because minifyEnabled true was configured in the debug build.
So, I created a custom build type and enabled it there:
buildTypes {
...
custom {
minifyEnabled true
proguardFiles 'proguard-android-JACK.txt-2.2.0-alpha1'
jackOptions {
enabled true
}
}
There was a problem when using proguardFiles getDefaultProguardFile('proguard-android.txt'). It errorred with: com.android.jack.api.v01.ConfigurationException: Error while parsing ..., . So, I just removed the lines it complained about and then just manually specified my modified configuration file.
You can have a look here: https://source.android.com/source/jack.html
From the official documentation:
(Jack) Handles shrinking, obfuscation, repackaging and multidex. Using a
separate package such as ProGuard is no longer necessary.
Please notice especially the section "Shrinking and Obfuscation" where it's mentioned that:
Jack has shrinking and obfuscation support and uses proguard
configuration files to enable shrinking and obfuscation features.
And also the supported and ignored options are presented too.

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

Obfuscation in Android Studio

Is there any obfuscation tool to use with Android Studio? IntelliGuard plugin is declared to be supported by the Studio, but it doesn't work actually due to missing AntSupport plugin. I wan't able to find one in the repository. Any ideas?
P.S. Android Studio build process is based on Gradle, so I wouldn't expect to see Ant support there at all. May be I'm wrong.
Basic Obfuscation
To obfuscate code in Android studio just go to your build.gradle file in your Android Studio project:
Change the minifyEnabled property from false to true
This is a basic Obfuscation.
After generating the apk you can see the obfuscation result by decompiling the apk with any software. This page could help you:
http://www.decompileandroid.com/
In the obfuscation result you will see classes with name: a,b,c....
And the obfuscation variables and methods will have also names like aa,c,ac...
Normal obfuscation:
To obfuscate the code in a more complex form you could go to your root directory app and create a .pro file. For example in the following picture I have created the file: proguard-rules-new.pro. In the same directory you should see a file called proguard-rules.pro
Now add the file you have created to the build.gradle file
And edit the .pro file you have create with your own custom proguard rules
First enable minifyEnabled in your build.gradle file, like
minifyEnabled true
After this, add below lines in progurad-rules.txt file
-keep class yourpackage.** { *; }
-dontusemixedcaseclassnames
-dontskipnonpubliclibraryclasses
-verbose
For checking that its working fine go to:
http://www.javadecompilers.com/apktool website so that you can verify after decompilation.
It will work and your classes will be hidden completely.
Update: R8 is by default enabled in android studio version 3.4.0 and above
In android studio 3.4+, R8 is enabled by default so no need to add additional property though you can opt for deep optimizations by adding fullMode property in gradle.properties as:
android.enableR8.fullMode=true
You can disable R8 and enable proguard by adding following properties in gradle.properties as:
android.enableR8 = false
useProguard = true
Android September 2018 release a new tool R8 shrinker and obfuscation tool.
R8 - R8 is a java code shrinker and minifying tool that converts java byte code to optimized dex code
For AS version below 3.4.0.
Open gradle.properties
Add android.enableR8 = true
as
# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
org.gradle.jvmargs=-Xmx1536m
# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
android.enableR8 = true
Minimum Requirements:
Android studio 3.2 September 2018 release or above
Java 8
R8 Tool
R8 supports Proguard:
Keep in mind, R8 is designed to work with your existing ProGuard rules, so you’ll likely not need to take any actions to benefit from R8. However, because it’s a different technology to ProGuard that’s designed specifically for Android projects, shrinking and optimization may result in removing code that ProGuard may have not. So, in this unlikely situation, you might need to add additional rules to keep that code in your build output.
To Disable R8 in AS 3.4.0 and above:
# Disables R8 for Android Library modules only.
android.enableR8.libraries = false
# Disables R8 for all modules.
android.enableR8 = false
Note: For a given build type, if you set useProguard to false in your app module's build.gradle file, the Android Gradle plugin uses R8 to shrink your app's code for that build type, regardless of whether you disable R8 in your project's gradle.properties file.
Proguard is well-supported on Android studio. You have to configure Gradle to run it. Instructions: http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Running-ProGuard
after setting minifyEnabled to true there are two version of apk you can get, so that you have to add debug option in your build.gradle to obfuscate debug one:
buildTypes {
release {
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
debug {
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
sync, build and build apk

Categories

Resources