In order to reduce the size of the application as much as possible, we should remove unused code and resources in the release version. In addition, there are two optimization directions that can be used to reduce the space occupied by the application. One is to use the obfuscation function, which will shorten the names of the application classes and members; the other is to use the optimization function , This feature will adopt a more aggressive strategy to further reduce the size of the application. This article will introduce how to use APK resource optimization to reduce application space and save user resources.
Ask a question
First use the + product U-APM application on different devices:
It can be seen from the figure that there is still room for optimization in the startup time of the application. In the next step, we will read the memory allocation of the application and determine the direction from which resources can be optimized to speed up the startup. time.
In order to analyze the above indicators in detail, we use the Memory tab on the Android window, which will show us the amount of data allocated on the heap over time:
The figure shows that a GC event has occurred, unused objects have been deleted and space on the heap has been released.
To investigate what is currently allocated in the heap, we can use the heap dump button on the left. This will take a snapshot of what is currently allocated in the heap and display it in a special report screen in Android Studio:
On the left, we see a histogram of the instances in the heap, grouped by class name. For each, there are the number of objects allocated, the size of these instances (shallow size), and the size of these objects that are kept in memory. The latter tells us how much memory can be released if these instances are released. This view gives us an important understanding of the memory usage of the application and helps us identify large data structures and object relationships. This information can help us build more efficient data structures, untie object connections to reduce reserved resources, and ultimately reduce resource usage as much as possible.
Subsequently, we use a single layout file to construct the APK
to count the number of times the Android APK
Using Gradle
build an Android application requires only one AndroidManifest.xml
file. We can add a virtual layout.
.
├── build.gradle
└── src
└── main
├── AndroidManifest.xml
└── res
└── layout
└── home_view.xml
gradle assembleRelease
will produce a release version APK
only 2,118 bytes. We can use dump its content xxd
and find the byte sequence home_view
According to this output, there are 3 uncompressed paths and 1 uncompressed name only in the APK.
A zip file is a list of file items, followed by a list of all available items. Each entry contains the file path, and so does the directory. This shows the first occurrence (item title) and the last occurrence (listing record) in the output.
The middle two appearing in the output come from the resources.arsc
, which is a database for sorting resources. Its content is visible because the file is not compressed in the APK. Transport
aapt dump --values resources
build/outputs/apk/release/app-release-unsigned.apk
Display the home_view
record and its mapping to the path:
Package Groups (1)
Package Group 0 id=0x7f packageCount=1 name=com.example
Package 0 id=0x7f name=com.example
type 0 configCount=1 entryCount=1
spec resource 0x7f010000 com.example:layout/home_view: flags=0x0000000
config (default):
resource 0x7f010000 com.example:layout/home_view: t=0x03 d=0x0000000
(string8) "res/layout/home_view.xml"
The APK contains the name of the fifth occurrence in the file classes.dex
It is not shown in the xxd output because the file is compressed. Transport
baksmali dump <(unzip -p build/outputs/apk/release/app-release-unsigned.apk classes.dex)
Display the string table of the file dex
home_view
:
This is a field in the class used to map the R.layout
By the way, this integer is resources.arsc
database, which is used to find the relevant file name to read its XML content.
To summarize the answer to our question, for each resource file, the full path appears 3 times and the name appears twice.
optimized resources
Android Gradle plug-in 4.2 introduces a android.enable ResourceOptimizations=true
logo, which will perform resource optimization. This will aapt optimize
the merged resources and resources.arsc
files before they are packaged into the APK. Optimization only applies to the released version, minifyEnabled
set to true
or not, it will always run. After adding the logo, gradle.properties
we can use diffuse reflection to compare the two APKs to see the effect. The output is very long, so we will break it down by part.
The first is the difference in the content of APK
The "compressed" column is APK
, and the "uncompressed" column is the cost at the time of extraction.
The res category represents our single resource file, and its size has dropped by 28 bytes. The arsc category is used for resource.arsc
itself, obviously, this produces a certain optimization.
These two parts represent the code and content of the resource database. No change, we can infer that the optimization has no effectR.layout.home_view
field and home_view
resource entry.
Finally, the optimization effect is shown. The file name of our layout resource is obviously truncated and moved out of the layout/
file
folder.
In Gradle
item in the destination time, XML
folder and file names is significant. The folder is the resource type, and the name corresponds to the fields and resource entries generated in the .arsc
However, if these files are in the APK, the file path becomes meaningless. Resource optimization is optimized by making the name as short as possible.
The output aapt dump
resource database also reflects the file changes:
Package Groups (1)
Package Group 0 id=0x7f packageCount=1 name=com.example
Package 0 id=0x7f name=com.example
type 0 configCount=1 entryCount=1
spec resource 0x7f010000 com.example:layout/home_view: flags=0x0000000
config (default):
resource 0x7f010000 com.example:layout/home_view: t=0x03 d=0x0000000
(string8) "res/eA.xml"
All three occurrences of the path in the APK are now shorter, saving 36 bytes. Although 36 bytes is a very small number, the entire binary file is only 2,118 bytes. The 36 bytes saves 1.7% of resources.Nick Butcher
of Plaid
has 734 resource files.
In addition to the quantity, the names of the resource files are more descriptive (which means they are more peculiar). home_viewPlaid
contains the names searchback_stem_search_to_back.xml
, attrs_elastic_drag_dismiss_frame_layout
,
And designer_news_story_description.xml
.
Comparing the build without resource optimization and the build with it enabled:
resource optimization saves 0.76% of APK size.
Uwe Trottmann
of SeriesGuide
has 1044 resource files. Unlike Plaid
, it does not have a native library, which should make the optimization effect better. I updated the project to AGP 4.2 again and compared the two versions:
Here, resource optimization can reduce APK size by 2.0%!
Chris Banes' Tivi application has Jetpack Compose
written with 06182024123d73, which means fewer overall resources. The current build still contains 776 resource files.
By using Compose
, Tivi is already using the latest AGP 4.2. Through two quick builds, we can see the impact of resource optimization:
We once again reached the 2.0% reduction in APK size
APK signature
APK signature has multiple versions. If your version minSdkVersion
lower than 24, you need to include version V1 when signing. The V1 signature uses Java’s .jar
signature specification, which treats each file as a separate signature META-INF/MANIFEST.MF
in the file.
After creating and configuring the keystore for the original single-layout application, dump the manifest file
unzip -cbuild/outputs/apk/release/app-release.apk META-INF/MANIFEST.MF
The following signature is displayed:
Manifest-Version: 1.0
Built-By: Signflinger
Created-By: Android Gradle 4.2.0-alpha08
Name: AndroidManifest.xml
SHA-256-Digest: HdoGVd8U3Zjtf2VkGLExAPCQ1fq+kNL8eHKjVQXGI60=
Name: classes.dex
SHA-256-Digest: BVA1ApPvECg56DrrNPgD3jgv1edcM8VKYjcJEAG4G44=
Name: res/eA.xml
SHA-256-Digest: nDn7UQex2OWB3/AT054UvSAx9pYNSWwERCLfgdM6J6c=
Name: resources.arsc
SHA-256-Digest: 6w7i2Z9+LjwqlXS7YhhjzP/XhgvJF3PUuyJM60t0Qbw=
The complete path of each file appears, so that the total number of occurrences of each resource path reaches four times. Since a shorter name will again cause this file to contain fewer bytes, resource optimization has a greater impact in the signature.
According to data, this method can save 1-3% of APK size. According to actual tests, this range seems to be correct. The final cost savings will depend on the size and quantity of the resource files in the APK.
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。