After we complete an app, we need to generate an APK and then go online. The size of APK also affects whether users are willing to download your app to a certain extent, so there is the art of APK slimming.
directory
- The structure of the apk
- Image compression
- Import vector map
- Adaptation problem
- Tint shader
- Dynamic library Removal
- So library related knowledge points
- ABI
- conclusion
The structure of the apk
Since we want to slim down an APK, we first need to know the content of the APK format file. In fact, an APK file is a ZIP package, we just need to change the suffix to zip, and then unzip to see the contents. Let’s take a look at its files and functions:
Apk contains the following directories:
assets/
: contains the application’s resources, which can be obtained through the AssetManager object.lib/
: contains compiled code for the processor level. This directory has a subdirectory for each platform type, such as armeabi, armeabi-v7A, ARM64-V8A, x86, X86_64, and MIPS.res/
: contains resources that are not compiled to resources.arsc.META-INF/
: contains cert. SF and cert. RSA signature files, as well as manifest.mf files. (Check that the APK has been changed)
Apk contains the following files:
classes.dex
: contains classes in the dex file format understood by the Dalvik/Art virtual machine.resources.arsc
: contains compiled resources. This file contains the XML content of all configurations for the RES/VALUES directory. The packaging tool compiles and compresses THE XML content into binary form. These contain language strings and styles, as well as content that is not stored directly in the resources.arsc file but is given a path to the content, such as layout files and images. So they are calledResource mapping tableAndroidManifest.xml
: contains the main Android configuration files. This file lists the application name, version, access rights, and reference library files. The file is stored in binary XML format. This file also shows minSdkVersion, targetSdkVersion, etc.
Ok, now that we know what APK is, let’s start slimming it down.
Image compression
As we all know, an APK will use a lot of images, if the image can be compressed, the effect is very impressive.
As shown below, we often use such a set of diagrams in projects.
It is obviously just a picture, but we need such a group because of its size and color, which obviously takes up too much size. Is there any way to optimize it?
The answer is yes.
Google’s AS provides a tool called Vector Asset Studio that helps you add built-in Material ICONS and import native formats such AS SVG AS Vector resources into your project. This will generate an XML file with a vector root in the drawable directory and a smaller vector. So let’s see how that works.
Import vector map
First we run Vector Asset Studio in AS AS: Right click on the RES folder in your project and select New –> Vector Asset. This will bring up the following dialog. Select the corresponding actions of the tags in the image to import the built-in Material icon or SVG Vector image.
But the above way can only import pictures one by one, obviously very troublesome. Is there a better way? In fact, the reason why we import SVG images with svg2Vector instead of directly copying them to drawable is because Android does not support SVG and we need a tool to convert them, so we can use svg2Vector to batch convert them and then directly copy them to drawable. The conversion command is as follows:
Java -jar svg2vector-cli-1.0.0.jar -d. -o a -h 20 -w 20
-d Specifies the directory where the SVG file resides. -o Prints the android Vector image directory. -h Sets the height of the converted SVG
Adaptation problem
Vector graphics was only supported in Android 5.0 (API21), so we need to adapt this area. If not, and your minSdkVersion is less than 21, it will automatically generate PNG images in each drawable directory, which will make the APK package larger, so be careful here. We have the following two ways to adapt:
Method 1: Generate a PNG image
This way, the corresponding PNGS are generated in the drawable file, but we can specify which ones to generate. For example:
Gradle can be configured to generate PNG images in the specified drawable file.
Method 2: Support libraries
Alternatively, you can use the support library (version 23.2 or higher), which is also configured in your project build.gradle as follows:
This adaptation uses the app:srcCompat attribute instead of android: SRC, as shown below:
In this way, you just solve the problem that you need multiple images of different sizes, but you also need images of different colors. What do we do with this? Don’t worry, Google engineers have a tool for this too, it is Tint shader.
Tint shader
We usually use black for vector images, and Tint shaders can change the color, which can be used directly in XML, as follows:
In Java code, we can do this with DrawableCompat, as follows:
So if you want to achieve the effect of buttons, can you also achieve it through Tint? The answer is yes.
First we need to create two selectors, one is drawable selector, the other is color selector, as follows:
Then you can use it directly, as follows:
In general, Tint color finder is pretty easy to change the color of vector images.
By using vector graphics, we can reduce the total size of the images used and thus the size of the APK.
You don’t lose weight overnight, so we keep losing weight.
Dynamic library Removal
So library related knowledge points
Speaking of the SO library, I believe that most people have used it, but do not know what it is. So library is a dynamic library compiled by NDK.
So why do we put so files in armeabi, ARM64-V8A, ArmeabI-v7A, x86, x86_64?
The main reason is that our app runs on different phones, and so library is compiled by C \ C ++, not cross-platform, so different platforms (different CPUS) need to use different so library. So what do I mean by different files? Let’s move on.
ABI
The ABI is an abbreviation for the Application Binary Interface, which defines how binaries (especially.so files) run on the appropriate system platform, from the instruction set used, to memory alignment, to the system libraries available. On Android, each CPU architecture corresponds to an ABI, namely, armeABI, ArmeabI-V7A, ARM64-V8A, x86, X86_64, MIPS, and MIPS64.
ABI
Supported Instruction Set(s)
armeabi
ARMV5TE and later, Thumb-1
armeabi-v7a
Armeabi, Thumb-2, VFPV3-D16, Other, Optional
arm64-v8a
AArch-64
x86
X86 (IA-32), MMX,SSE/2/3, SSSE3
x86_64
X86-64, MMX, SSE/2/3, SSE3, SSE4.1, SSE4.2, POPCNT
mips
MIPS32r1 and later
mips64
MIPS64r6
The analysis of each version is as follows:
- MIPS/MIPS64: Rarely used for mobile phones can be ignored
- X86 / X86_64: X86 mobile phones will include an instruction set dynamic transcoding tool called Houdini provided by Intel, which is compatible with ARM. So. Considering the market share of x86 is less than 1%, the two x86 related
- Armeabi: ARM V5 This is a fairly old version that lacks hardware support for floating-point calculations and has performance bottlenecks when a large number of calculations are required
- Armeabi-v7a: The current mainstream version of ARM V7
- Arm64-v8a: 64-bit support
So now we usually only need to adapt ARM V7 in the project build.gradle, as follows:
conclusion
Ok, that’s all for today. There’s a long way to go, and we’ll share some tips next time.