Android performance optimization series apk slimming

Why APK needs to be slimmed down. The larger the APK, the more traffic they will consume during the download and installation process, and the longer the installation waiting time will be; for the product itself, it means that the download conversion rate will be lower (because users have more opportunities to choose among competing products) Which one has the best experience, the most functions, the best performance, and the smallest package), so the optimization of apk slimming is also very important. This blog will talk about the relevant content of apk slimming.

Inclusion analysis

In the Android Studio toolbar, open build–>Analyze APK and select the APK package to be analyzed.

Write picture description here

It can be seen that the space occupied is mainly code, pictures, resources and lib and assert files. The main directions are to streamline code, compress pictures, remove useless libraries, and reduce files in asserts.

Use a set of resources

For the vast majority of apps, just a set of design drawings is enough. In view of the current trend of resolution, it is recommended to take 720p resources and put them in the xhdpi directory. Compared with multiple sets of resources, using only one set of 720P resources has little visual difference. The same is true for the products of many large companies, but it can significantly reduce the size of the resource occupied and also reduce the designer’s drawing workload. . Note that this does not mean to delete all directories that are not xhdpi, but to emphasize that retaining a set of design resources is enough.

Turn on minifyEnabled obfuscated code

Using minifyEnabled in gradle to configure Proguard obfuscation can greatly reduce the size of the APP:

android {<!-- -->
    buildTypes {<!-- -->
        release {<!-- -->
            minifyEnabled true
        }
    }
}

In proguard, whether to retain the symbol table has a significant impact on the size of the APP. You can not retain it as appropriate, but it is recommended to retain it for debugging as much as possible.

parameter:

-include {<!-- -->filename} Read configuration parameters from the given file
-basedirectory {<!-- -->directoryname} specifies the base directory as the relative file name in the future
-injars {<!-- -->class_path} specifies the application jar, war, ear and directory to be processed
-outjars {<!-- -->class_path} specifies the name of the jar, war, ear and directory to be output after processing.
-libraryjars {<!-- -->classpath} specifies the library files required by the application jar, war, ear and directory to be processed
-dontskipnonpubliclibraryclasses specifies not to ignore non-public library classes.
-dontskipnonpubliclibraryclassmembers Specifies not to ignore members of package-visible library classes.

Keep options

-keep {<!-- -->Modifier} {<!-- -->class_specification} protects the specified class file and class members
-keepclassmembers {<!-- -->modifier} {<!-- -->class_specification} Protect members of the specified class. They will be better protected if this class is protected.
-keepclasseswithmembers {<!-- -->class_specification} Protect the specified classes and class members, but only if all specified classes and class members exist.
-keepnames {<!-- -->class_specification} protect the names of the specified classes and class members (if they will not be removed during the compression step)
-keepclassmembernames {<!-- -->class_specification} Keep the member names of the specified classes (if they will not be removed during the compression step)
-keepclasseswithmembernames {<!-- -->class_specification} Protect the names of the specified classes and members of the class if all specified class members are present (after the compression step)
-printseeds {<!-- -->filename} List the class and its members -keep option, standard output to the given file

compression

-dontshrink does not compress input class files
-printusage {<!-- -->filename}
-whyareyoukeeping {<!-- -->class_specification}

optimization

-dontoptimize does not optimize the input class file
-assumenosideeffects {<!-- -->class_specification} Assume the specified method when optimizing, without any side effects
-allowaccessmodification allows access and modification of modified classes and class members during optimization

Confuse

-dontobfuscate does not obfuscate input class files
-printmapping {<!-- -->filename}
-applymapping {<!-- -->filename} reuses mappings to increase confusion
-obfuscationdictionary {<!-- -->filename} Use keywords from the given file as the name of the method to be obfuscated
-overloadaggressively applies intrusive reloading when obfuscating
-useuniqueclassmembernames determines the member names of unified obfuscated classes to increase confusion
-flattenpackagehierarchy {<!-- -->package_name} Repackage all renamed packages into the given single package
-repackageclass {<!-- -->package_name} Repackage all renamed class files into the given single package
-dontusemixedcaseclassnames will not produce a variety of class names when confusing
-keepattributes {<!-- -->attribute_name,...} protects the given optional attributes, such as LineNumberTable, LocalVariableTable, SourceFile, Deprecated, Synthetic, Signature, and InnerClasses.
-renamesourcefileattribute {<!-- -->string} sets the string constant given in the source file

Enable shrinkResources to remove useless resources

Use shrinkResources in gradle to remove useless resources, the effect is very good.

android {<!-- -->
    buildTypes {<!-- -->
        release {<!-- -->
            shrinkResources true
        }
    }
}

Clean up useless resources

During the version iteration process, not only will there be redundant abandoned code, there will definitely be useless images. Configuring shrinkResources true in build.gradle will automatically clear out useless resources when packaging. However, after experiments, it was found that the package will not, but will replace some useless resources with smaller things. Note that “useless” here means that all parent functions that call the image are ultimately discarded code, and shrinkResources true can only remove the situation where there is no parent function call. The real effect can only be achieved through the “Remove Unused Resources” that comes with Android Studio. “The small plug-in is implemented, directly as shown in the picture.

