Android-Gradle-插件、依赖

4,023 阅读5分钟

前言

通过前两篇文章我们了解了 Groovy语言Gradle基本命令、生命周期、Task 的相关知识,那么这篇文章主要记录一些关于插件以及依赖配置的知识。

一、Project

build.gradle 在配置阶段会生成 project 实例,在 build.gradle 中直接调用方法或属性,实则是调用当前工程 project 对象的方法或属性。

1.project的相关api

  • project(':app'){ } 指定project(app)的配置,源代码如下:
/**
     * <p>Locates a project by path and configures it using the given closure. If the path is relative, it is
     * interpreted relative to this project. The target project is passed to the closure as the closure's delegate.</p>
     *
     * @param path The path.
     * @param configureClosure The closure to use to configure the project.
     * @return The project with the given path. Never returns null.
     * @throws UnknownProjectException If no project with the given path exists.
     */
    Project project(String path, Closure configureClosure);
  1. allprojects{ } 表示配置所有的project及其子project
allprojects {//fro project include repositories
    repositories {
        google()
        mavenCentral()
    }
}
  1. subprojects{ } 表示配置所有的子project
//根目录下的build.gradle
subprojects {
    println("subprojects->$it")
}
输出:
> Configure project :
subprojects->project ':app'

4. buildscript{ } 表示项目配置构建脚本类路径

buildscript {//for ☆gradle include dependencies and repositories
    repositories {
        google()
        mavenCentral()
    }
    dependencies {//构建工具的依赖
        classpath(group: 'com.android.tools.build', name: 'gradle', version: '4.2.1')
    }
}

2.ext扩展

使用 ext 可以对任意对象属性进行扩展。

  1. 在根项目中配置对其它 project 均可见
  2. 一般在 root project 中进行 ext 属性扩展,为子工程提供复用属性,通过 rootProject 直接访问。
  3. 任意对象都可以使用 ext 来添加属性:使用闭包,在闭包中定义扩展属性。直接使用 = 赋值,添加扩展属性。
//根build.gradle
this.ext.pop = "pop"
//ext{
//    pop = '1111'
//}

4.使用 gradle.properties 以键值对形式定义属性,所有 project 可直接使用。

例如:我们在管理全局依赖配置文件一般会有 config.gradle 文件,一般写法如下:

ext {
    android = [
            compileSdkVersion: 29,
            minSdkVersion    : 21,
            targetSdkVersion : 29,
    ]

    androidxVersion = "1.0.0"

    supportDependencies = [
            supportV4: "androidx.legacy:legacy-support-v4:${androidxVersion}",
    ]
}

然后在 module 中的 build.gradle 引入此文件使用其属性达到依赖版本统一。

二、插件

插件就是把独立或可公用的代码进行打包,已达到其它模块的复用。插件的应用都是通过 Project.apply() 方法完成的,并且插件分为两种,一种是脚本插件,另一种是二进制插件。

1.脚本插件

脚本插件就是直接编辑在 gradle 脚本文件中,然后通过 apply plugin: PluginName 引用对应的插件,只能在此脚本中使用。

class MyPlugin implements Plugin<Project> {
    @Override
    void apply(Project target) {
    //此project对象就是 apply插件的Project对象
        println "MyPlugin apply"
    }
}

apply plugin: MyPlugin

2.二进制插件

二进制插件就是实现了 Plugin 接口的插件,他们有 plugin id,通过 apply id 引用。一般可以在单独的项目中实现,也可以在 buildSrc 目录下编写,由于 buildSrc 可应用于其他项目,那么在它项目初始化前就需要构建好 buildSrc,所以他的构建时间会早于 settings.gradle,接下来我们以 buildSrc 方式来实现, buildSrc 目录下的插件,在运行时,会自动打包成 jar 并进行依赖,实现方式:

  • 创建 moudle,并且命名为 buildSrc。
  • 删除目录仅留下 main 文件夹,然后创建 java 文件夹( groovy 也可以,只是实现的语言不同),和 resources 文件夹。
  • 新建 resources -> META-INF.gradle-plugins -> com.empty.test.properties 文件,并且写入
implementation-class=com.empty.test.MyTestPlugin
  • 在 buildSrc 中配置 groovy 依赖:apply plugin:'groovy'
  • 在 app 中 apply plugin: MyTestPlugin 即可使用

结构

三、Transform

