Gradle学习笔记-Android打包过程

概述

APK组成

Apk文件进行解压处理,本质是Zip,解压后可以看到若干文件。

主要由以下部分组成:

文件/目录 描述
lib/ 存放so文件,一般情况下包含armeabi-v7aarm64-v8a这两个目录,其他还有x86armeabi等。
res/ 存放编译后的资源文件,例如drawablelayout
META_INF/ 一般存在于已经签名的Apk中,记录签名摘要等信息
assets/ 应用程序的资源,可通过AssetManager来检索对应资源
classes(n).dex classes对应Java Class,被编译成Dex后,可以被Dalvik/ART虚拟机所理解
resources.arsc 打包过程中产生的资源索引文件。用于包体积优化,可对重复资源、资源文件名混淆提供分析
AndroidManifest.xml 用于描述App名称、版本、所需权限以及注册的四大组件

后续打包流程的介绍,也会分析具体部分生成的时机以及内容。

打包流程

Apk构建流程

流程中的椭圆形部分为打包过程中所需要用到的工具,下面简单的介绍下

主要执行文件的位置在${ANDROID_SDK_HOME}/build-tools/XX/

名称 功能介绍
aapt(aapt2) Android资源打包工具
aidl Android接口描述语言 -> Java文件
javac Java编译器
dex(d8) 打包class文件dex
apkbuilder(apkfinger) 生成apk
zipalign 字节码对齐工具

根据上图可以得出,Android打包流程主要分为两部分:

  • 编译
    • 资源文件编译 - 通过AAPT2编译
    • aidl文件编译 - 编译成Java文件
    • kotlin/java文件编译 - javac编译成class文件
    • jni相关文件编译 - 编译成so文件
  • 打包
    • 打包class为dex文件 - 使用D8 R8编译
    • 打包dex和编译后资源为apk - 使用ApkFlinger打包
    • 给apk签名 - 使用v2/v3/v4方式签名

打包相关Task

通过执行./gradlew assembleRelease 观察执行哪些Task

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
=========TaskExecutionGraph:app:buildKotlinToolingMetadata=========
=========TaskExecutionGraph:app:preBuild=========
=========TaskExecutionGraph:app:preReleaseBuild=========
=========TaskExecutionGraph:app:compileReleaseAidl=========
=========TaskExecutionGraph:app:compileReleaseRenderscript=========
=========TaskExecutionGraph:app:generateReleaseBuildConfig=========
=========TaskExecutionGraph:app:checkReleaseAarMetadata=========
=========TaskExecutionGraph:app:generateReleaseResValues=========
=========TaskExecutionGraph:app:generateReleaseResources=========
=========TaskExecutionGraph:app:mergeReleaseResources=========
=========TaskExecutionGraph:app:packageReleaseResources=========
=========TaskExecutionGraph:app:mapReleaseSourceSetPaths=========
=========TaskExecutionGraph:app:parseReleaseLocalResources=========
=========TaskExecutionGraph:app:createReleaseCompatibleScreenManifests=========
=========TaskExecutionGraph:app:extractDeepLinksRelease=========
=========TaskExecutionGraph:app:processReleaseMainManifest=========
=========TaskExecutionGraph:app:processReleaseManifest=========
=========TaskExecutionGraph:app:processReleaseManifestForPackage=========
=========TaskExecutionGraph:app:processReleaseResources=========
=========TaskExecutionGraph:app:compileReleaseKotlin=========
=========TaskExecutionGraph:app:javaPreCompileRelease=========
=========TaskExecutionGraph:app:compileReleaseJavaWithJavac=========
=========TaskExecutionGraph:app:extractProguardFiles=========
=========TaskExecutionGraph:app:lintVitalAnalyzeRelease=========
=========TaskExecutionGraph:app:lintVitalReportRelease=========
=========TaskExecutionGraph:app:lintVitalRelease=========
=========TaskExecutionGraph:app:mergeReleaseJniLibFolders=========
=========TaskExecutionGraph:app:mergeReleaseNativeLibs=========
=========TaskExecutionGraph:app:stripReleaseDebugSymbols=========
=========TaskExecutionGraph:app:extractReleaseNativeSymbolTables=========
=========TaskExecutionGraph:app:mergeReleaseNativeDebugMetadata=========
=========TaskExecutionGraph:app:checkReleaseDuplicateClasses=========
=========TaskExecutionGraph:app:transformReleaseClassesWithAsm=========
=========TaskExecutionGraph:app:dexBuilderRelease=========
=========TaskExecutionGraph:app:desugarReleaseFileDependencies=========
=========TaskExecutionGraph:app:mergeExtDexRelease=========
=========TaskExecutionGraph:app:mergeDexRelease=========
=========TaskExecutionGraph:app:mergeReleaseArtProfile=========
=========TaskExecutionGraph:app:compileReleaseArtProfile=========
=========TaskExecutionGraph:app:mergeReleaseShaders=========
=========TaskExecutionGraph:app:compileReleaseShaders=========
=========TaskExecutionGraph:app:generateReleaseAssets=========
=========TaskExecutionGraph:app:mergeReleaseAssets=========
=========TaskExecutionGraph:app:compressReleaseAssets=========
=========TaskExecutionGraph:app:processReleaseJavaRes=========
=========TaskExecutionGraph:app:mergeReleaseJavaResource=========
=========TaskExecutionGraph:app:optimizeReleaseResources=========
=========TaskExecutionGraph:app:collectReleaseDependencies=========
=========TaskExecutionGraph:app:sdkReleaseDependencyData=========
=========TaskExecutionGraph:app:writeReleaseAppMetadata=========
=========TaskExecutionGraph:app:writeReleaseSigningConfigVersions=========
=========TaskExecutionGraph:app:packageRelease=========
=========TaskExecutionGraph:app:createReleaseApkListingFileRedirect=========
=========TaskExecutionGraph:app:assembleRelease=========