Write picture description here

What is more user-friendly is that the search results can be deleted with one click. Of course, the pictures may be obtained through reflection or character splicing, so this detection list is not completely correct. After deletion, there is a high probability that the compilation will fail or some pages will hang or have no pictures. There is no solution to this problem, and the tool is not smart enough yet. At this point, you can only “compile – solve some problems – compile and then” over and over again. Don’t ask me why I know.

Delete useless language resources

Most applications don’t actually need international support for dozens of languages. Fortunately, the powerful gradle supports language configuration. For example, domestic applications only support Chinese:

android {<!-- -->
    defaultConfig {<!-- -->
        resConfigs "zh"
    }
}

Use tinypng lossy compression

The TinyPNG tool only supports uploading PNG images to the official website for compression, and then downloading and saving them. The compression of PNGs can be within 1/3 while maintaining the alpha channel, and the compression loss is basically invisible to the naked eye. Tinypng official Website: http://tinypng.com/

Use jpg format

For non-transparent large images, jpg will have a significant advantage over png in size. Although not absolute, it will usually be reduced to more than half. It would be a very wise choice to use jpg in large picture display areas such as startup pages, activity pages, etc.

Use webp format

webp supports transparency. The compression ratio is higher than jpg but the display effect is not inferior to jpg. The official evaluation quality parameter is equal to 75, which is the best balance. Compared with jpg and png, webp is a new image format. It is limited to the support of android and has not yet been widely used on mobile phones. It is natively supported starting from Android 4.0+, but does not support transparency. It is not until Android 4.2.1+ that the display of webp with transparency is supported. Pay special attention when using it. Official introduction: https://developers.google.com/speed/webp/docs/precompiled

Zoom out the image

If after going through the above steps, you still have some large pictures in your project, consider whether it is necessary to maintain such a large size and whether it can be appropriately reduced. In fact, due to the designer’s drawings, many of the pictures we got can be appropriately reduced with minimal visual impact.

Large picture covering the third library

Some third-party libraries reference some large images but they will not actually be used by us, so we can consider covering them with 1×1 transparent images. You may be a little uncomfortable because your drawable contains some 1×1 images with inexplicable names…

Delete so under the armable-v7 package

Basically armable’s so is also compatible with armable-v7. The armable-v7a library will greatly improve graphics rendering. If there are no requirements in this regard, it can be streamlined. It is not ruled out that a very small number of devices will crash, which may be related to different SOs. Please be sure to test thoroughly before releasing.

Delete so under x86 package

Different from Article 10, the so under the x86 package is required for x86 model mobile phones. If the product is not used, this requirement can be streamlined. It is recommended that the actual working configuration is to only retain the so files under armable and armable-x86, which is a compromise.

Use WeChat resource compression and packaging tool

The WeChat resource compression and packaging tool uses short resource names and uses 7zip to compress the APP to the extreme to achieve the goal of reducing the size of the APP. The effect is very good and is highly recommended.

It is recommended to enable 7zip and pay attention to the configuration of the whitelist, otherwise some resources will not be found. The official has released AndResGuard into gradle, which is very convenient:

apply plugin: 'AndResGuard'
buildscript {<!-- -->
    dependencies {<!-- -->
        classpath 'com.tencent.mm:AndResGuard-gradle-plugin:1.1.7'
    }
}
andResGuard {<!-- -->
    mappingFile = null
    use7zip=true
    useSign = true
    keepRoot = false
    // add <your_application_id>.R.drawable.icon into whitelist.
    // because the launcher will get thgge icon with his name
    def packageName = <your_application_id>
            whiteList = [
    //for your icon
    packageName + ".R.drawable.icon",
            //for fabric
            packageName + ".R.string.com.crashlytics.*",
            //for umeng update
            packageName + ".R.string.umeng*",
            packageName + ".R.string.UM*",
            packageName + ".R.string.tb_*",
            packageName + ".R.layout.umeng*",
            packageName + ".R.layout.tb_*",
            packageName + ".R.drawable.umeng*",
            packageName + ".R.drawable.tb_*",
            packageName + ".R.anim.umeng*",
            packageName + ".R.color.umeng*",
            packageName + ".R.color.tb_*",
            packageName + ".R.style.*UM*",
            packageName + ".R.style.umeng*",
            packageName + ".R.id.umeng*"
    ]
    compressFilePattern = [
    "*.png",
            "*.jpg",
            "*.jpeg",
            "*.gif",
            "resources.arsc"
    ]
    sevenzip {<!-- -->
        artifact = 'com.tencent.mm:SevenZip:1.1.7'
        //path = "/usr/local/bin/7za"
    }
}

An andresguard/resguard Task will be generated, and the release signature will be automatically read for re-obfuscation and packaging.

