preface

As the maximum memory of iphone13p is enlarged to 1T, the era of large memory phone is coming quietly. In android, Samsung also has it. Luo said a few years ago: if I told you that we are making a 1T phone, you might think I am crazy.

Look at the present, it is estimated that there will be more phones with 1T version in the future, people are starting to smell good.

But if someone says they’re going to build a 1TB app now, they’re probably crazy, at least not in the next decade. Because the bigger the memory, the better, your app is certainly as small as it can be

Android App file format is APK, this article is to explore for an Android APK, there are ways to reduce the size

An Apk

To reduce the volume, we first need to understand the composition of APK

  • Java files will be compiled into.class files and then compiled into classes. dex files by the dx tool. Due to android limitations, each dex file can have up to 65535 methods. So the extra methods generate classes2. dex, classes3. dex~ classesn. dex

  • Resource(res) is similar to Assets except that Resource ids are generated in the res directory. R file records, can be directly used, we usually use a lot here, and assets do not have ID, but through the AssetManager interface to obtain;

    So RES is like our desktop, which holds the control resources we want to manipulate, while Assets are like the drawer under the desk, which holds the database, HTML and so on

  • Native Libraries have little interaction and limited optimization space

Above is the abstract structure of APK, now let’s look at an actual one

Drag Q.apk into Android Studio

You can see the largest R folder, click in, there are some pictures, the second largest is assets, there are some emojis and plug-in pictures

And the other thing that we just talked about is that there’s a meta-INF in there

He stored the app’s signature information in

  • .mf: Each resource has an SHA1 signature and is stored here

  • .sf: file storage. MF Base64 encoded signature

  • The RSA: that’s right. The SF file uses the SHA1 algorithm to generate a digital summary (note: in.mf each resource is SHA1, in this case the file), then RSA encryption, signed with the developer private key, and decrypted with the public key at installation

This way, when an app is installed on the phone, it decrypts the digital summary and then works with the internal one. If the MF file matches, the resource content is not modified

Dex file

As can be seen from APK composition, res, assets and classs.dex files occupy the largest amount of memory, which is also our optimization direction. Next, let’s look at how to optimize dex

First let’s look at the structure of dex

A more detailed version is available on the official website, where you can see the detailed version below if you are interested in what these structures do

ProGuadrd

Dex is a compilation of code, and for code files, the most important optimization is obfuscation, method names, property names, etc., into short and meaningless names, not only to reduce the size of the decompilation to avoid cracking

In the IDE, we can see that the classes in QQ are all lowercase letters, and the variables and methods are arranged alphabetically, starting with a

In addition to changing variable names, ProGuadrd can also rewrite code based on functional equivalence, such as writing multiple function calls into a single function to make it more difficult to read (although beginners usually do this already), and messing with formatting and adding whitespace

The main steps are as follows

  • Shrink: Detects and deletes unused classes, fields, methods, and features.

  • Optimize: Analyze and Optimize Java bytecode.

  • Obfuscate: Rename classes, fields, and methods using short, meaningless names.

  • Preveirfy: Used to prevalidate Java classes (prevalidate is mainly for JME development, there is no prevalidate process in Android, it is turned off by default).

D8 and R8 optimization

They don’t have much contact with each other at ordinary times. They are mainly optimized in bytecode, and don’t have strong perception during development (feeling is used for interview).

D8 mainly resorts bytecodes when they are compiled, making the space footprint smaller, such as for the greetingType method, which normally results after compilation