以上是执行assembleRelease相关的Task,与上述打包流程相关的主要是以下Task,重点分析的也是这些关联Task

  • 编译

    • 资源文件编译 - 通过AAPT2编译

      generateBuildConfig - 生成BuildConfig.java

      mergeResources - merge资源文件

      mergeAssets - merge assets/下资源文件

      processManifest - merge AndroidManifest.xml文件

      processResources - 生成R.java文件 处于AAPT2链接阶段

    • aidl文件编译 - 编译成Java文件

      compileAidl - 编译aidl文件

    • kotlin/java文件编译 - javac编译成class文件

      compileKotlin - 编译kotlin文件

      compileJavaWithJavac - 编译java文件为class文件

    • jni相关文件编译 - 编译成so文件

      externalNativeBuild - 编译C/C++等文件为so

      mergeJniLibFolders - 合并依赖的Native库

      stripDebugSymbols - 剔除debug符号

    • class文件处理 - 类似Transform进行字节码操作

      transformClassesWithAsm - 实现AsmClassVisitorFactory

  • 打包

    • 打包class为dex文件 - 使用D8 R8编译

      dexBuilder - 打包class

    • 打包dex和编译后资源为apk - 使用ApkFlinger打包

      package - 打包Apk

    • 给apk签名 - 使用v2/v3/v4方式签名

主流程分析

资源与代码编译

资源文件编译

Apk资源主要包含以下几种:

  • res目录下所有文件,例如drawablelayout等文件目录下
  • assets目录下文件
  • 各Module下的AndroidManifest.xml
mergeAssets&packageAssets-合并assets文件
  • mergeAssets:合并所有的assets文件
  • packageAssets:合并子module中的assets文件

上述Task对应的源码实现类位于com.android.build.gradle.tasks.MergeSourceSetFolders

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
class MergeAppAssetCreationAction(creationConfig: ComponentCreationConfig) :
MergeAssetBaseCreationAction(
creationConfig,
true
) {

override val name: String
get() = computeTaskName("merge", "Assets")

override fun handleProvider(
taskProvider: TaskProvider<MergeSourceSetFolders>
)
{
super.handleProvider(taskProvider)

creationConfig.artifacts.use(taskProvider)
.wiredWith { it.outputDir }
.toAppendTo(MultipleArtifact.ASSETS)
}
}

class LibraryAssetCreationAction(creationConfig: ComponentCreationConfig) :
MergeAssetBaseCreationAction(
creationConfig,
false
) {

override val name: String
get() = computeTaskName("package", "Assets")

override fun handleProvider(
taskProvider: TaskProvider<MergeSourceSetFolders>
)
{
super.handleProvider(taskProvider)

creationConfig.artifacts.setInitialProvider(
taskProvider,
MergeSourceSetFolders::outputDir
).withName("out").on(InternalArtifactType.LIBRARY_ASSETS)
}
}

最终合并完成的assets位于build/intermediates/assets下。

MergeAssetsTask为契机,可以实现类似assets文件压缩或者无用文件删除功能。

//todo 示例

processManifest-合并AndroidManifest.xml文件
  • processManifest - 处理子moduleAndroidManifest.xml文件
  • processMainManifest - 处理app moduleAndroidManifest.xml文件
  • processManifestForPackage - 处理merged_manifests,位于build/intermediates/merged_manifests。最后合并得到打到Apk里的AndroidManifest.xml,位于build/intermediates/packaged_manifest

上述Task对应源码分别如下:

processManifest - ProcessLibraryManifest

1
2
3
4
5
```

processMainManifest - `ProcessApplicationManifest`

```kotlin

processManifestForPackage - ProcessPackagedManifestTask


processManifestForPackage为契机,可以实现类似隐私权限检测新增页面检查等功能

//todo 示例

*mergeResources&processResources-处理res下资源文件

AIDL文件编译

compileAidl-编译aidl为java

Kotlin/Java文件编译

compileKotlin
compileJavaWithJavac

jni相关文件编译

externalNativeBuild
mergeNativeLibs

打包流程

打包成Dex

dexBuilder

打包成Apk

package

相关链接

Apk构建流程

Android签名相关


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!