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.
- 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);
- Process.aidl files and generate corresponding Java interface files;
- R.java, Java interface files and Java source files were compiled with Java Compiler to generate.class files.
- Using the dex command, you can generate classes.dex by processing.class files and.class files in third-party libraries.
- Arsc, RES files, assets files and classes.dex files generated by AAPT are packaged together to generate APK using apkBuilder.
- Use the Jarsigner tool to debug or release the above APK;
- 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
- The project root directory build.gradle is opened
- 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.
- R8 before the start of the compilation process
- 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.