Transform 允许我们在 class 文件转为 dex 文件前操作编译好的 class 文件,每个 Transform 都是一个 gradle task。具体实现如下:

class MyTestTransform extends Transform {

    @Override
    String getName() {
        return MyTestTransform
    }

    @Override
    Set<QualifiedContent.ContentType> getInputTypes() {
        return TransformManager.CONTENT_CLASS
    }

    @Override
    Set<? super QualifiedContent.Scope> getScopes() {
        return TransformManager.SCOPE_FULL_PROJECT
    }

    @Override
    boolean isIncremental() {
        return true
    }

    @Override
    void transform(TransformInvocation transformInvocation) throws TransformException, InterruptedException, IOException {
        super.transform(transformInvocation)
        
        transformInvocation.inputs.each { TransformInput input ->
            input.jarInputs.each { JarInput jarInput ->
                //处理Jar
            }

            input.directoryInputs.each { DirectoryInput directoryInput ->
                //处理源码文件
            }
        }
    }
  • getName():对应的Task名称
  • getInputTypes():确定对那些类型的结果进行转换,常用的是 CONTENT_CLASS 表示要处理 java 的 class 文件。
  • getScopes():指定插件的适用范围,常用的是 TransformManager.SCOPE_FULL_PROJECT 表示处理全部的class 字节码。
  • isIncremental():是否支持增量更新
  • transform():具体的转换过程

之后在 Plugin 中注册这个 Transform 即可。

def appExtension = project.getExtensions().getByType(AppExtension.class)
appExtension.registerTransform(new MyTestTransform())

四、依赖管理

关于依赖项的配置,我们常用的有 implementation、api、compileOnly 等,具体的解释官网中有, 链接在此

需要注意的是:

  • A implemetation B,B implemetation C,则 A 不能使用 C。
  • A implemetation B,B api C,则 A 可以使用C。
  • A implemetation B,B implemetation C,C api D,则 B 可以使用 D,但 A 不能使用 D。
  • A implemetation B,B api C,C api D,这样 A 可以使用 D 不管ABCD在何处被添加到类路径都一样,在运行时这些模块中的 class 都是要被加载的。

1.查看项目依赖

要查看项目依赖项 可使用命令:
gradlew :app:dependencies 或者 gradlew :app:dependencies --configuration compile 也可以使用 gradlew build --scan 在网址上看。

同时 Gradle 也会有一部分优化,例如:
如果项目存在同一个依赖库的多个版本,默认选择最高版本、Gradle 会自动排除重复的依赖、Gradle 默认支持依赖传递等等。

命令输出

buildScan 其中

  • x.x.x (*) 该依赖已经有了,将不再重复依赖。
  • x.x.x -> x.x.x 该依赖的版本被箭头所指的版本代替。
  • x.x.x -> x.x.x(*) 该依赖的版本被箭头所指的版本代替,并且该依赖已经有了,不再重复依赖。

2.排除依赖

随着应用的范围不断扩大,它可能会包含许多依赖项,包括直接依赖项和传递依赖项(应用中导入的库所依赖的库)。如需排除不再需要的传递依赖项,可以使 exclude 关键字:

dependencies {
    implementation('androidx.appcompat:appcompat:1.2.0') {
        exclude(group: 'androidx.core')
        exclude(group: 'androidx.arch.core', module: 'core-common')
    }
}

使用全部排除:

// 在configurations{ } 中添加下面节点
configuration {
    all*.exclude module: 'name'
}

3.指定依赖库版本

使用 force 来强行指定某个三方库的版本。

configurations.all {
   resolutionStrategy {
       force 'group:module:version'
   }
}

五、发布插件到本地

先引入 maven 插件,再在 uploadArchives 加入上传的仓库地址与相关配置,配置中:groupId 为组织或公司名称, artifactId 为模块名称,version 为当前版本号,这样 Gradle 在执行 uploadArchives 时将生成和上传 pom.xml 文件。

apply plugin: 'maven'

uploadArchives {
    repositories.mavenDeployer {
        repository(url: uri('../repostory'))
        pom.groupId = "com.empty.test"
        pom.artifactId = "mylibrary"
        pom.version = "1.0.0"
    }
}

implementation(group: 'com.empty.test', name: 'mylibrary', version: '1.0.0')

发布远程一般为 MavenCentral 或者 Jitpack ,具体实现可自查。

六、总结

到这里,我们了解到什么是project、自定义插件、Transform、发布插件及依赖配置