自定义Gradle二进制插件
二进制插件
我们出于自己的目的,要开发实际业务场景的插件来辅助项目构建。 自定义二进制插件,可以使用 java,kotlin,或者 groovy 来编码,因为他们都是基于JVM的编程语言,最终都会生成class交给JVM去执行。groovy提供了更多插件相关的api,有一些情况用groovy能直接达成效果,而不需要去引入其他类库。
以kotlin为例:
创建一个java library
每个androidStudio版本的操作界面可能各不相同,这是 Android Studio Electric Eel | 2022.1.1 Patch 2 版本的截图。
引入 必要的 依赖
包括两部分,一个是gradleApi,必须引入。
另外就是其他的,我们编写编码需要用到的其他依赖库,比如 发送网络请求的 okhttp,生成二维码的zxing ,接入华为云的 obs等等。
plugins {
id 'java-library'
id 'org.jetbrains.kotlin.jvm' // kotlin依赖
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation gradleApi() // 必须的gradle依赖
// 引入其他工具类库
implementation 'com.squareup.okhttp3:okhttp:3.14.6' // 使用最新版okhttp居然无法引用,很诡异
implementation 'com.huaweicloud:esdk-obs-java-bundle:3.21.8' // 引入 华为云
implementation 'com.google.zxing:core:3.4.1' // 二维码生成器
implementation 'org.springframework:spring-core:2.5.6'
implementation 'net.dongliu:apk-parser:2.5.3' // apk解析工具
新建一个Project实现类
import com.android.build.gradle.AppExtension
import com.tw.lib.bean.AutoUploadBean
import org.gradle.api.Plugin
import org.gradle.api.Project
class AutoUploadPlugin : Plugin<Project> {
override fun apply(project: Project) {
println("======== 自动上传插件初始化 =========")
// 配置外来参数, 表示插件的使用者可以在gradle文件中写 相关的参数
val autoUploadBean = project.extensions.create("autoUpload", AutoUploadBean::class.java)
project.afterEvaluate {
val appExtension = it.extensions.getByType(AppExtension::class.java)
appExtension.applicationVariants.all { v ->
v.outputs.all { out ->
val file = out.outputFile // 输出的apk文件
val name = out.name
project.tasks.create(
"auto_upload_$name",
AutoUploadTask::class.java,
file,
autoUploadBean
比如上面我要做一个实现自动上传的插件 AutoUploadPlugin
,它必须实现
Plugin<Project>
接口,并实现其中的apply方法。方法内部写上你要做的操作。
一个project是由多个Task组合而成,下面的代码中,我我在apply方法中创建了一个名叫 autoUpload
的 额外参数,并创建了一个名为 AutoUploadTask
的 任务。
创建 AutoUploadTask 任务
public class AutoUploadTask extends DefaultTask {
private File file;
private final AutoUploadBean autoUploadBean;
@Inject
public AutoUploadTask(File file, AutoUploadBean autoUploadBean) {
setGroup("autoUpload");
this.file = file;
this.autoUploadBean = autoUploadBean;
@TaskAction
public void action() throws IOException {
System.out.println("做你想做的事情");
这里有一些要素必须提到,
首先,setGroup是自定任务的分组,这个分组最终会呈现在androidStudio右侧的gradle面板中。
其次,步骤3中执行了这么一段代码:
project.tasks.create(
"auto_upload_$name",
AutoUploadTask::class.java,
file,
autoUploadBean
这其实是在反射创建 AutoUploadTask对象,后面的file和autoUploadBean其实就是入参,所以我们必须提供一个带这两个参数的构造函数。
最后,在接收到 file和 autoUploadBean 外来参数之后,我们可以在 重写的action方法中使用它们来完成我们自己想要的的操作。
AutoUploadBean类的内容为:
open class AutoUploadBean {
// 华为OBS账号
var userName: String? = null
// 华为OBS密码
var pwd: String? = null
// 华为OBS桶
var domain: String? = null
// 是否使用分段上传
var usePartUpload: Boolean = false
// 下载二维码的输出目录
var buildRootDir: String? = null
到这里,插件基本上就编写完成了。
每一个插件都有全局唯一一个 id ,这个id注册在 /src/main/resources/META-INF/gradle-plugins
中,我们在 这个目录下,创建一个 自定义名称的com.tw.autoUpload.properties
文件,自定义的名称就是我们插件的唯一ID,文件内容为:implementation-class=com.tw.lib.AutoUploadPlugin
,也就是我们自定义Plugin的全类名。
在 要使用插件模块的build.gradle中
apply plugin:'com.tw.autoUpload'
plugins {
id 'com.android.application'
id 'org.jetbrains.kotlin.android'
id 'com.tw.autoUpload' // 使用插件
并且指定插件的额外参数:
autoUpload {
userName 'c00293388'
pwd 'Wd2A@zFJ1234'
domain 'hwstaff_DigitalPayment'
usePartUpload false
buildRootDir 'C:\Users\zwx1245985\Desktop\saved'
执行插件任务
至此完成,经过编译之后,我们就能在 任务分组 autoupload之下,使用 auto_upload任务去执行上传操作了。
插件的发布
发布二进制插件有两种方式,
发布到naven仓库
此处以 发布到localMaven为例说明:
编写发布脚本
在我们创建的java library的 build.gradle中,写入内容:
publishing {
publications {
AutoUploadPlugin(MavenPublication) {
from components.java
groupId 'com.tw'
artifactId 'aotuUpload'
version '1.0'
上面有4处需要我们做修改:
AutoUploadPlugin 这是自定义插件的名称,直接用 我们创建的继承 org.gradle.api.Plugin<Project>
的类名
groupId 插件发布的群组
artifactId 群组下的插件名称
version 版本
后面3项直接决定了插件的唯一性。
建立mavenLocal环境
在 本地建立localMaven环境(如何创建环境,看这里!www.jianshu.com/p/cb941c74a… ),然后执行 本工程的 publishToMavenLocal 命令,将它发布到本地maven仓库下。
发布之后就是引用插件:
buildscript {
repositories {
mavenLocal()
dependencies {
classpath 'com.tw:aotuUpload:1.0'
随后的 apply plugin:'com.tw.autoUpload'
之后的步骤就参照前文使用插件
章节。
直接引用jar包
我们创建了一个 autoUploadPlugin 的java library ,在编译之后,module下会存在一个 jar包 autoUploadPlugin.jar
, 它的效果和本地maven相同,只不过 引用的方式必须是在 build.gradle
中:
buildscript{
dependencies {
classpath files('lib/autoUploadPlugin.jar')
同样,apply plugin:'com.tw.autoUpload'
之后的步骤也参照前文使用插件
章节。
Gradle插件
纯gradle插件则简单很多,以下是一个简单案例:
在app 目录下 创建一个 config.gradle
文件,内容为:
ext {
dependenciesx = [ appcompat : [name: 'androidx.appcompat:appcompat', version: '1.6.1'],
material : [name: 'com.google.android.material:material', version: '1.8.1'],
constraintlayout : [name: 'androidx.constraintlayout:constraintlayout', version: '2.1.4'],
navigation_fragment: [name: 'androidx.navigation:navigation-fragment', version: '2.5.3'],
navigation_ui : [name: 'androidx.navigation:navigation-ui', version: '2.5.3'],
junit : [name: 'junit:junit', version: '4.13.2'],
junitx : [name: 'androidx.test.ext:junit', version: '1.1.5'],
espresso_core : [name: 'androidx.test.espresso:espresso-core', version: '3.5.1'],
其中放置了很多第三方依赖的 name 和 version
apply from: "config.gradle"
如果想把 config.gradle发布到远程(内网或外网)的话,
则可以使用 apply from :"http://xxx.com/config.gradle"
的方式引入。
dependencies {
dependenciesx.each { dependencyName, dependency ->
implementation "${dependency.name}:${dependency.version}"
很简洁的三步走。
两种方式的对比
它们具有不同的优缺点,具体情况下可以根据项目的特点和需求来决定应该使用哪种方式。
二进制插件(Binary Plugin):
性能更好:二进制插件是使用 JVM 字节码编写的,因此它们通常比纯 Gradle 插件的脚本执行速度更快,尤其是对于大型项目来说。
可以使用其他语言:二进制插件可以使用许多编程语言编写(如 Kotlin、Groovy、Java 等),因此你可以选择熟悉的语言来编写插件。
开发复杂度高:二进制插件的开发需要实现插件的接口和声明插件的元数据。在一些简单的场景下,这可能会增加不必要的开发复杂性。
部署和依赖管理稍复杂:使用二进制插件时,你需要构建插件并将其发布到仓库,然后才能在项目中引用并配置依赖关系。
项目的规模和复杂度:对于较大、复杂的项目,二进制插件可能更适合,可以提供更好的性能和扩展性。
开发资源和技能:如果你已经熟悉了 Groovy 或 Kotlin,那么纯 Gradle 插件可能更容易上手和开发。而如果你有其他语言的开发经验,二进制插件则提供了更多选择。
部署和依赖管理的要求:如果你希望将插件发布到仓库并作为独立的模块使用,那么二进制插件是更合适的选择。而纯 Gradle 插件则更适合内部使用或作为项目本身的一部分。
综上所述,二进制插件和纯 Gradle 插件各有优劣,选择哪种方式要根据具体项目的要求和约束来进行决策。
提示