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

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

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


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


网络异常,图片无法展示
|


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


网络异常,图片无法展示
|


如果只是满足于一个写基础业务的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下载:


网络异常,图片无法展示
|


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


3. 取巧(推荐)


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


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


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


网络异常,图片无法展示
|


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,然后观察此窗口:


网络异常,图片无法展示
|


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


0x5、AGP的构建过程


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


网络异常,图片无法展示
|


打开:


网络异常,图片无法展示
|


指向:AppPlugin 类,跟下:


网络异常,图片无法展示
|


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


① BasePlugin


网络异常,图片无法展示
|


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


网络异常,图片无法展示
|


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

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


相关文章
|
6月前
|
安全 Java Android开发
05. 【Android教程】Android 程序签名打包
05. 【Android教程】Android 程序签名打包
63 1
|
3月前
|
Linux Android开发 iOS开发
使用Kivy创建“Hello World”应用并打包成APK
使用Kivy创建“Hello World”应用并打包成APK
|
4月前
|
安全 Java Android开发
【Android P】OTA升级包定制,移除不需要更新的分区,重新打包签名
如何解压OTA升级包、编辑升级包内容(例如移除不需要更新的分区)、重新打包、签名以及验证OTA文件的过程。
315 2
【Android P】OTA升级包定制,移除不需要更新的分区,重新打包签名
|
5月前
uniapp 打包成 apk(原生APP-云打包)免费
uniapp 打包成 apk(原生APP-云打包)免费
291 1
|
5月前
|
JavaScript
vue 项目/备案网页/ip网页打包成 apk 安装到平板/手机(含vue项目跨域代理打包成apk后无法访问接口的解决方案)
vue 项目/备案网页/ip网页打包成 apk 安装到平板/手机(含vue项目跨域代理打包成apk后无法访问接口的解决方案)
125 0
|
5月前
|
Android开发
【亲测,安卓版】快速将网页网址打包成安卓app,一键将网页打包成app,免安装纯绿色版本,快速将网页网址打包成安卓apk
【亲测,安卓版】快速将网页网址打包成安卓app,一键将网页打包成app,免安装纯绿色版本,快速将网页网址打包成安卓apk
137 0
|
6月前
|
Java 开发工具 Android开发
详细解读Android开发DNK开发将.c文件打包成os
详细解读Android开发DNK开发将.c文件打包成os
33 0
|
6月前
|
jenkins 持续交付 开发工具
Android使用Jenkins打包自动维护sdk版本号
Android使用Jenkins打包自动维护sdk版本号
61 0
|
6月前
|
Android开发
Android Gradle开发—脚本实现自动打包后复制一份APK文件,并修改APK名称,到指定目录作备份
Android Gradle开发—脚本实现自动打包后复制一份APK文件,并修改APK名称,到指定目录作备份
305 0
|
7月前
|
JavaScript 前端开发 Android开发
Auto.js如何打包成APK文件
Auto.js如何打包成APK文件