需求背景
在SDK开发过程中,我们可能遇到过需要将多个Module的代码打包成一个jar或者aar的情况,由于安卓打包的时候不会将module依赖的其他module打包进aar中,所以通过AS打包出来的aar是不完整的。但是在组件化开发盛行的当下,这种诉求却越发明显。
解决方案
当然,针对上述问题,也有很多解决方案,比如利用Python脚本来对代码进行重组、利用Gradle来进行打包流程干预,还有直接使用单模块开发的方式。首先,使用单模块开发的方式是不会面临上述问题的,也就不存在解决,但是它会抛弃掉组件化开发或者模块化开发的巨大优势;其次,使用Python对代码进行重组,这种方式的成本比较低,利用Python脚本语言的拷贝等语法对多个模块的代码进行组合,然后对组合后的代码进行打包操作,可以实现多个模块打包成一个目标文件的目的;当然,我们还可以利用AS原生嵌入的Gradle来完成这项工作,通过在打包流程中添加自定义的操作来完成多模块打包成一个目标文件。
下面对比下这几种方式的优缺点:
方式 | 优点 | 缺点 |
---|---|---|
单模块 | 兼容性高,没有额外的流程 | 不支持组件化开发,在项目较复杂时,开发维护成本偏高 |
Python | 处理思路简单,实现容易 | 需要额外的脚本语言支持,需要操作文件,通用性较弱 |
Gradle | 没有额外流程,扩展性强,接近原生速度 | 需要对原始流程进行干预,操作部分文件 |
事实上,在笔者的项目中,最开始是用的Python脚本的方式,打包时,调用Python命令来完成。在此过程中,通过执行Python脚本命令来完成打包的方式在每次版本迭代时,可能都需要修改打包脚本,在我们的jenkins服务器上也需要安装Python环境,因此,我们修改了打包方式,通过原生的Gradle来实现,这种方式让我们的项目的打包更简洁,直接通过AS的任务来实现,而且具备很强的通用性。
方案分析
针对Gradle这种方式,我们主要是利用Gradle的一些特性和Android标准打包流程来实现的。
Gradle生命周期
涉及到到gradle的构建干预,我们必须了解gradle的一些基本规则。gradle的构建流程有三个步骤(或者说它的生命周期包含三个主要节点),分别是:初始化、配置、执行。
官方给出的定义是:
A Gradle build has three distinct phases.
Initialization
Gradle supports single and multi-project builds. During the initialization phase, Gradle determines which projects are going to take part in the build, and creates a Project instance for each of these projects.
Configuration
During this phase the project objects are configured. The build scripts of all projects which are part of the build are executed.
Execution
Gradle determines the subset of the tasks, created and configured during the configuration phase, to be executed. The subset is determined by the task name arguments passed to the gradle command and the current directory. Gradle then executes each of the selected tasks.
事实上,每个build.gradle文件都会对应一个Project对象,在初始化完成之后,我们就可以获取到这个对象并进行一些操作。而配置阶段则是针对我们的build.gradle文件来进行一些配置操作,比如构建任务树等。在执行阶段,就会按照配置阶段确定的任务树来依次执行每个任务(不开启并发执行的情况下)。
而我们的切入点就是在执行接阶段来对构建流程进行干预。事实上,我们既可以通过项目内的gradle脚本来实现,也可以通过gradle的插件plugin来实现我们的功能。相对脚本,插件具备更加强的通用性和简洁性。但是这里,我们仅仅针对脚本来阐述下我们的实现思路。
生命周期监听器
在我们的实现中,我们没有采用自定义任务以及任务依赖的方式,因为这样我们需要添加额外的任务,并且需要通过额外的任务来完成我们的构建,这是我们不想看到的,也是我们抛弃掉Python构建方式的原因之一。我们采用的是通过对构建流程中项目以及各个任务的执行状态和流程来进行切入的。这里,我们可以使用gradle api 提供的各种监听器来实现。Gradle本身提供了很多监听器,使之具备极强的扩展性。具体包含:
/**
* <li>{@link org.gradle.BuildListener}
* <li>{@link org.gradle.api.execution.TaskExecutionGraphListener}
* <li>{@link org.gradle.api.ProjectEvaluationListener}
* <li>{@link org.gradle.api.execution.TaskExecutionListener}
* <li>{@link org.gradle.api.execution.TaskActionListener}
* <li>{@link org.gradle.api.logging.StandardOutputListener}
* <li>{@link org.gradle.api.tasks.testing.TestListener}
* <li>{@link org.gradle.api.tasks.testing.TestOutputListener}
* <li>{@link org.gradle.api.artifacts.DependencyResolutionListener}
*/