How do I prevent the Android "build process" from optimizing .png images?
I have an Android project with the following res directories:
- /res/
- /res/drawable
- /res/drawable-hdpi
- /res/drawable-hdpi-v5
- /res/drawable-ldpi
- /res/drawable-ldpi-v5
- /res/drawable-mdpi
- /res/drawable-mdpi-v5
These directories contain many .png files. I optimize PNG sizes with PNGOUTWin, and the overall size is reduced by more than 20%. When I build the .apk file, the images are "optimized" by the build process and the overall size is now 10% above the initial size, or 30% above my/PNGOUTWin optimized size.
My goal is to reduce the .apk size, even if it will affect the final performance, memory requirements, etc. How do I prevent the "build process" from optimizing .png images?
I'm targeting Android 2.2 and above.
P.S.: I am currently building my Android project from Eclipse, but I will switch to the automated build later (Ant?).
Note about JPG images: JPG will not work, because they do not have transparency.
Finally there is an official way to disable the PNG cruncher with Gradle which hasn't been mentioned here yet:
Edit main build.gradle to require gradle version 1.1.3 (or newer):
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:1.1.3'
}
}
In the individual apps's build.gradle, section android {}, insert:
aaptOptions {
cruncherEnabled = false
}
Reference:
https://code.google.com/p/android/issues/detail?id=65335
Specifying PNG crunching is now a BuildType property and is disabled by default on debug builds:
android {
…
buildTypes {
release {
crunchPngs false // or true
}
}
}
Note: It's available from Android Studio 3.0 Canary 5 .
As mentioned in the Android documentation: http://developer.android.com/guide/topics/graphics/2d-graphics.html#drawables
Note: Image resources placed in res/drawable/ may be automatically optimized with lossless image compression by the aapt tool during the
build process. For example, a true-color PNG that does not require
more than 256 colors may be converted to an 8-bit PNG with a color
palette. This will result in an image of equal quality but which
requires less memory. So be aware that the image binaries placed in
this directory can change during the build.
So if you want to reduce the size of your application you should either reduce the color-depth of your PNG files (this helps a lot) or switch to .JPG files wherever possible.
Android Studio: Since Gradle Android plugin 1.0.0:
android {
...
aaptOptions {
useNewCruncher false
}
....
}
Eclipse: Override the crunch task writing this in your build.xml:
<target name="-crunch">
<echo message="This will skip PNG optimization"/>
</target>
buildTypes {
release {
crunchPngs false // or true
}
}
add above the line on android block in
in ionic/Cordova project : root_folder_Of_App/platforms/android/app/build.gradle
in Android project: app/build.gradle
For More Information Visit: https://androidstudio.googleblog.com/2017/06/android-studio-30-canary-5-is-now.html
Google recently introduced a new PNG processor in aapt 0.9.1 in the Android SDK Build Tools that fixes this issue of increased PNG sizes after aapt optimization.
With this update, it is now possible for Android Studio & Gradle to switch between the PNG processors with the following change in your build.gradle configuration file:
android {
..
..
aaptOptions.useAaptPngCruncher = false
}
By adding this line, aapt uses the new PNG processor in which it checks to see if the "optimized" PNG files are smaller than the original PNG files. I was able to reduce 4.8 MB in my compiled APK and have not encountered any bugs/issues with the new build configuration.
UPDATE: This has been deprecated in later versions of Android Studio. Please refer to the answer provided by ChrisG.
Related
I am using the following splits code in my gradle to reduce APK size:
splits {
abi {
// Enable ABI split
enable true
// Clear list of ABIs
reset()
// Specify each architecture currently supported by the Video SDK
include "armeabi-v7a", "arm64-v8a", "x86", "x86_64"
// Specify that we do not want an additional universal SDK
universalApk false
}
}
When I run the app, the APK is generated fine, with reduced size and runs on Emulator.
But when I try to build APK file from Build > Build bundles/apks like
I get this error:
Execution failed for task ':app:packageAbcDebug'.
> A failure occurred while executing com.android.build.gradle.tasks.PackageAndroidArtifact$IncrementalSplitterRunnable
> Could not find EOCD in '....apk'
Possible solution:
- Declare repository providing the artifact, see the documentation at https://docs.gradle.org/current/userguide/declaring_repositories.html
I only wanted to exclude "x86" architectures, to reduce the APK size and need to send the APK to my client. How do I fix this?
I was running into a similar issue during my build process, though I wasn't enabling split. Take it for what you will.
After digging through the source kit for PackageAndroidArtifact and other sources in Android, I discovered "EOCD" means "End Of Central Directory". That is, it's related to the end marker of the zip file that gets built when building your output. (The link to the comments in Android's source kit.)
In my own case, I discovered that even though I'm asking Android Studio to do a complete clean of my build directory, it's leaving the app-debug.apk build artifact file. (For reasons, I'm trying to package the debug version of our APK for internal testing.) And somehow that file got corrupted, which completely confuses the build process.
The resolution was to manually delete the apk file prior to running the build process. (In my case, it was found in my build's app/debug directory, next to the app/build directory.)
G'figure...
May be its late but here is the solution with reason for it to work.
Since we are using splits to create apks for each architecture build system needs a different name for each apk being generated.
Best solution is to provide a dynamic way of generating apk names.
Just go to app level build.gradle file
Add rules for release/debug build variants in buildTypes block inside android block like this
buildTypes {
release {
minifyEnabled true
shrinkResources true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
applicationVariants.all { variant ->
variant.outputs.all { output ->
project.ext { appName = 'YourApkName' }
outputFileName = "${appName}-${output.getFilter(OutputFile.ABI)}-${variant.name}-${variant.versionName}.apk"
}
}
}
}
Explaination :
Here the apk name is appended by the ABI name that helps build system identify the apks for each architectures.
You can also use Android Size Analyze to identify sizes and reduces the apk size.
In order to understand which files are actually taking up more space in the application, use the Android Size Analyzer plugin inside Android Studio. For installing the plugin
Select File > Settings (or on Mac, Android Studio > Preferences.)
Select the Plugins section in the left panel.
Click the Marketplace tab.
Search for the “Android Size Analyzer” plugin.
Click the Install button for the analyzer plugin.
Restart the IDE after installing the plugin. Now, to analyze the application, go to Analyze > Analyze App Size from the menu bar.
I had gradle
classpath 'com.android.tools.build:gradle:3.5.3'
distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip
and my apk 160Mb
then I update it to
classpath 'com.android.tools.build:gradle:3.6.3'
distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.4-all.zip
and my apk size is 270Mb
How is it possible? But acctually if I build .aab it is still has 160Mb, so size increasing if I build .apk
This is caused by a change in the Gradle plugin which used to zip deflate the native libraries, but now just stores them. According to Google this ends up being a benefit for end users:
Smaller app install size because the platform can access the native
libraries directly from the installed APK, without creating a copy of
the libraries.
Smaller download size because Play Store compression is
typically better when you include uncompressed native libraries in
your APK or Android App Bundle.
According to that same link, you can revert this change by setting extractNativeLibs to true
add this tag on you AndroidManifest.xml file
android:extractNativeLibs="true"
example:
<application
android:extractNativeLibs="true"
... >
</application>
i had the same problem the only thing that help me little is to add abiFilter in build.gradle inside defaultConfig
ndk{
abiFilters "mips","mips64","armeabi","armeabi-v7a","arm64-v8a"
}
I had the same problem, but the provided solution was not working. For those having multidex enabled on your APK your must add the following instead:
android {
packagingOptions {
dex {
useLegacyPackaging true
}
}
}
on your module build.gradle
Source : https://developer.android.com/studio/releases/gradle-plugin#dex_files_uncompressed_in_apks_when_minsdk_28_or_higher
I have a problem with 9 patch images.
There are around 30 9 patch images in my res folder. On earlier versions of Android Studio, errors told me exactly which one of the images was bad, but on newer versions I just get error
Error:Execution failed for task
':app:mergePhotoKeyboardThemeChangerDebugResources'.
Error: java.lang.RuntimeException: Some file crunching failed, see logs for details
Is there an option for that in Android Studio settings? It is a lot of work to check images one by one and see which one is bad.
Some times the error will come with jpg images, try to convert the jpg images to png images.
convert online from online png converter.
Suggestion#1:
Relocate your project and the build will succeed.
Resource Link: https://stackoverflow.com/a/25209204
Suggestion#2:
Sometimes .png images are corrupted. you need to replace in drawable
Resource Link: https://stackoverflow.com/a/41380118
Suggestion#3:
change build directory
For example:
allprojects {
buildDir = "C:/tmp/${rootProject.name}/${project.name}"
repositories {
jcenter()
}
}
Rebuild and happy coding.
Resource Link: https://stackoverflow.com/a/41877283
Last Suggestion
Add
aaptOptions {
cruncherEnabled = false
}
in your gradle(app) file in android{ } scope
it will work fine
I'm trying to reduce the size of my apk.
So first I've compressed my pngs with zopfli then added
aaptOptions {
cruncherEnabled=false
}
in my build.gradle (app) and built.
But the result is same with and without that option (gradle version 2.2.3)
Can anyone help?
I have 5 modules in my project, it takes me 2 mins to build everytime, is there any way to speed up android studio build time?
You can try to add this in your build.gradle file inside the android closure
dexOptions {
incremental true
javaMaxHeapSize "4g"
}
It will allocate large heap size for your dex process which usually takes more time in build.
You can change your your heap size according to RAM you have in your system like "2048M" for 2GB allocation.
Another idea might be using a faster repository. If your build is using mavenCentral() try to replace it with jcenter().
For me, adding the following two properties to the "gradle.properties" file in the project root improved performance considerably.
org.gradle.parallel=true
org.gradle.daemon=true
"org.gradle.parallel=true" does parallel processing of the modules. You may receive a message that the feature is experimental but it has worked for me without any problems.
"org.gradle.daemon=true" will keep a dedicated Gradle JVM running so that it is not re-started each time you do a build. This first build takes as long but subsequent builds are much quicker.
Hope this helps.
Yup you can speed up android studio build time.
1. You need to clean your project before building your project.
2. Close all other projects on which you are not working before build.
3. Allow auto build option.
According to this document https://developer.android.com/studio/build/multidex.html#dev-build
If you are using MultiDexApplication you can set minSdkVersion 21 for your develop productFlavors to mitigate the longer build times for multidex output.
productFlavors {
dev {
// Enable pre-dexing to produce an APK that can be tested on
// Android 5.0+ without the time-consuming DEX build processes.
minSdkVersion 21
}
prod {
// The actual minSdkVersion for the production version.
minSdkVersion 14
}
}