Gradle Builds Everything —— 产物输出

in 开发 with 0 comment

Gradle 打包的时候,还有个最终要的东西 —— 产物,这里的产物包括提供给别的项目的产物,今天我们来讲一讲,产物这个东西。

首先,看下我们前面介绍了的 Configuration 对象,我们看下这个接口声明知道这个对象有incomingoutgoing两种模式,incoming 我们会用的多一点,就是从这个 Configuration 中获取产物,比如:

dependency {
    implementation `aa:bb:1.0.0`
    implementation `cc:dd:1.0.0`
}

那么我们可以使用 project.getConfigurations().maybeCreate("implementation") 获取到 implementation 相关的信息,同时使用getIncoming()拿到 ResolvableDependencies 对象,然后可以调用getFiles()等直接拿到下载的文件。但是我们前面知道,依赖下载来之后会根据一些规则做一些转换,比如我们使用的 aar 是不能直接参与编译的,需要解压,解出资源,class 文件,R.txt 等参与编译,所以如果我们想获得特定的类型,需要使用 artifactView 获取一个视图。

Outgoing 和 Configuration 的关系

以上是 incoming 的用途,也就是 ResolvableDependencies,我们现在要关注下 outgoing,就是 ConfigurationPublications,这个类用来注册产物信息。

在注册产物前,我们需要先定义一个 Configuration,因为 Configuration 里面配置了 Attributes —— 这个类用来标注产物的一些属性,只有过滤器对应上这个属性之后,我们才能获取到相关的依赖。那么我们首先想想两个项目编译
项目结构

这样的关系,我们关注到 mylibrary 产出产物,成为 Producer(P),app 消化 mylibrary 的产物,称为 Consumer(C)。

Attribute 的定义

那么这里,我们定义,P 和 C 都有一些属性(Attribute),就像一对男女朋友一样,只有对上眼了才有可能互相选择在一起,他们互相挑选的方式就是使用 Attribute,在默认情况下,只有 Attribute 「相符」的情况下才可以被 C 消费,那么怎么定义相符呢?首先默认的规则是这样的:

  1. 如果 P 和 C 都拥有一个 attr name 相同的 attr,一旦 attr 的值不一致,则判断为不匹配。
  2. 如果 P 和 C 拥有对方没有的 attr,那么认为他们依然匹配。

P 和 C 的 attr 可以设置一些规则(Rule)来解决冲突和兼容问题,主要是 AttributeCompatibilityRule 和 AttributeDisambiguationRule 这两个类。

C 去找 P 的过程就是仅仅是通过 Attribute 过滤找,没有别的要素,那么知道这个之后,我们想让 C 拿到我们的结果的时候,只要让 P 的 attribute 匹配上就好了。

综上,我们为了不污染 mylibrary 这个项目中其他的 Conguration 的配置(每个 Configuration 事实上就是一系列 配置的集合),我们需要新建一个 Configuration。 Android Gradle Plugin 比较喜欢用 "apiElements" 和 "runtimeElements" 代表编译时和运行时的依赖。

debugApiElements

我们把 Attribute 放大看全一点:

3.png

记住我们刚刚的原则:

默认情况下,如果有相关的属性,值一定是一样的。

我这里截图的是一个 application 工程,所以 AndroidTypeAttr 是 APK,如果是 AAR 的话,值就是 AAR。

我们在 Consumer 里面的 ArtifactView,先获取到引入 mylibrary 的 Configuration 名称,并设置以上的几个 Attr,就能获取到这个产物了。

Outgoing 产物设置

上面我们简单讲了下 Attribute 和 Configuration 之间的关系,后续我会专门开篇讲这个,因此我们先点到为止。
下面我们讲讲 Outgoing 的用法:

 runtimeConfig.getOutgoing()
    .variants(variants -> variants.create("xxxx-artifact", configurationVariant -> {
        configurationVariant.artifact(artifactFile, configurablePublishArtifact -> {
            configurablePublishArtifact.setType("jar"); 
            configurablePublishArtifact.builtBy(bundleArtifact);
        });
    }));

其中, configurationPublishAritfact 是 ConfigurablePublishArtifact 这个类,为 artifactFile 这个文件定义了一些,具体可以看下这个类的定义:https://docs.gradle.org/current/javadoc/org/gradle/api/artifacts/ConfigurablePublishArtifact.html

其中 setType 是设置这个文件的 artifactType,默认是文件的后缀名,如果我们改成其他 Consumer 的 ArtfactTransfomer 产物类型的话,Consumer 就能省去 Transform 这一步,直接使用我们导出的产物。

所以,从这里我们可以知道,虽然 mylibrary 的最终产物是 aar,但是 app 依赖 mylibrary 的时候,是并不需要 aar 这个产物的,因为在 aar 打包之前,这些产物都已经存在,完全没有必要再解压提取一次。

builtBy 这个是定义了产物的依赖,如果 app 在 task 执行阶段需要提取这个产物的时候,就先要执行 builtBy 的这个 Task。

从这里我们终于知道了 app 的 task 和 mylibrary 的 task 是通过产物这条链连在一起的。

结语

我们通过本文知道了 Configuration Outing 的用途,后续会跟大家进行实战项目解说,我们来自定义一个 Configuration 和产物类型,敬请期待。