[000584] Main.greetingType:(LGreeting;) Ljava/lang/String;0000: sget-object v0, LMain$1; .$SwitchMap$Greeting:[I0002: invoke-virtual {v2}, LGreeting; .ordinal:()I0005: move-result v1
0006: aget v0, v0, v1
0008: packed-switch v0, 00000017  / / here
Copy the code

If using D8 optimization, the compiled results

[0005f0] Main.greetingType:(LGreeting;) Ljava/lang/String;0000: sget-object v0, LMain$1; .$SwitchMap$Greeting:[I0002: invoke-virtual {v1}, LGreeting; .ordinal:()I0005: move-result v1
0006: aget v0, v0, v1
-0008: packed-switch v0, 00000017  / / here+ 0008:const/4 v1, #int 1+ 0009:if-eq v0, v1, 0014
+000b: const/4 v1, #int 2
+000c: if-eq v0, v1, 0017
Copy the code

It can be seen that several instructions after 0008 have changed, and there are several more if, which can save space to create different variables for different cases

R8 is similar, but with a different strategy

For more details, see D8 Optimizations

In short, they are used to rewrite some of the class instructions without changing the functionality, reducing the space footprint, but possibly increasing the number of instructions

Redex optimization

Redex is a tool developed by Facebook to optimize Dex files. Like D8R8, Redex is also a bytecode processing tool with the following effects

  1. Inline functions to reduce calls
  2. Delete useless code
  3. Replace an interface or superclass that has only one implementation class with an implementation class
  4. The string confuses what is seen

I haven’t used this before, but I feel that both Proguard and D8R8 are more or less able to do this, probably because they used better algorithms for details

But no matter how many frameworks, the optimization of dex files can only go so far

Remove redundant libraries and code

Finally, there are business logic reasons for removing third-party libraries and redundant code

  • Redundant library

    For small projects, fortunately, for large projects with multiple participants, it is likely that different people will use different wheels for the same function, such as Powermock, JMock, and Mockk, one project and three single test frameworks

    Since a number of monoprets have been written for different monoprets, it is unlikely to be removed for a short period of time, but it can be slowly converted to the same monoprets

  • Redundant code

    Android Studio will check for it itself, and if it’s not used, it will set a gray alert, but it will miss a lot. Lint can check for it by using plugin Lint.

Resources to clean up

The above is to reduce dex at the code level, another big space hog of APK, is resources, especially the images,

Picture, do you know, how many OOM because of you? How many apps are you canceling?

Image compression and replacement format

Let’s start with why is the picture so big

The default display mode is ARGB8888. ARGB8888 indicates that the color range of each channel is [0,255], that is, two hexadecimal numbers, that is, 8bit -> 1 byte

So in ARGB8888 mode, a pixel occupies 4 bytes in 4 channels, a 1024*1024 phone picture picture, is


2 10 2 10 2 2 = 2 22 = 4 M 2^{10} * 2^{10} * 2^2 = 2^{22} = 4M

A picture 4M, too outrageous!

We can change the color channel or ARGB565 to reduce the memory occupied by a single pixel. However, this is a bit off topic. We are talking about the size of the app, that is, the memory occupied by the phone (we agreed that the phone memory = computer memory, phone memory = computer hard disk).

There are different forms of images in memory and operation, and the compression method is different, so many people are easy to confuse

Back in memory, images are stored in PNG, JPG, etc

I used to compress PNG images into the Tinypng website before I developed them, so I can compress images by 1/3 to 2/3.

It is possible to change image formats, such as WebP, SVG can be smaller, and Android Studio provides support for this, but there is no best format, just different scenarios

:point_down:

Here much mention webp, because this is Google, everyone in the Google browser to download pictures, generally is the default download webp, so-called smaller memory footprint, is essentially a compressed images, webp compression algorithm is VP8 video coding, the core logic is divided into the picture smaller sub-block, Then predict the value of surrounding pixels. The more accurate the prediction is, the values of surrounding pixels can be deleted, and the deleted pixels can be calculated when the picture is opened

Picture networking

In wechat or QQ chat, when the other party sends us a picture, we often see a blurred thumbnail in the chat window first. When clicked, the hd image will be loaded.

This idea can also be used in APK. There is no need to build in APK for many large high-resolution images with deep entrance or pictures that need to be updated frequently. Maybe users don’t even look at them

As for which diagrams are networked, it’s a tradeoff between business and user experience

Taobao, for example, only icon is built in when it is opened when the Internet is disconnected

Other strategies

Although the optimization of Dex and resources is safe and effective, it essentially makes the original things smaller, and the weight loss of APK is limited. There are also some “seven injury boxing”, which have a very high optimization rate, but also have a great impact on APK, so it needs to be used with caution.

pluggable

The so-called plug-in is to turn non-major functions in APK into independent APK, and the original master APK is called the host.

For example, Alipay is engaged in payment, so his reputation, fund, Tmall a mess, at the same time, independent function of the thing is very suitable for plug-in, when users use from the network to load in, which greatly reduces the OCCUPATION of APK.

But there are more technical issues involved:

  1. The user now only has the host APK, how to get the host to load the code in the plug-in APK?
  2. Android’s four major components need to be registered in the manifest, plug-in components obviously can not be registered in advance in the host manifest (otherwise registered, plug-in did not load in, will not find the class), so how to let the system consider downloaded plug-in registered?
  3. Can host and plug-in resources reference each other correctly?

Generally, it is handled by proxy and reflection. Tencent has a shadow framework that can achieve roughly “zero reflection”.

  • Reuse independently installed App source code:
  • Zero reflection without Hack plug-in technology:
  • Full dynamic plug-in framework:
  • Host increments are minimal:
  • Kotlin implementation:

However, plug-in technology is beyond the scope of today’s discussion. If you are interested, please check out The Tencent – Shadow

When plug-ins are used, the project basically needs to be reconstructed. Compared with changing Dex and images, this project is a huge amount of work, but the benefits will be very high

webview

It’s kind of like image networking, where you turn the whole interface into a URL,

The small program in our mobile app is usually the URL displayed in the WebView

Related technologies can use jsBridge and Hybird, essentially connecting H5 to Android iOS through bridge to achieve communication

The tradeoff, however, is slower loading than native, and attention to prevent url tampering, etc

summary

In this paper, we discuss apK slimming scheme, first of all, the main components of APK are dex file and resource file

  • For dex files, we can obfuscate, bytecode reorder, and remove redundant libraries and code

  • For resource files, we can replace formats, compress images, network

In addition to these general operations, we can use plug-in and Webview methods to minimize the volume, but these two techniques have a lot of engineering and performance costs and should be used with caution.

My name is Komatsu, focusing on computer and Android development, if interested, you can follow a wave of [Komatsu Walk] public account, collected a lot of e-books to share for free, thank you for your support!

The resources

Exploring Android Package Volume Optimization

Resource files in the Android project – asset directory and res directory

Top image App reinforcement technology analysis: DEX file format details

D8 Optimizations

Android Development should master Proguard skills