How to build APK cleverly? If you haven't understood the principle yet, you can read this

Overview

The APK building process involves many tools and processes for converting a project into an Android application package (APK). The build process is very flexible, so it’s helpful to understand some of its underlying working principles.

The detailed APK construction process is a bit more complicated. This article will be divided into four steps, from the shallower to the deeper, with readers in-depth analysis of the construction process.

  • The first step: see the build
  • Step 2: Revisit the construction
  • Step 3: Build in depth
  • Step 4: Give up building

First sight build

First of all " see the construction ", in this step, we can ignore the details of the construction, and first have a general understanding of the main process.

As shown in the figure above ( square : indicates file, diamond : indicates operation):

1, the entire construct is divided into two main operations: compiling (the Compile), packing (APK Package)

2. Compiler : The Compiler compiles the source code, AIDL file, resource file, and dependency package, and finally generates Dex file and compiled resource file.

3. Packaging : The packager (APK Packager) uses the signature file (KeyStore), the Dex file generated in the previous compilation process, and the compiled resource file to package into the final APK file.

Revisit construction

In the previous step of " First Seeing Build ", we have a general understanding of the APK packaging process, and let's get a little more detailed.

( Square : indicates file, ellipse : indicates tool and operation)

The picture above shows a more detailed construction process. Bounded by a broken line, the first part describes the compiling process , described in the latter part of the packaging process .

The following detailed analysis of the build flow is divided into seven steps (compilation 1-4, packaging 5-7):

    1. Use the aapt tool to compile the res/file and generate the compiled binary resource file (.ap_ file) and R.java file. (Currently, the new version uses the aapt2 tool, and R.java has also been replaced with R.jar)

    2. Use aidl tool to generate corresponding Java interface file according to aidl file

    3. Use the Java Compiler tool, Java Compiler (commonly known as javac) to compile R.java, the code in the project, and the Aidl interface file into a .class file.

    4. Use the dex tool to compile the .class file generated in the previous step and the .class in the third-party dependencies into a .dex file. (Currently the new version uses d8 tool)

    5. Use the apkbuilder tool to compress the compiled resources (.ap_ files), dex files and other resource files (such as so files, asset files, etc.) into an .apk file.

    6. Use the Jarsigner tool to read the signature file, sign the apk file generated in the previous step, and generate a signed apk file.

    7. Use the zipalign tool to optimize the volume of the signed apk file (this step is only available for the v1 signature, and the v2 signed apk will be damaged after zipalign).

Let's rest for 3 minutes and digest.

Build in depth

Ready to go deep into the construction process. The picture looks complicated, but there are picture-reading skills:

We can interpret this flowchart by referring to the pictures shown in " Revisiting Construction ".

Take the ellipse (tools and operations) as a clue and follow the construction process described earlier to understand this diagram. Aapt, aidl, javac, dex, apkbuilder Jarsigner, zipalign are familiar? The big block on the left is about Render Script and ndk compilation, we can ignore it for the time being (I believe you can analyze it yourself if you don’t ignore it after reading this article), just know that it provides .so files and parts Java files.

First, look at the lower left corner. The ellipse operations are divided into three types: Gradle plugin provided (completed by task), Build tool provided , JDK comes with

Take aapt as an example, in-depth analysis of a more detailed construction process:

    Before aapt, various Merge tasks in the Gradle plug-in will merge Manifest, Res, and Assets. These merged resources may come from third parties such as internal projects, android.jar, and arr. These merged files are used as input files. After appt is compiled, the compiled resource files, R.java files, and aapt is also responsible for merging various obfuscated files.

    In addition, there is a proguard (obfuscation) between javac and dex operations. Proguard reads the .class file, generates the obfuscated .class file, and gives it to dex (or d8).

Give up building

Very powerful, your understanding of the Android build process has surpassed most developers (I guess :-)).

But it's still a bit far from practice. Think about how gradle implements the above-mentioned build process when we click to run? When we run the assembleReleasecommand to pack, huh? What is this string? Facing the above analysis process, you will know what it is.

Interpretation version:

//以下两个task是预编译工作,暂不关心
> Task :app:preBuild UP-TO-DATE
> Task :app:preReleaseBuild UP-TO-DATE

//aidl编译
> Task :app:compileReleaseAidl NO-SOURCE

//生成BuildConfig文件
> Task :app:generateReleaseBuildConfig

