补齐Android技能树 - 玩转Gradle(二) | 小册免费学(中)

简介: 在开始本节内容前,先来温习下几个关键词: Project(项目) → Gradle的构建 → 由一个或多个Project组成; Task(任务) → Gradle中的Project → 由一个或多个Task组成; Action(执行动作) → Gradle中的Task → 由一个或多个Action(函数/方法)按序组成;

0x2、依赖规则


Gradle会声明每个依赖项的适用范围,可以理解为 分组,如:有些依赖在编译时用到,有些则在运行时用到,Gradle通过 Configuration 来表示这个范围(分组),不同的Configuration通过不同的name区分。


许多Gradle插件会预置一些Configuration添加到你的项目中,如Java插件:


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


有点懵,没关系,看下Android内置的这些Configuration你就懂了(2.x是废弃的):


// 对应2.x的 compile,既参与编译又参与打包
implementation → 当前模块依赖,但不向其他模块暴露此依赖,编译时只能在本模块访问;
api → 当前模块依赖,且向其他模块暴露此依赖,同compile;
举例区分下:
模块A、B,如果A依赖了Gson库,B依赖A,使用implementation,B用不了Gson,使用api,B可以使用Gson。
// 对应2.x的provided和apk,用的较少
compileOnly → 编译时有效,不会参与打包;
runtimeOnly → 运行时有效,不会参与编译;
annotationProcessor →  注解处理器依赖
testCompile → 对应2.x的testImplementation,只在单元测试代码的编译以及最终打包测试apk时有效;
debugCompile → 对应2.x的debugImplementation,只在debug模式的编译和最终的debug apk打包时有效;
releaseCompile → releaseImplementation,只在release的编译和最终的release apk打包时有效;
附:四种依赖方式
// ① 本地library依赖
implementation project(":mylibrary")  
// ② 本地二进制依赖
implementation files('libs/xxx.jar', 'libs/yyy.jar')    // 依赖特定库
implementation fileTree(dir: 'libs', include: ['*.jar']) // 依赖目录下的库
// ③ 远程二进制依赖
implementation('io.reactivex:rxandroid:1.2.1')
// ④ AAR包依赖
implementation(name: 'me.leolin:ShortcutBadger', ext: 'aar')    // 本地
implementation 'me.leolin:ShortcutBadger:1.1.17@aar'    // 远程


当然,你也可以自定义一个Configuration,示例如下:


allprojects {
    // 配置maven仓库地址
    repositories {
        maven { url "https://maven.aliyun.com/repository/jcenter" }
    }
}
// 定义一个名为myDependency的Configuration
configurations {
    myDependency
}
// 为自定义Configuration添加依赖
dependencies  {
    myDependency('io.reactivex:rxjava:1.1.9')
    myDependency('io.reactivex:rxandroid:1.2.1')
}
// 打印自定义Configuration下载依赖后的文件地址
task showMyDependency {
    println configurations.myDependency.asPath
}


终端键入:gradle showMyDependency,输出结果如下:


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


还可以调 extendsFrom 方法来继承另一个Configuration的所有dependencies,比如implementation就继承了compile。


最后还得提提两个标志,默认都为true:


  • canBeResolved:编译时依赖


  • canBeConsumed:运行时依赖


0x3、依赖创建的过程


Tips:跟源码了解下原理,不感兴趣可以直接跳过,不影响后续学习~


1. 依赖识别


build.gradle 处点开 dependencies,定位到了 Project 类:


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


看注释:传递的闭包由此Project的 DependencyHandler 执行,定位到此接口:


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


可以看到每个方法都返回 Dependency 实例,点开这个接口:


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


噢吼,接口定义了获取group、name、version的方法,回到 DependencyHandleradd() 方法,最多可传递三个参数:


implementation(io.reactivex:rxandroid:1.2.1) {
    transitive = false
}
Dependency add(String configurationName, Object dependencyNotation, Closure configureClosure);
// 参数一一对应:
implementation、io.reactivex:rxandroid:1.2.1、后面跟着的大括号(依赖配置闭包)


AS只能跟到这里,接着用VS Code打开Gradle的源码,全局搜下 implements DependencyHandler,定位到 DefaultDependencyHandler 类:


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


该类除了实现 DependencyHandler 接口外,还实现了一个**MethodMixIn** 接口:


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


在讲解这个接口前,我们先来了解下Groovy语言的两个特性:invokeMethodmethodMissing,先介绍下前者:


package groovy.reflect
class InvokeTest1 {
    def hello() {
        '执行Hello方法'
    }
    def invokeMethod(String name, Object args) {
        return "未知方法 $name(${args.join(',')})"
    }
    static main(args) {
        def it = new InvokeTest1()
        println it.hello()
        println it.foo("test", 28)
    }
}
// 运行输出:
// 执行Hello方法
// 未知方法 foo(test, 28)


对于一个对象的方法调用,类中有此方法就分发给此方法,如果不能分派,就调用invokeMethod方法,而methodMissing同样能实现上面的效果:


package groovy.reflect
class InvokeTest1 {
    def hello() {
        '执行Hello方法'
    }
    def methodMissing(String name, Object args) {
        return "未知方法 $name(${args.join(',')})"
    }
    static main(args) {
        def it = new InvokeTest1()
        println it.hello()
        println it.foo("test", 28)
    }
}


输出结果相同,而在Groovy中invokeMethod是用来 分发一个对象的所有方法 (已实现和未实现)的,要借助 GroovyInterceptable 接口。而methodMissing则只能 分发一个类未实现的方法,无论它是否实现了GroovyInterceptable接口。


总结下就是:invokeMethod管理所有方法,methodMissing只管理类所有的未实现方法!


弄懂后回到 MethodMixIn 接口,其实就是Gradle对methodMissing的封装,类想要实现这个特性,只需实现此接口,接口中定义了一个抽象方法 getAdditionalMethods() 返回一个 MethodAccess 对象:


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


定义了两个方法:判断某Method是否存在,动态执行Method,如出一辙,可以,跟下 getAdditionalMethods 重写处:


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


跟下哪里给 dynamicMethods 属性赋值:


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


跟下 DynamicAddDependencyMethods


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


参数个数判断,最后都调用到 dependencyAdder.add(),而 DependencyAdder 是一个内部接口,跟下哪里实现了:


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


实际上还是调用的 DefaultDependencyHandlerdoAdd() 方法:


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


判断dependencyNotation是否为Configuration对象,如果存在,就让当前的configuration对象继承dependencyNotation,即将添加到dependencyNotation的依赖都添加到configuration中。


2. 依赖创建


往下一点,可以看到 DefaultDependencyHandler 调用 create() 方法创建了一个 Dependency 的实例,跟下:


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


跟下:DefaultDependencyFactory → createDependency()


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


调用 dependencyNotationParser 实例的 parseNotation() 创建了 Dependency 实例,往上跟下:


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


构造方法里设置了这个参数,跟下哪里传入的:


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


跟下:DependencyNotationParser → parser()


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



相关文章
|
6月前
|
SQL 人工智能 移动开发
Android Studio插件版本与Gradle 版本对应关系
Android Studio插件版本与Gradle 版本对应关系
Android Studio插件版本与Gradle 版本对应关系
|
6月前
|
Java 开发工具 Android开发
Cocos Creator 2.4.6 Android Gradle 版本升级为 6.5.1(插件4.1.0)
Cocos Creator 2.4.6 Android Gradle 版本升级为 6.5.1(插件4.1.0)
186 1
|
7月前
|
存储 Java Android开发
Android 开发 - 充分利用Gradle
Android 开发 - 充分利用Gradle
112 2
|
11月前
|
XML IDE Java
Android gradle.properties 基础使用和常规配置
Gradle 是一个开源构建自动化工具,其设计足够灵活,可以构建几乎任何类型的软件。
|
8月前
|
IDE Java 开发工具
Android Gradle plugin requires Java 11 to run. You are currently using Java 1.8的解决方案
Android Gradle plugin requires Java 11 to run. You are currently using Java 1.8的解决方案
|
4月前
|
开发工具 Android开发 开发者
Android 项目编译 Gradle 配置说明
Android 项目编译 Gradle 配置说明
151 0
|
5月前
|
Java Maven Android开发
android之gradle配置仓库与引入依赖
android之gradle配置仓库与引入依赖
235 0
|
7月前
|
Java 开发工具 Maven
Android 编译 gradle 内存 OOM 解决之路(二)
Android 编译 gradle 内存 OOM 解决之路
|
7月前
|
Java Android开发
Android 编译 gradle 内存 OOM 解决之路(一)
Android 编译 gradle 内存 OOM 解决之路
|
8月前
|
Java Shell 数据处理
Android 根目录下和应用目录下的build.gradle的详解,以及groovy语法的讲解
Android 根目录下和应用目录下的build.gradle的详解,以及groovy语法的讲解
154 0