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 effect
R.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.


六一
556 声望347 粉丝

SegmentFault 新媒体运营