🍵补齐Android技能树——从AGP构建过程到APK打包过程(上)

简介: Android Gradle Plugin,简称 AGP,老早之前就想好好研究下Android APK的打包过程,毕竟 APK包体积优化 的前置知识之一。
+关注继续查看

0x1、网上流传的三张APK打包流程图


Android官网 有一张新的打包流程图(左),相比起旧的流程图(右)更抽象,隐藏了很多细节:


image


Android Studio Project Site 还找到了一张更详细的图:


image


如果只是满足于一个写基础业务的Android开发仔,了解下足矣,不过如果想有更深的造诣,还是建议往下学的。


本节就来了解下AGP的构建过程,以及简单了解下APK的打包过程~


Tips:Tasks那么多,不可能一个个去精读源码解析,不同插件版本还有差异,不如授之以渔,本文的目的就是让读者遇到问题时懂得如何追根溯源,找到对应的源码。


0x2、如何查看插件源码


研究对象是AGP的源码,所以要先搞一份源码,方法有下述几种:


1. 下载完整源码


如果磁盘空间比较充足,可以通过repo的方式,将Android Gradle Plugin的源码下载到本地(貌似30多G):


# 最新源码的只有3.4.0的
repo init -u https://android.googlesource.com/platform/manifest -b gradle_3.4.0
repo sync


2. 下载部分源码


当然不需要编译的话,可以直接下对应源码包,来到下述地址:build-system

点tgz下载:


image


然后用VS Code之类的代码查看工具查看即可~


3. 取巧(推荐)


在app层级的build.gradle添加下述依赖:


implementation 'com.android.tools.build:gradle:3.4.0'


build下,然后在左侧 External Libraries 即可找到源码:


image


0x3、阅读源码前的一些补充


阅读源码前建议温习下我前面写的三篇文章,另外补充点姿势:

Gradle Plugin 中的Task主要有三种:普通Task增量TaskTransform

Task一般会继承 DefaultTaskIncrementalTask,而 @TaskAction 注解的方法,就是此Task做的事。


继承 IncrementalTask 的类为增量Task,这个增量是相对于全量来说的,全量指的是:调用完clean后第一次编译过程,修改代码或资源后再次编译,就是增量编译。几个关键方法:


public abstract class IncrementalTask extends BaseTask {
    // 是否需要增量,默认false
    @Internal protected boolean isIncremental() { }  
    
    // 需要子类实现,全量时执行的任务
    protected abstract void doFullTaskAction() throws Exception;
    
    // 增量时执行的任务,默认什么都不执行,参数是增量时修改过的文件
    protected void doIncrementalTaskAction(Map<File, FileStatus> changedInputs) throws Exception{ }
    
