Project address: github.com/didi/booste…

Introduction to the

Booster is an easy-to-use, lightweight, and extensible quality optimization framework for mobile applications. It is designed to address the performance, stability, and package size issues that come with increasing APP complexity.

Why Booster?

Quality optimization is a problem all APP developers have to face. For apps with tens of millions of DAU, a crash rate of one in ten thousand means thousands of users will be affected. For drivers who are online for a long time, the stability of driver-side APP is related to the safety and income of drivers, so it should not be underestimated.

With the rapid development of business and the increasing complexity of business, we began to think:

  1. How do I keep the quality of my APP?
  2. When the APP crashes, how can I quickly locate the fault line?
  3. Can potential quality problems be identified in advance before launch?
  4. Is it possible to optimize the APP globally without intruding without pushing the lines of business?

Based on these considerations, Booster was born. After more than a year of continuous improvement, Booster has made remarkable achievements. At present, there are only a few open source projects based on static analysis in terms of quality optimization, and the threshold of quality optimization is high for APP developers. Therefore, we choose Booster, hoping that more developers and users can benefit from it.

Functions and Features

Dynamic loading module

To support differentiated optimization requirements, Booster implements dynamic loading of modules, so that developers can choose to use the specified modules without using configuration. See booster-task-all and booster-transform-all.

Third-party library injection

Booster may need to inject specific classes or libraries during optimization. In order to solve the dependency management problem of injected classes, Booster provides VariantProcessor SPI for easy extension. For details, see: ThreadVariantProcessor.kt#L12

Performance testing

APP lag rate is an important indicator of application runtime performance. In order to detect potential lag problems in advance, Booster implements performance detection through static analysis and generates visual reports to help developers locate the problems, as shown in the figure below:

This is done by analyzing all class files, building a global Call Graph, and then identifying the links (Application, four components, View, Widget, etc.) that are called in the main thread from the Call Graph. These links are then reported separately by class.

See booster-transform-lint for details.

Multithreading optimization

Business line of APP common thread overload problem, and thread management has always been one of the biggest headaches in developers, although can through strict code specification come to avoid such problems happen, but for large complex structure, implement cost, for the third party SDK, code specification is restrictive. To solve this problem completely, Booster implements global thread pool optimization and renames the thread by modifying the bytecode during compilation.

Here is the sample code:

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?). {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        getSharedPreferences("demo", MODE_PRIVATE).edit().commit()
    }

    override fun onStart(a) {
        super.onStart()
        Thread({
            while (true) {
                Thread.sleep(5)}},"#Booster").start()
    }

    override fun onResume(a) {
        super.onResume()
        HandlerThread("Booster").start()
    }
}
Copy the code

The thread renaming effect is shown below:

For details, see booster-transform-thread.

SharedPreferences optimization

For Android developers, SharedPreferences are ubiquitous. Modifying SharedPreferences in the main thread can cause backwardness or even ANR. To solve this problem, Booster replaces the instructions in the APP globally.

For details, see booster-transform-shared-preferences.

Constant field deletion

Whether resource index, or other constant field, upon the completion of the compilation, there is no value of the existence of the except (reflection), therefore, Booster to resource index field access instructions for constant, the other constant field is removed from the class, on the one hand can improve runtime performance, on the other hand, also can reduce the package size, Resource index (R) looks trivial on the surface, but actually takes up a lot of space. Take Didi Car owner as an example, there are thousands of classes related to resource index. After constant field deletion, it is reduced by about 1MB.

For details, see booster-transform-shrink.

Toast Bug fixes

Booster replaces the toas.show () method call instruction in the APP globally to solve the bug 30150688 in Android 7.1.

See booster-transform-toast for details.

Resources compression

In APP installation, image resources account for a large proportion. Normally, a 10%-20% reduction in image quality does not affect the visual effect. Therefore, Booster uses lossy compression to reduce the image size. Less memory.

Booster provides two compression schemes:

  1. pngquantLossy compression (need to install yourselfpngquantCommand line tools)
  2. cwebpLossy compression (built in)

The two schemes have their own advantages and disadvantages. Pngquant’s scheme does not have compatibility problems, but its compression rate is slightly lower than WebP, while WebP has compatibility problems with system versions. Generally speaking, the effect of lossy compression is very significant.

In addition, for example, the Android Support Library contains a large number of image resources, and supports a variety of screen sizes. For the APP, the same image resources, the largest size can be reserved. Taking the Android Support Library as an example, the APP package size is reduced by about 1MB after redundancy is removed.

For details, see booster-task-compression.

The WebView preload

To solve the lag caused by WebView initialization, Booster uses an injection command to load the WebView in advance when the main thread is idle.

In addition to the above features, Booster also provides several development assistance features, such as checking whether a dependency contains a SNAPSHOT version.

Quick start

Introduce the Booster plug-in in buildScript’s classpath and then enable it:

buildscript {
    ext.booster_version = '0.4.3'
    repositories {
        google()
        mavenCentral()
        jcenter()
    }
    dependencies {
        classpath "com.didiglobal.booster:booster-gradle-plugin:$booster_version"
        classpath "com.didiglobal.booster:booster-task-all:$booster_version"
        classpath "com.didiglobal.booster:booster-transform-all:$booster_version"
    }
}

apply plugin: 'com.android.application'
apply plugin: 'com.didiglobal.booster'
Copy the code

Assemble Task is then executed to build an optimized application package:

$ ./gradlew assembleRelease
Copy the code

After the build is complete, the corresponding report will be generated in the build/reports/ directory:

Build /reports/ Exercises ─ booster-task-press │ ├─ ├─ press │ ├─ build/reports/ Exercises ─ booster-task-press │ ├─ press │ ├─ press ├ ─ ─ com │ └ ─ ─ org ├ ─ ─ booster - transform - Shared - preferences │ └ ─ ─ release │ └ ─ ─ the report. TXT ├ ─ ─ booster - transform - shrink │ ├─ uninhibited.txt TXT TXT TXT TXT TXT TXT TXT TXT TXT TXT TXT TXT TXT TXT TXT └ ─ ─ release └ ─ ─ the report. TXTCopy the code