//编译Renderscrip,暂不关心(感兴趣的可以去探究Renderscrip)
> Task :app:compileReleaseRenderscript NO-SOURCE
//*
> Task :app:javaPreCompileRelease

//生成资源文件并合并
> Task :app:generateReleaseResValues
> Task :app:generateReleaseResources
> Task :app:createReleaseCompatibleScreenManifests
> Task :app:extractDeepLinksRelease
> Task :app:processReleaseManifest
> Task :app:prepareLintJar UP-TO-DATE
> Task :app:checkReleaseDuplicateClasses
> Task :app:desugarReleaseFileDependencies
> Task :app:mergeReleaseResources

//产生build/intermediates/compile_and_runtime_not_namespaced_r_class_jar/release/R.jar文件
> Task :app:processReleaseResources

//javac将java编译成Class文件
> Task :app:compileReleaseJavaWithJavac

//将资源文件编译并生成resource.arsc文件,并放入.ap_文件中(./app/build/intermediates/processed_res/release/out/resources-release.ap_)
> Task :app:compileReleaseSources

> Task :app:lintVitalRelease

//dex工具将.class文件编程传.dex文件
> Task :app:dexBuilderRelease

//合并非res/的资源文件及assets文件
> Task :app:mergeExtDexRelease
> Task :app:mergeReleaseShaders
> Task :app:compileReleaseShaders NO-SOURCE
> Task :app:generateReleaseAssets UP-TO-DATE
> Task :app:mergeReleaseAssets
> Task :app:processReleaseJavaRes NO-SOURCE
> Task :app:collectReleaseDependencies
> Task :app:sdkReleaseDependencyData
> Task :app:mergeReleaseJniLibFolders
> Task :app:mergeReleaseNativeLibs
> Task :app:stripReleaseDebugSymbols NO-SOURCE
> Task :app:mergeReleaseJavaResource

//合并.dex文件
> Task :app:mergeDexRelease

//将.dex文件、.ap_打包进以及非res资源文件打包进.apk文件中并签名
> Task :app:packageRelease

使用zipalign对apk进行体积优化
> Task :app:assembleRelease

It is said that " abandon construction ", why haven't you given up? We learned that the build process, now give up automated build apk, use the manual to build apk. Proceed as follows:

    1. Compile the res resource files in the project (except assets), generate corresponding binary resource files, and pack these binary files into the res.zip file

$aapt2 compile -o build/res.zip --dir ./app/src/main/res

    2. Connect the res.zip file with the SDK to generate .ap_ files (including compiled resource files, manifest files, and arsc files) and R.java files,

$aapt2 link build/res.zip -I $ANDROID_HOME/platforms/android-21/android.jar --java build --manifest ./app/src/main/AndroidManifest.xml -o build/app-debug.ap_

    3. Compile java files into .class files

$javac -d build -cp $ANDROID_HOME/platforms/android-21/android.jar com/*/.java

    4. Compile the .class file generated in the previous step into a .dex file

$d8 --output build/ --lib $ANDROID_HOME/platforms/android-21/android.jar build/com/example/application/*.class

    5. Use the zip command to package the .ap_ resource file in step (2) and the .dex file in step (4) into an unsigned apk

$zip -j build/app-debug.ap_ build/classes.dex

    6. Modify .ap_ to .apk and use apksigner to sign the apk

$apksign -ks ~/.android/debug.keystore build/app-debug.apk

Some students may have questions. What is the relationship between aapt, aidl, javac, dex, apkbuilder Jarsigner, zipalign and the tasks of the Gradle plugin?

Answer: The automatic build process of the Gradle plugin is to directly or indirectly call the tools used in the manual packaging process in the Task.

to sum up

At this point, the APK construction process is basically analyzed, and readers can further understand the specific operations of gradle plugin packaging according to the source code of the gradle plugin.

You can write the following code in the build.gradle file, output the class corresponding to each Task, and then view the specific work of the Task:

//build.gradle
gradle.taskGraph.whenReady {
    it.allTasks.each { task ->
        println("Task Name : ${task.name}")
        task.dependsOn.each{ t->
            println "-----${t.class}"
        }
        //def outputFileStr = task.outputs.files.getAsPath();
        //def inputFileStr = task.inputs.files.getAsPath()
    }
}

dependencies {
    ...
    testImplementation "com.android.tools.build:gradle:4.0.0"
    ...
}

(For the mistakes and deficiencies in the article, please comment and leave a message, discuss together, and make progress together:-)


 

Guess you like

Origin blog.csdn.net/qq_39477770/article/details/109053692