    @TaskAction
    void taskAction(IncrementalTaskInputs inputs) throws Exception {
        // 判断是否是增量,是执行doIncrementalTaskAction,否则执行doFullTaskAction
    
    // 获取修改文件
    private Map<File, FileStatus> getChangedInputs(IncrementalTaskInputs inputs) { }
}


至于 Transform(变换),是Android官方提供给开发者,在**.class → .dex转换期间用来修改.class文件的一套API**,留意transform() 方法的实现就好。


0x4、执行gradle assemble的Task链


我们常常使用下面的命令来打包APK:


gradlew assemble


可以由此入手,看下打包一次都涉及到了哪些Task,键入下述命令(linux、mac使用./gradlew):


gradlew assemble --console=plain


输出结果及要点简述如下所示:


:app:preBuild UP-TO-DATE    → 空task,锚点
:app:preDebugBuild  → 空task,锚点
:app:compileDebugAidl NO-SOURCE → 处理AIDL
:app:checkDebugManifest → 检查Manifest是否存在
:app:compileDebugRenderscript NO-SOURCE → 处理renderscript
:app:generateDebugBuildConfig   → 生成 BuildConfig.java
:app:mainApkListPersistenceDebug → 生成 app-list.gson
:app:generateDebugResValues → 生成resvalue,generated.xml
:app:generateDebugResources → 空task,锚点
:app:mergeDebugResources    → 合并资源文件
:app:createDebugCompatibleScreenManifests   → manifest文件中生成compatible-screens,指定屏幕适配
:app:processDebugManifest → 合并manifest.xml文件
:app:processDebugResources → aapt打包资源
:app:compileDebugKotlin → 编译Kotlin文件
:app:prepareLintJar UP-TO-DATE → 拷贝 lint jar包到指定位置
:app:generateDebugSources → 空task,锚点
:app:javaPreCompileDebug → 生成 annotationProcessors.json 文件
:app:compileDebugJavaWithJavac → 编译 java文件
:app:compileDebugNdk → 编译ndk
:app:compileDebugSources → 空task,锚点
:app:mergeDebugShaders → 合并 shader文件
:app:compileDebugShaders → 编译 shaders
:app:generateDebugAssets → 空task,锚点
:app:mergeDebugAssets → 合并 assests文件
:app:validateSigningDebug → 验证签名
:app:signingConfigWriterDebug → 编写SigningConfig信息
:app:checkDebugDuplicateClasses → 检查重复class
:app:transformClassesWithDexBuilderForDebug → class打包成dex
:app:transformDexArchiveWithExternalLibsDexMergerForDebug → 打包第三方库的dex
:app:transformDexArchiveWithDexMergerForDebug → 打包最终的dex
:app:mergeDebugJniLibFolders → 合并jni lib 文件
:app:transformNativeLibsWithMergeJniLibsForDebug → 合并jnilibs
:app:transformNativeLibsWithStripDebugSymbolForDebug → 去掉native lib里的debug符号
:app:processDebugJavaRes NO-SOURCE → 处理java res
:app:transformResourcesWithMergeJavaResForDebug → 合并java res
:app:packageDebug  → 打包apk
:app:assembleDebug → 空task,锚点
:app:extractProguardFiles → 生成混淆文件
# 还会打一个release包,task和上述基本一致,此处省略~


当然,也可以直接在 Build 窗口直接查看,双击右侧Gradle窗口中assemble的Task,然后观察此窗口:


image


啧啧,还可以看到每个Task的执行时间,不错,但先不跟每个Task具体内容,而是跟下AGP的构建过程~


0x5、AGP的构建过程


上一节将Gradle插件时说过,每个插件都会配置一个 id名字.properties 的文件,在此写上插件的实现类,全局搜定位到下述文件:


image


打开:


image


指向:AppPlugin 类,跟下:


image


上节说过:插件类都继承于 Plugin,入口函数 apply(),但在这里没找到,跟下:AbstractAppPluginBasePlugin


① BasePlugin


image


行吧,在BasePlugin中重写了 apply() 方法,里面调用了两个函数,先跟下:basePluginApply()


image


执行一些检查操作,接着是 插件的初始化及配置,而另一个函数:

pluginSpecificApply() 则是空实现,接着跟下:配置项目、配置扩展及创建Tasks的过程。


相关文章
|
26天前
|
Android开发
安卓构建首个应用 2
安卓构建首个应用
15 0
|
26天前
|
XML Java Maven
安卓构建首个应用 1
安卓构建首个应用
11 0
|
5月前
|
Java API Android开发
Android项目实战:使用Retrofit构建天气预报应用
1. 项目简介 在这个Android项目实战中,我们将构建一个简单的天气预报应用。用户可以输入城市名称,获取该城市的实时天气信息、未来几天的天气预报以及其他相关信息。为了实现这个功能,我们将使用Retrofit框架进行网络请求,从OpenWeatherMap API获取天气数据。
100 0
|
6月前
|
前端开发 测试技术 Android开发
重新构建711的Android项目(二),架构的选择与实现
重新构建711的Android项目(二),架构的选择与实现
|
6月前
|
数据库 Android开发
重新构建711的Android项目(一),巧妙的小屏菜单查询框架实现
重新构建711的Android项目(一),巧妙的小屏菜单查询框架实现
|
6月前
|
XML 安全 Java
使用Kotlin构建Android应用:现代化的开发语言
随着移动应用开发的不断发展,开发人员有了更多选择来构建功能强大、高效和可维护的Android应用程序。其中一种备受推崇的选择就是使用Kotlin作为开发语言。Kotlin是一种现代化的编程语言,它为Android开发带来了许多优势和便利。
|
7月前
|
Android开发
【Android构建篇】MakeFile语法中 := 和 = 的区别
使用:= 在Makefile中使用 := 赋值方式定义变量时,如果该变量定义中包含了其他变量的引用,那么这些引用所表示的值将在变量定义时即被展开。也就是说,子变量会被立即展开,并赋值给父变量。
70 0
|
7月前
|
Shell C语言 Android开发
【Android构建篇】MakeFile语法&lt; 3 &gt;
对于一个看不懂Makefile构建文件规则的人来说,这个Makefile语法和shell语法是真不一样,但是又引用了部分shell语法,可以说是shell语法的子类,Makefile语法继承了它。 和shell语法不一样,这个更难一点,而且不太容易懂,所以后续还会持续更新这篇文章。
57 0
|
7月前
|
存储 Shell 编译器
【Android构建篇】MakeFile语法&lt; 2 &gt;
对于一个看不懂Makefile构建文件规则的人来说,这个Makefile语法和shell语法是真不一样,但是又引用了部分shell语法,可以说是shell语法的子类,Makefile语法继承了它。 和shell语法不一样,这个更难一点,而且不太容易懂,所以后续还会持续更新这篇文章。
52 0
相关产品
云迁移中心
推荐文章
更多