Everyone, can you give me a star for my project or my previous article? It’s so bitter. Github.com Nuggets article

Interviewer: Oh, uncle, here we go again.

Me: Emmmmm, I came to kill the dragon today.

Interviewer: Courageous, so let’s talk about the Android compilation process.

I: eat me a recruit day hit thunder chop dragon.

It’s time to show some real technique

Normally, the compilation process starts with the following figure.

  1. Package res resource files with AAPT to generate R.Java, resources.arsc and RES files (binary & non-binary such as RES/RAW and PIC remain unchanged);
  2. Process.aidl files and generate corresponding Java interface files;
  3. R.java, Java interface files and Java source files were compiled with Java Compiler to generate.class files.
  4. Using the dex command, you can generate classes.dex by processing.class files and.class files in third-party libraries.
  5. Arsc, RES files, assets files and classes.dex files generated by AAPT are packaged together to generate APK using apkBuilder.
  6. Use the Jarsigner tool to debug or release the above APK;
  7. Use zipalign to align the signed APK.

Well, it looks like we’ve already answered that question, but we’re here to slay dragons, so we can’t just let it go.

See the compilation process from Gradle Task

Start with a code that tells you how long it takes for Gradle to print a task

  1. The project root directory build.gradle is opened
  2. Add the following code

import java.util.concurrent.TimeUnit
// Log timings per task.
class TimingsListener implements TaskExecutionListener, BuildListener {
    private long startTime
    private timings = []

    @Override
    void beforeExecute(Task task) {
        startTime = System.nanoTime()
    }

    @Override
    void afterExecute(Task task, TaskState taskState) {
        def ms = TimeUnit.MILLISECONDS.convert(System.nanoTime() - startTime, TimeUnit.NANOSECONDS);
        timings.add([ms, task.path])
        task.project.logger.warn "${task.path} took ${ms}ms"
    }

    @Override
    void buildFinished(BuildResult result) {
        println "Task timings:"
        for (timing in timings) {
            if (timing[0] > =50) {
                printf "%7sms %s\n", timing
            }
        }
    }

    @Override
    void buildStarted(Gradle gradle) {}

    @Override
    void projectsEvaluated(Gradle gradle) {}

    @Override
    void projectsLoaded(Gradle gradle) {}

    @Override
    void settingsEvaluated(Settings settings) {}
}

gradle.addListener new TimingsListener()
Copy the code

When the project has finished running, a log similar to the following is output, which represents the time and name of the task executed by Gradle after a run.

  1543ms  :compiler:kaptGenerateStubsKotlin
    144ms  :RouterLib:packageDebugResources
   1166ms  :compiler:kaptKotlin
    816ms  :compiler:compileKotlin
    401ms  :compiler:compileJava
     65ms  :compiler:jar
    122ms  :app:mergeDebugResources
     56ms  :EmptyLoader:compileJava
    170ms  :app:processDebugManifest
    171ms  :RouterLib:parseDebugLocalResources
     60ms  :app:checkDebugDuplicateClasses
   2416ms  :RouterLib:compileDebugKotlin
    122ms  :RouterLib:compileDebugJavaWithJavac
    124ms  :secondmoudle:mergeDebugNativeLibs
   1185ms  :app:processDebugResources
     70ms  :secondmoudle:kaptGenerateStubsDebugKotlin
    202ms  :RouterLib:mergeDebugNativeLibs
    350ms  :secondmoudle:kaptDebugKotlin
    158ms  :secondmoudle:compileDebugJavaWithJavac
   1108ms  :app:kaptGenerateStubsDebugKotlin
     91ms  :secondmoudle:bundleLibRuntimeToJarDebug
    129ms  :app:mergeDebugNativeLibs
    430ms  :app:kaptDebugKotlin
   1008ms  :app:compileDebugKotlin
    120ms  :app:compileDebugJavaWithJavac
    265ms  :app:mergeDebugJavaResource
    181ms  :app:transformClassesAndResourcesWithAuto_registerForDebug
   7262ms  :app:dexBuilderDebug
   1308ms  :app:mergeProjectDexDebug
    344ms  :app:packageDebug
Copy the code

As you can see from the list of tasks above, the compilation process described in the top diagram is not complete.

Kapt and apt

My previous article said, executed before javaCompiler apt, generate Java code, and the task name is kaptGenerateStubsDebugKotlin.

Talk about AbstractProcessor and Java compilation processes

Compiler is mixed in with something strange

Kotlin has been introduced in many versions, but kotlin’s Compiler is actually different from Java’s.

If you follow the standard answer to this question, it will feel like there is something missing, so the one point we need to add is compileDebugKotlin.

And of course transform

When we use the bytecode in pile after actually increases the transform process, namely the transformClassesAndResourcesWithAuto_registerForDebug.

Is there anything else to add?

AGP varies greatly among different versions. Especially since versions above 3.2 were introduced into the D8 compiler.

The lower version first uses the DX compiler to convert the class to dex.

The older version uses the D8 compiler to convert class to dex.

What does Desugar do?

Android Studio provides built-in support for using some of the Java 8 language features and third-party libraries that take advantage of them. The default toolchain performs bytecode conversion (called desugar) on the output of the JavAC compiler to implement the new language functionality.

But in the end, Dex doesn’t know who you are.

So what’s the advantage of the D8??

Not much to say.

You can see that D8 has significantly improved the compilation speed and the size of the compiled files.

What about confusion??

Take a look at the original diagram and see if there is less confusion in the process!!

R8, or obfuscation upgrade, was introduced on AGP3.4. And on the higher version, the overall process has actually changed subtly, merging the original process.

  1. R8 before the start of the compilation process

  1. R8 after enabling the compilation process

As an aside, R8 eats more memory, so be careful.

About the signature

What I wrote before is a little bit missing. Google has an official explanation. Here is a quote

Note: You must use Zipalign at one of two specific points in the application build process, depending on which application signing tool you use:

If you are using apkSigner, you can only perform zipalign before signing the APK file. If you make further changes to the APK after using apkSigner to sign the APK, the signature is invalidated.

If you are using Jarsigner, you can only perform zipalign after signing the APK file.

The link address

So when V1 signature is used, the compilation process sequence is still 6-7

When V2 signatures are used, the compilation process is 7-6

The end of the

I don’t really have anything to say. I just want to do a handstand for you guys. Give me a thumbs up if you think it’s okay. If any of you are unlucky enough to be asked the same question again, you can come here and make a note.