Compile using provided

Some libraries are dynamically loaded as needed, which may not be needed in some versions, but the code is inconvenient to remove otherwise it will fail to compile. Using provided can ensure that the code is compiled successfully, but this third-party library is not referenced in the actual packaging, achieving the goal of controlling the size of the APP. But at the same time, developers need to judge by themselves not to execute the relevant code when not referencing this third-party library to avoid APP crashes.

Vector graphics

Vector graphics are composed of points and lines. Unlike bitmaps, they can maintain clarity no matter how much they are enlarged. Moreover, using vector graphics can save 30 to 40% of space compared to bitmap design. Now Google has been emphasizing the flattening method. , vector graphics can fit this design concept well. -Advantages (1) Small storage space occupied (2) Continuous stretching will not cause aliasing and can take care of models of different sizes (3) Android Studio comes with a lot of resources to reduce the UI workload-Disadvantages (1) Only supports 5.0 and above systems (2) Compared with bitmaps, it has an extra layer of calculation and requires more performance (3) Not supported. 9 pictures (4) are not suitable for showing real photos and complex graphics, and are generally used in simple icons and animations superior

Use shape background

Especially now that flatness is prevalent, many solid-color, gradient, and rounded-corner images can be realized using shape. The code is flexible and controllable, eliminating the need for a large number of background images.

Use a coloring scheme

I believe there are many selector files in your project, and there are also many similar pictures with different colors. Through the coloring scheme, we can greatly reduce the workload and reduce the number of such files. A fully version-compatible coloring scheme can be implemented with the help of the android support library, reference code: DrawableLess.java

Online material library

If your APP supports a material library (such as a chat emoticon library), consider the online loading mode, because the material library is often quite large. This step requires developers to implement online loading. On the one hand, it increases the complexity of the code, and on the other hand, it increases the traffic consumption of the APP. It is recommended to choose accordingly.

Avoid duplicate libraries

It seems natural to avoid duplicating libraries, but the secret is always hidden deep. You must be careful about which third-party library you reference and which third-party library it references. This makes it easy to have libraries with duplicate functions, such as using two libraries. Image loading libraries: Glide and Picasso. By checking the exploded-aar directory and External Libraries or the APK generated by decompilation, try to avoid duplicating the size of the library and reduce the size of the APP.

Clean up third-party libraries and redundant code

During the version iteration process, because deletion functions often leave redundant code and third-party libraries behind, this will more or less increase the package body. There is no shortcut in this case, and you can only search for each file, which is a hard job. It is also necessary to check whether it is possible to streamline third-party libraries, such as Google’s basic, advertising and analysis packages, network libraries, supportv4, etc. This will be analyzed in detail on the specific situation and will not be elaborated on.

Support plug-in

Plug-in technology supports dynamic loading of code and dynamic loading of resources, which separates part of the APP. It is very useful for projects with huge business and greatly reduces the size of the APP. Because plug-in technology requires certain technical guarantees and server system support, there are certain risks. If it is not necessary (such as some small projects and there is no business expansion), it is not necessary. It is recommended to choose it as appropriate.

Facebook’s redex optimized bytecode

Redex is an Android bytecode optimization tool released by Facebook. You need to configure it yourself according to the documentation.

redex input.apk -o output.apk --sign -s <KEYSTORE> -a <KEYALIAS> -p <KEYPASS>

Let’s take a look at its effect. If only redex is used, it is reduced by 157k:

Write picture description here

Let’s take a look at its effect. If only redex is used, it is reduced by 157k:

Write picture description here

If wechat obfuscation is performed first, and then redex is reduced, the reduction is 565k, and redex only contributes 10k:

Write picture description here

If redex is performed first, and then WeChat obfuscation is performed, the reduction is 711k, and redex contributes 157k:

Write picture description here

The last one has the best effect, which is easy to explain. If the last repackage is redex, the previous 7zip compression will be wasted, so for the best effect, pay attention to the order. In addition, it is reported that there will be a crash after redex. Please pay attention to this. I can run normally after compression here.

For more Android advanced guides, you can Scan the code to unlock “Android Ten Major Section Documents”

1. Android vehicle application development system study guide (with actual project practice)

2. Android Framework study guide to help you become a system-level development expert

3.2023 Latest Android Intermediate and Advanced Interview Questions Summary + Analysis, Say Goodbye to Zero Offers

4. Enterprise-level Android audio and video development learning route + project practice (with source code)

5. Android Jetpack builds high-quality UI interfaces from entry to proficiency

6. Flutter technology analysis and practical implementation, the first choice for cross-platform

7. Kotlin improves the architectural foundation in all aspects from entry to actual use

8. Advanced Android plug-in and componentization (including practical tutorials and source code)

9. Android performance optimization practice + 360° all-round performance tuning

10. Android from beginner to proficient, the path to advancement for experts

It’s not easy to code, so pay attention. ?( ′?` )