Android Gradle 插件开发入门指南一共规划了三篇文档:
- Android Gradle 插件开发入门指南(一),讲解Gradle Plugin开发的完整流程
- Android Gradle 插件开发入门指南(二),针对Android的Gradle Plugin开发实践
- Android Gradle 插件开发入门指南(三),如何将插件发布到jcenter
目标
在指南一中我们实现了一个简单的Gradle通用插件,可以应用到任何以Gradle为构建系统的项目里。指南二里,我们要让Gradle和Android真正在一起,实现一个修改Apk输出名称的Gradle插件,使Apk的文件名中包含应用名称、VersionCode、VersionName、生成类型(BuildType: Debug/Release)、打包日期、Flavor信息。
先给我们的app module添加qq
、baidu
两个Flavor信息(flavor名字随意,baidu、qq只是举例哈,别一根筋),方便待会验证插件功能,两种方式:
- 如果你对Android Gradle插件比较熟悉,直接在app的build.gradle脚本里写入变体信息
- 也可以借助Android Studio提供的Project Structure窗口设置
参考文档:developer.android.com/studio/buil…
实现
Gradle构建系统里有两个很重要的概念,一个就是我们反复提到的Task(任务),构建的基本单元;另一个就是我们即将用到的Extension(扩展),通过扩展属性可以定制构建过程和构建产物。
上面提到的诸多信息中,打包日期、应用名称属于通用信息我们可以直接得到,其他信息属于Android Gradle插件的扩展信息,我们要得到这些扩展信息,就得依赖(implementation
)于Android Gradle插件,具体Android Gradle Plugin有哪些扩展信息,可以参考Android 插件 DSL 参考文档
配置插件Module
按照指南一的步骤,新建一个名为apkrename-plugin
的插件Module,并添加对Android Gradle插件的依赖
dependencies {
implementation 'com.android.tools.build:gradle:4.1.0'
}
依赖添加完成后,我们就可以在插件的apply函数里实现我们的功能了
实现插件功能
我们定义Apk的文件名称格式为:应用名称-VersionName-Flavor-$Date.apk,下面我们一步一步获取我们需要的所有信息:
1. 获取应用名称
public void apply(Project project) {
// 应用名称
def projectName = project.name
}
2. 获取日期
public void apply(Project project) {
// 应用名称
def projectName = project.name
// 打包日期,格式为:年月日时分秒
def buildTime = new Date().format("yyyyMMddHHmmss")
}
3. 获取Android Gradle Plugin的扩展信息
apply函数的入参project对象包含了项目构建的所有扩展信息,我们这里只需要Android Gradle Plugin的扩展信息,这些信息是指什么呢?看文档啊:Extension types
public void apply(Project project) {
// 应用名称
def projectName = project.name
// 打包日期,格式为:年月日时分秒
def buildTime = new Date().format("yyyyMMddHHmmss")
// project有很多扩展信息,我们这里需要Android相关的扩展信息,com.android.build.gradle.AppExtension
def appExtension = project.extensions.getByType(AppExtension)
}
appExtension
包含了Android Gradle Plugin的所有扩展信息,其中applicationVariants
属性是所有构建变体信息的集合,我们遍历这个集合就能得到每个变体实例,进而得到变体的其他信息。
完整的信息获取代码:
public void apply(Project project) {
// 应用名称
def projectName = project.name
// 打包日期,格式为:年月日时分秒
def buildTime = new Date().format("yyyyMMddHHmmss")
// project有很多扩展信息,我们这里需要Android相关的扩展信息,com.android.build.gradle.AppExtension
def appExtension = project.extensions.getByType(AppExtension)
// 遍历扩展信息里的所有变体,根据每个变体的信息组合出Apk的文件名称
appExtension.applicationVariants.all { variant ->
// 通过方法定义我们知道variant的实际类型为ApplicationVariant
// val applicationVariants: DomainObjectSet<ApplicationVariant> =
// dslServices.domainObjectSet(ApplicationVariant::class.java)
def versionCode = ((ApplicationVariant) variant).versionCode
def versionName = ((ApplicationVariant) variant).versionName
def buildType = ((ApplicationVariant) variant).buildType.name
def flavor = ((ApplicationVariant) variant).flavorName
}
}
如果你去看Android 插件 DSL 参考文档,并不能发现applicationVariants
的描述文档,所以到这里文档就指望不上了,还好我机智,command+B
定位到了方法声明的地方,发现applicationVariants
元素类型是ApplicationVariant
,而且ApplicationVariant
只是个接口,具体的实现是ApplicationVariantImpl
,有了这些信息,其他信息的获取水到渠成,顺便还发现了后面我们要用的属性outputs
。
4. 修改apk输出名称
apk文件名称属于任务的输出属性,那一定就在前面的outputs
里,同样command+B
发现outputs的元素类型为BaseVariantOutput
,BaseVariantOutput
只是个接口,具体实现为ApkVariantOutputImpl
,在ApkVariantOutputImpl
类里并没找到修改apk输出名称的函数,但是ApkVariantOutputImpl
同时还实现了ApkVariantOutput
,这里面就有我们需要的setOutputFileName
方法:
public void apply(Project project) {
// 应用名称
def projectName = project.name
// 打包日期,格式为:年月日时分秒
def buildTime = new Date().format("yyyyMMddHHmmss")
// project有很多扩展信息,我们这里需要Android相关的扩展信息,com.android.build.gradle.AppExtension
def appExtension = project.extensions.getByType(AppExtension)
// 遍历扩展信息里的所有变体,根据每个变体的信息组合出Apk的文件名称
appExtension.applicationVariants.all { variant ->
// 通过方法定义我们知道variant的实际类型为ApplicationVariant
// val applicationVariants: DomainObjectSet<ApplicationVariant> =
// dslServices.domainObjectSet(ApplicationVariant::class.java)
def versionCode = ((ApplicationVariant) variant).versionCode
def versionName = ((ApplicationVariant) variant).versionName
def buildType = ((ApplicationVariant) variant).buildType.name
def flavor = ((ApplicationVariant) variant).flavorName
((ApplicationVariant) variant).outputs.all { output ->
// 变体输出的除了apk还有其他文件,这里我们只修改apk的文件名
def outputFile = ((BaseVariantOutput) output).outputFile
if (outputFile != null && outputFile.name.endsWith(".apk")) {
((ApkVariantOutput) output).outputFileName = "$projectName-$versionCode-$versionName-$buildType-$flavor-${buildTime}.apk"
}
}
}
}
验证
插件功能开发完成了,发布插件到repo目录(不会的,回去看指南一),然后对app应用apkRename插件:
- build.gradle
buildscript {
repositories {
...
// 如果是发布到MavenLocal就是用mavenLocal()
// mavenLocal()
// 自定义的发布地址
maven { url('./repo') }
}
dependencies {
...
classpath "com.lenebf.plugin:apk-rename:0.0.1"
}
}
- app/build.gradle
plugins {
...
id 'com.lenebf.plugin.apk-rename'
}
执行assembleDebug
任务看看输出的apk名称是否如我们所愿
一如既往的完美,真是佩服我自己
代码
文章中代码地址:github.com/lenebf/Grad…