Gradle的settings.gradle.kts你真的理解吗?

你还在用.gradle文件吗?例如build.gradle、settings.gradle,那么你就out了。现在我们有必要了解一下kts脚本了。在Android项目中,默认有3个文件可以替换成kts脚本,即project的build.gradle、app模块的build.gradle和project的settings.gradle,它们更名后分别为build.gradle.kts、build.gradle.kts和settings.gradle.kts。

settings.gradle简介

我们的gradle脚本本质上是执行一个个gradle plugin,即apply plugin,可以执行外部导入的,也可以执行项目编写的编译脚本代码。所以settings.gradle.kts也是编译过程中一个gradle plugin。在 org.gradle.initialization.DefaultSettings中有个getSettings方法,调用这个方法拿到我们配置的settings gradle plugin。settings.gradle.kts中可以配置的内容我们参考Settings这个类。在settings.gradle.kts这个文件中,主要配置一些项目全局的设置。

Settings全局设置解析

java 复制代码
package org.gradle.api.initialization;

import org.gradle.StartParameter;
import org.gradle.api.Action;
import org.gradle.api.Incubating;
import org.gradle.api.UnknownProjectException;
import org.gradle.api.initialization.dsl.ScriptHandler;
import org.gradle.api.initialization.resolve.DependencyResolutionManagement;
import org.gradle.api.invocation.Gradle;
import org.gradle.api.plugins.ExtensionAware;
import org.gradle.api.plugins.PluginAware;
import org.gradle.api.provider.Provider;
import org.gradle.api.provider.ProviderFactory;
import org.gradle.api.toolchain.management.ToolchainManagement;
import org.gradle.api.cache.CacheConfigurations;
import org.gradle.caching.configuration.BuildCacheConfiguration;
import org.gradle.internal.HasInternalProtocol;
import org.gradle.plugin.management.PluginManagementSpec;
import org.gradle.vcs.SourceControl;

import javax.annotation.Nullable;
import java.io.File;
import java.util.Arrays;

/**
 * <p>Declares the configuration required to instantiate and configure the hierarchy of {@link
 * org.gradle.api.Project} instances which are to participate in a build.</p>
 *
 * <p>There is a one-to-one correspondence between a <code>Settings</code> instance and a <code>{@value
 * #DEFAULT_SETTINGS_FILE}</code> settings file. Before Gradle assembles the projects for a build, it creates a
 * <code>Settings</code> instance and executes the settings file against it.</p>
 *
 * <h3>Assembling a Multi-Project Build</h3>
 *
 * <p>One of the purposes of the <code>Settings</code> object is to allow you to declare the projects which are to be
 * included in the build. You add projects to the build using the {@link #include(String...)} method.  There is always a
 * root project included in a build.  It is added automatically when the <code>Settings</code> object is created.  The
 * root project's name defaults to the name of the directory containing the settings file. The root project's project
 * directory defaults to the directory containing the settings file.</p>
 *
 * <p>When a project is included in the build, a {@link ProjectDescriptor} is created. You can use this descriptor to
 * change the default values for several properties of the project.</p>
 *
 * <h3>Using Settings in a Settings File</h3>
 *
 * <h4>Dynamic Properties</h4>
 *
 * <p>In addition to the properties of this interface, the {@code Settings} object makes some additional read-only
 * properties available to the settings script. This includes properties from the following sources:</p>
 *
 * <ul>
 *
 * <li>Defined in the {@value org.gradle.api.Project#GRADLE_PROPERTIES} file located in the settings directory of the
 * build.</li>
 *
 * <li>Defined the {@value org.gradle.api.Project#GRADLE_PROPERTIES} file located in the user's {@code .gradle}
 * directory.</li>
 *
 * <li>Provided on the command-line using the -P option.</li>
 *
 * </ul>
 */
@HasInternalProtocol
public interface Settings extends PluginAware, ExtensionAware {
    /**
     * <p>The default name for the settings file.</p>
     */
    String DEFAULT_SETTINGS_FILE = "settings.gradle";

    /**
     * <p>Adds the given projects to the build. Each path in the supplied list is treated as the path of a project to
     * add to the build. Note that these path are not file paths, but instead specify the location of the new project in
     * the project hierarchy. As such, the supplied paths must use the ':' character as separator (and NOT '/').</p>
     *
     * <p>The last element of the supplied path is used as the project name. The supplied path is converted to a project
     * directory relative to the root project directory. The project directory can be altered by changing the 'projectDir'
     * property after the project has been included (see {@link ProjectDescriptor#setProjectDir(File)})</p>
     *
     * <p>As an example, the path {@code a:b} adds a project with path {@code :a:b}, name {@code b} and project
     * directory {@code $rootDir/a/b}. It also adds the a project with path {@code :a}, name {@code a} and project
     * directory {@code $rootDir/a}, if it does not exist already.</p>
     *
     * <p>Some common examples of using the project path are:</p>
     *
     * <pre class='autoTestedSettings'>
     *   // include two projects, 'foo' and 'foo:bar'
     *   // directories are inferred by replacing ':' with '/'
     *   include 'foo:bar'
     *
     *   // include one project whose project dir does not match the logical project path
     *   include 'baz'
     *   project(':baz').projectDir = file('foo/baz')
     *
     *   // include many projects whose project dirs do not match the logical project paths
     *   file('subprojects').eachDir { dir -&gt;
     *     include dir.name
     *     project(":${dir.name}").projectDir = dir
     *   }
     * </pre>
     *
     * @param projectPaths the projects to add.
     */
    default void include(String... projectPaths) {
        include(Arrays.asList(projectPaths));
    }

    /**
     * <p>Adds the given projects to the build. Each path in the supplied list is treated as the path of a project to
     * add to the build. Note that these path are not file paths, but instead specify the location of the new project in
     * the project hierarchy. As such, the supplied paths must use the ':' character as separator (and NOT '/').</p>
     *
     * <p>The last element of the supplied path is used as the project name. The supplied path is converted to a project
     * directory relative to the root project directory. The project directory can be altered by changing the 'projectDir'
     * property after the project has been included (see {@link ProjectDescriptor#setProjectDir(File)})</p>
     *
     * <p>As an example, the path {@code a:b} adds a project with path {@code :a:b}, name {@code b} and project
     * directory {@code $rootDir/a/b}. It also adds the a project with path {@code :a}, name {@code a} and project
     * directory {@code $rootDir/a}, if it does not exist already.</p>
     *
     * <p>Some common examples of using the project path are:</p>
     *
     * <pre class='autoTestedSettings'>
     *   // include two projects, 'foo' and 'foo:bar'
     *   // directories are inferred by replacing ':' with '/'
     *   include(['foo:bar'])
     *
     *   // include one project whose project dir does not match the logical project path
     *   include(['baz'])
     *   project(':baz').projectDir = file('foo/baz')
     *
     *   // include many projects whose project dirs do not match the logical project paths
     *   file('subprojects').eachDir { dir -&gt;
     *     include([dir.name])
     *     project(":${dir.name}").projectDir = dir
     *   }
     * </pre>
     *
     * @param projectPaths the projects to add.
     *
     * @since 7.4
     */
    void include(Iterable<String> projectPaths);

    /**
     * <p>Adds the given projects to the build. Each name in the supplied list is treated as the name of a project to
     * add to the build.</p>
     *
     * <p>The supplied name is converted to a project directory relative to the <em>parent</em> directory of the root
     * project directory.</p>
     *
     * <p>As an example, the name {@code a} add a project with path {@code :a}, name {@code a} and project directory
     * {@code $rootDir/../a}.</p>
     *
     * @param projectNames the projects to add.
     */
    default void includeFlat(String... projectNames) {
        includeFlat(Arrays.asList(projectNames));
    }

    /**
     * <p>Adds the given projects to the build. Each name in the supplied list is treated as the name of a project to
     * add to the build.</p>
     *
     * <p>The supplied name is converted to a project directory relative to the <em>parent</em> directory of the root
     * project directory.</p>
     *
     * <p>As an example, the name {@code a} add a project with path {@code :a}, name {@code a} and project directory
     * {@code $rootDir/../a}.</p>
     *
     * @param projectNames the projects to add.
     *
     * @since 7.4
     */
    void includeFlat(Iterable<String> projectNames);

    /**
     * <p>Returns this settings object.</p>
     *
     * @return This settings object. Never returns null.
     */
    Settings getSettings();

    /**
     * Returns the build script handler for settings. You can use this handler to query details about the build
     * script for settings, and manage the classpath used to compile and execute the settings script.
     *
     * @return the classpath handler. Never returns null.
     *
     * @since 4.4
     */
    ScriptHandler getBuildscript();

    /**
     * <p>Returns the settings directory of the build. The settings directory is the directory containing the settings
     * file.</p>
     *
     * @return The settings directory. Never returns null.
     */
    File getSettingsDir();

    /**
     * <p>Returns the root directory of the build. The root directory is the project directory of the root project.</p>
     *
     * @return The root directory. Never returns null.
     */
    File getRootDir();

    /**
     * <p>Returns the root project of the build.</p>
     *
     * @return The root project. Never returns null.
     */
    ProjectDescriptor getRootProject();

    /**
     * <p>Returns the project with the given path.</p>
     *
     * @param path The path.
     * @return The project with the given path. Never returns null.
     * @throws UnknownProjectException If no project with the given path exists.
     */
    ProjectDescriptor project(String path) throws UnknownProjectException;

    /**
     * <p>Returns the project with the given path.</p>
     *
     * @param path The path
     * @return The project with the given path. Returns null if no such project exists.
     */
    @Nullable
    ProjectDescriptor findProject(String path);

    /**
     * <p>Returns the project with the given project directory.</p>
     *
     * @param projectDir The project directory.
     * @return The project with the given project directory. Never returns null.
     * @throws UnknownProjectException If no project with the given path exists.
     */
    ProjectDescriptor project(File projectDir) throws UnknownProjectException;

    /**
     * <p>Returns the project with the given project directory.</p>
     *
     * @param projectDir The project directory.
     * @return The project with the given project directory. Returns null if no such project exists.
     */
    @Nullable
    ProjectDescriptor findProject(File projectDir);

    /**
     * <p>Returns the set of parameters used to invoke this instance of Gradle.</p>
     *
     * @return The parameters. Never returns null.
     */
    StartParameter getStartParameter();

    /**
     * Provides access to methods to create various kinds of {@link Provider} instances.
     *
     * @since 6.8
     */
    ProviderFactory getProviders();

    /**
     * Returns the {@link Gradle} instance for the current build.
     *
     * @return The Gradle instance. Never returns null.
     */
    Gradle getGradle();

    /**
     * Includes a build at the specified path to the composite build.
     * @param rootProject The path to the root project directory for the build.
     *
     * @since 3.1
     */
    void includeBuild(Object rootProject);

    /**
     * Includes a build at the specified path to the composite build, with the supplied configuration.
     * @param rootProject The path to the root project directory for the build.
     * @param configuration An action to configure the included build.
     *
     * @since 3.1
     */
    void includeBuild(Object rootProject, Action<ConfigurableIncludedBuild> configuration);

    /**
     * Returns the build cache configuration.
     *
     * @since 3.5
     */
    BuildCacheConfiguration getBuildCache();

    /**
     * Configures build cache.
     *
     * @since 3.5
     */
    void buildCache(Action<? super BuildCacheConfiguration> action);

    /**
     * Configures plugin management.
     *
     * @since 3.5
     */
    void pluginManagement(Action<? super PluginManagementSpec> pluginManagementSpec);

    /**
     * Returns the plugin management configuration.
     *
     * @since 3.5
     */
    PluginManagementSpec getPluginManagement();

    /**
     * Configures source control.
     *
     * @since 4.4
     */
    void sourceControl(Action<? super SourceControl> configuration);

    /**
     * Returns the source control configuration.
     *
     * @since 4.4
     */
    SourceControl getSourceControl();

    /**
     * Enables a feature preview by name.
     *
     * @param name the name of the feature to enable
     *
     * @since 4.6
     */
    void enableFeaturePreview(String name);

    /**
     * Configures the cross-project dependency resolution aspects
     * @param dependencyResolutionConfiguration the configuration
     *
     * @since 6.8
     */
    void dependencyResolutionManagement(Action<? super DependencyResolutionManagement> dependencyResolutionConfiguration);

    /**
     * Returns the dependency resolution management handler.
     *
     * @since 6.8
     */
    DependencyResolutionManagement getDependencyResolutionManagement();

    /**
     * Configures toolchain management.
     *
     * @since 7.6
     */
    @Incubating
    void toolchainManagement(Action<? super ToolchainManagement> toolchainManagementConfiguration);

    /**
     * Returns the toolchain management configuration.
     *
     * @since 7.6
     */
    @Incubating
    ToolchainManagement getToolchainManagement();

    /**
     * Returns the configuration for caches stored in the user home directory.
     *
     * @since 8.0
     */
    @Incubating
    CacheConfigurations getCaches();

    /**
     * Configures the settings for caches stored in the user home directory.
     *
     * @param cachesConfiguration the configuration
     *
     * @since 8.0
     */
    @Incubating
    void caches(Action<? super CacheConfigurations> cachesConfiguration);
}

比如要索引哪些模块。

kts 复制代码
include(":app")

以及项目的编译期间的名称。

kts 复制代码
rootProject.name = "DoraMusic"

PluginManagementSpec插件管理规格

我们可以看到,在这里我们还可以配置pluginManagement函数,pluginManagement传入的是一个PluginManagementSpec。

java 复制代码
package org.gradle.plugin.management;

import org.gradle.api.Action;
import org.gradle.api.artifacts.dsl.RepositoryHandler;
import org.gradle.api.initialization.ConfigurableIncludedPluginBuild;
import org.gradle.internal.HasInternalProtocol;
import org.gradle.plugin.use.PluginDependenciesSpec;

/**
 * Configures how plugins are resolved.
 *
 * @since 3.5
 */
@HasInternalProtocol
public interface PluginManagementSpec {

    /**
     * Defines the plugin repositories to use.
     */
    void repositories(Action<? super RepositoryHandler> repositoriesAction);

    /**
     * The plugin repositories to use.
     */
    RepositoryHandler getRepositories();

    /**
     * Configure the plugin resolution strategy.
     */
    void resolutionStrategy(Action<? super PluginResolutionStrategy> action);

    /**
     * The plugin resolution strategy.
     */
    PluginResolutionStrategy getResolutionStrategy();

    /**
     * Configure the default plugin versions.
     * @since 5.6
     */
    void plugins(Action<? super PluginDependenciesSpec> action);

    /**
     * The Plugin dependencies, permitting default plugin versions to be configured.
     * @since 5.6
     */
    PluginDependenciesSpec getPlugins();

    /**
     * Includes a plugin build at the specified path to the composite build.
     * Included plugin builds can contribute settings and project plugins.
     * @param rootProject The path to the root project directory for the build.
     *
     * @since 7.0
     */
    void includeBuild(String rootProject);

    /**
     * Includes a plugin build at the specified path to the composite build, with the supplied configuration.
     * Included plugin builds can contribute settings and project plugins.
     * @param rootProject The path to the root project directory for the build.
     * @param configuration An action to configure the included build.
     *
     * @since 7.0
     */
    void includeBuild(String rootProject, Action<ConfigurableIncludedPluginBuild> configuration);

}

在PluginManagementSpec的源码中,我们可以得知,这个高阶函数传入的block可以配置repositories、resolutionStrategy、plugins、includeBuild这几个函数。我们用的比较多的是前面三个。我们再细看repositories,需要传入的是Action<? super RepositoryHandler>,那么问题来了,我明明是要传入的Action,怎么编译器提示的是Action里面的泛型类。 比如:

kts 复制代码
pluginManagement {
    repositories {
        gradlePluginPortal()
        google()
        mavenCentral()
        maven { setUrl("xxx")
    }
}

不信你就看,this指代的是RepositoryHandler。我们观摩一下Action类。

java 复制代码
package org.gradle.api;

/**
 * Performs some action against objects of type T.
 *
 * @param <T> The type of object which this action accepts.
 */
@HasImplicitReceiver
public interface Action<T> {
    /**
     * Performs this action against the given object.
     *
     * @param t The object to perform the action on.
     */
    void execute(T t);
}

如果你理解T.() -> Unit,那么就会很好理解这个概念了。这里其实是kotlin的一个高级的用法,SAM接口。Kotlin中的SAM接口是指"Single Abstract Method"接口,它也被称为函数式接口。在Kotlin中,可以使用lambda表达式来代替这些只有一个抽象方法的接口。通过使用lambda表达式,可以更简洁地表示函数或方法。

Kotlin的SAM转换是指将lambda表达式转换为这些SAM接口的实例,从而可以像使用普通函数一样使用它们。这在使用Java的库或与Java代码交互时特别有用,因为在Java中,通常需要使用匿名内部类来实现SAM接口,而在Kotlin中可以直接使用lambda表达式。

例如,如果有一个只有一个抽象方法的Java接口OnClickListener,在Kotlin中可以这样使用lambda表达式来代替:

kotlin 复制代码
button.setOnClickListener { view ->
    // 点击事件的处理逻辑
}

这样我们就好理解为什么这么配置RepositoryHandler了。

java 复制代码
/*
 * Copyright 2009 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.gradle.api.artifacts.dsl;

import groovy.lang.Closure;
import groovy.lang.DelegatesTo;
import org.gradle.api.Action;
import org.gradle.api.artifacts.ArtifactRepositoryContainer;
import org.gradle.api.artifacts.repositories.ArtifactRepository;
import org.gradle.api.artifacts.repositories.ExclusiveContentRepository;
import org.gradle.api.artifacts.repositories.FlatDirectoryArtifactRepository;
import org.gradle.api.artifacts.repositories.IvyArtifactRepository;
import org.gradle.api.artifacts.repositories.MavenArtifactRepository;
import org.gradle.internal.HasInternalProtocol;

import java.util.Map;

/**
 * A {@code RepositoryHandler} manages a set of repositories, allowing repositories to be defined and queried.
 */
@HasInternalProtocol
public interface RepositoryHandler extends ArtifactRepositoryContainer {

    /**
     * Adds a resolver that looks into a number of directories for artifacts. The artifacts are expected to be located in the
     * root of the specified directories. The resolver ignores any group/organization information specified in the
     * dependency section of your build script. If you only use this kind of resolver you might specify your
     * dependencies like <code>":junit:4.4"</code> instead of <code>"junit:junit:4.4"</code>.
     *
     * The following parameter are accepted as keys for the map:
     *
     * <table summary="Shows property keys and associated values">
     * <tr><th>Key</th>
     *     <th>Description of Associated Value</th></tr>
     * <tr><td><code>name</code></td>
     *     <td><em>(optional)</em> The name of the repository.
     * The default is a Hash value of the rootdir paths. The name is used in the console output,
     * to point to information related to a particular repository. A name must be unique amongst a repository group.</td></tr>
     * <tr><td><code>dirs</code></td>
     *     <td>Specifies a list of rootDirs where to look for dependencies. These are evaluated as per {@link org.gradle.api.Project#files(Object...)}</td></tr>
     * </table>
     *
     * <p>Examples:</p>
     * <pre class='autoTested'>
     * repositories {
     *     flatDir name: 'libs', dirs: "$projectDir/libs"
     *     flatDir dirs: ["$projectDir/libs1", "$projectDir/libs2"]
     * }
     * </pre>
     *
     * @param args The arguments used to configure the repository.
     * @return the added resolver
     * @throws org.gradle.api.InvalidUserDataException In the case neither rootDir nor rootDirs is specified of if both
     * are specified.
     */
    FlatDirectoryArtifactRepository flatDir(Map<String, ?> args);

    /**
     * Adds and configures a repository which will look for dependencies in a number of local directories.
     *
     * @param configureClosure The closure to execute to configure the repository.
     * @return The repository.
     */
    FlatDirectoryArtifactRepository flatDir(@DelegatesTo(FlatDirectoryArtifactRepository.class) Closure configureClosure);

    /**
     * Adds and configures a repository which will look for dependencies in a number of local directories.
     *
     * @param action The action to execute to configure the repository.
     * @return The repository.
     */
    FlatDirectoryArtifactRepository flatDir(Action<? super FlatDirectoryArtifactRepository> action);

    /**
     * Adds a repository which looks in Gradle Central Plugin Repository for dependencies.
     *
     * @return The Gradle Central Plugin Repository
     * @since 4.4
     */
    ArtifactRepository gradlePluginPortal();

    /**
     * Adds a repository which looks in Gradle Central Plugin Repository for dependencies.
     *
     * @param action a configuration action
     * @return the added resolver
     * @since 5.4
     */
    ArtifactRepository gradlePluginPortal(Action<? super ArtifactRepository> action);

    /**
     * Adds a repository which looks in Bintray's JCenter repository for dependencies.
     * <p>
     * The URL used to access this repository is {@literal "https://jcenter.bintray.com/"}.
     * The behavior of this repository is otherwise the same as those added by {@link #maven(org.gradle.api.Action)}.
     * <p>
     * Examples:
     * <pre class='autoTestedWithDeprecations'>
     * repositories {
     *   jcenter {
     *     artifactUrls = ["http://www.mycompany.com/artifacts1", "http://www.mycompany.com/artifacts2"]
     *   }
     *   jcenter {
     *     name = "nonDefaultName"
     *     artifactUrls = ["http://www.mycompany.com/artifacts1"]
     *   }
     * }
     * </pre>
     *
     * @param action a configuration action
     * @return the added repository
     * @deprecated JFrog announced JCenter's <a href="https://blog.gradle.org/jcenter-shutdown">sunset</a> in February 2021. Use {@link #mavenCentral()} instead.
     */
    @Deprecated
    MavenArtifactRepository jcenter(Action<? super MavenArtifactRepository> action);

    /**
     * Adds a repository which looks in Bintray's JCenter repository for dependencies.
     * <p>
     * The URL used to access this repository is {@literal "https://jcenter.bintray.com/"}.
     * The behavior of this repository is otherwise the same as those added by {@link #maven(org.gradle.api.Action)}.
     * <p>
     * Examples:
     * <pre class='autoTestedWithDeprecations'>
     * repositories {
     *     jcenter()
     * }
     * </pre>
     *
     * @return the added resolver
     * @see #jcenter(Action)
     * @deprecated JFrog announced JCenter's <a href="https://blog.gradle.org/jcenter-shutdown">sunset</a> in February 2021. Use {@link #mavenCentral()} instead.
     */
    @Deprecated
    MavenArtifactRepository jcenter();

    /**
     * Adds a repository which looks in the Maven central repository for dependencies. The URL used to access this repository is
     * {@value org.gradle.api.artifacts.ArtifactRepositoryContainer#MAVEN_CENTRAL_URL}.
     *
     * <p>The following parameter are accepted as keys for the map:
     *
     * <table summary="Shows property keys and associated values">
     * <tr><th>Key</th>
     *     <th>Description of Associated Value</th></tr>
     * <tr><td><code>name</code></td>
     *     <td><em>(optional)</em> The name of the repository. The default is
     * {@value org.gradle.api.artifacts.ArtifactRepositoryContainer#DEFAULT_MAVEN_CENTRAL_REPO_NAME} is used as the name. A name
     * must be unique amongst a repository group.
     * </td></tr>
     * <tr><td><code>artifactUrls</code></td>
     *     <td>A single jar repository or a collection of jar repositories containing additional artifacts not found in the Maven central repository.
     * But be aware that the POM must exist in Maven central.
     * The provided values are evaluated as per {@link org.gradle.api.Project#uri(Object)}.</td></tr>
     * </table>
     *
     * <p>Examples:</p>
     * <pre class='autoTested'>
     * repositories {
     *     mavenCentral artifactUrls: ["http://www.mycompany.com/artifacts1", "http://www.mycompany.com/artifacts2"]
     *     mavenCentral name: "nonDefaultName", artifactUrls: ["http://www.mycompany.com/artifacts1"]
     * }
     * </pre>
     *
     * @param args A list of urls of repositories to look for artifacts only.
     * @return the added repository
     */
    MavenArtifactRepository mavenCentral(Map<String, ?> args);

    /**
     * Adds a repository which looks in the Maven central repository for dependencies. The URL used to access this repository is
     * {@value org.gradle.api.artifacts.ArtifactRepositoryContainer#MAVEN_CENTRAL_URL}. The name of the repository is
     * {@value org.gradle.api.artifacts.ArtifactRepositoryContainer#DEFAULT_MAVEN_CENTRAL_REPO_NAME}.
     *
     * <p>Examples:</p>
     * <pre class='autoTested'>
     * repositories {
     *     mavenCentral()
     * }
     * </pre>
     *
     * @return the added resolver
     * @see #mavenCentral(java.util.Map)
     */
    MavenArtifactRepository mavenCentral();

    /**
     * Adds a repository which looks in the Maven central repository for dependencies. The URL used to access this repository is
     * {@value org.gradle.api.artifacts.ArtifactRepositoryContainer#MAVEN_CENTRAL_URL}. The name of the repository is
     * {@value org.gradle.api.artifacts.ArtifactRepositoryContainer#DEFAULT_MAVEN_CENTRAL_REPO_NAME}.
     *
     * <p>Examples:</p>
     * <pre class='autoTested'>
     * repositories {
     *     mavenCentral()
     * }
     * </pre>
     *
     * @param action a configuration action
     * @return the added resolver
     * @since 5.3
     */
    MavenArtifactRepository mavenCentral(Action<? super MavenArtifactRepository> action);

    /**
     * Adds a repository which looks in the local Maven cache for dependencies. The name of the repository is
     * {@value org.gradle.api.artifacts.ArtifactRepositoryContainer#DEFAULT_MAVEN_LOCAL_REPO_NAME}.
     *
     * <p>Examples:</p>
     * <pre class='autoTested'>
     * repositories {
     *     mavenLocal()
     * }
     * </pre>
     * <p>
     * The location for the repository is determined as follows (in order of precedence):
     * </p>
     * <ol>
     * <li>The value of system property 'maven.repo.local' if set;</li>
     * <li>The value of element &lt;localRepository&gt; of <code>~/.m2/settings.xml</code> if this file exists and element is set;</li>
     * <li>The value of element &lt;localRepository&gt; of <code>$M2_HOME/conf/settings.xml</code> (where <code>$M2_HOME</code> is the value of the environment variable with that name) if this file exists and element is set;</li>
     * <li>The path <code>~/.m2/repository</code>.</li>
     * </ol>
     *
     * @return the added resolver
     */
    MavenArtifactRepository mavenLocal();

    /**
     * Adds a repository which looks in the local Maven cache for dependencies. The name of the repository is
     * {@value org.gradle.api.artifacts.ArtifactRepositoryContainer#DEFAULT_MAVEN_LOCAL_REPO_NAME}.
     *
     * <p>Examples:</p>
     * <pre class='autoTested'>
     * repositories {
     *     mavenLocal()
     * }
     * </pre>
     * <p>
     * The location for the repository is determined as follows (in order of precedence):
     * </p>
     * <ol>
     * <li>The value of system property 'maven.repo.local' if set;</li>
     * <li>The value of element &lt;localRepository&gt; of <code>~/.m2/settings.xml</code> if this file exists and element is set;</li>
     * <li>The value of element &lt;localRepository&gt; of <code>$M2_HOME/conf/settings.xml</code> (where <code>$M2_HOME</code> is the value of the environment variable with that name) if this file exists and element is set;</li>
     * <li>The path <code>~/.m2/repository</code>.</li>
     * </ol>
     *
     * @param action a configuration action
     * @return the added resolver
     * @since 5.3
     */
    MavenArtifactRepository mavenLocal(Action<? super MavenArtifactRepository> action);

    /**
     * Adds a repository which looks in Google's Maven repository for dependencies.
     * <p>
     * The URL used to access this repository is {@literal "https://dl.google.com/dl/android/maven2/"}.
     * <p>
     * Examples:
     * <pre class='autoTested'>
     * repositories {
     *     google()
     * }
     * </pre>
     *
     * @return the added resolver
     * @since 4.0
     */
    MavenArtifactRepository google();

    /**
     * Adds a repository which looks in Google's Maven repository for dependencies.
     * <p>
     * The URL used to access this repository is {@literal "https://dl.google.com/dl/android/maven2/"}.
     * <p>
     * Examples:
     * <pre class='autoTested'>
     * repositories {
     *     google()
     * }
     * </pre>
     *
     * @param action a configuration action
     * @return the added resolver
     * @since 5.3
     */
    MavenArtifactRepository google(Action<? super MavenArtifactRepository> action);

    /**
     * Adds and configures a Maven repository. Newly created instance of {@code MavenArtifactRepository} is passed as an argument to the closure.
     *
     * @param closure The closure to use to configure the repository.
     * @return The added repository.
     */
    MavenArtifactRepository maven(@DelegatesTo(MavenArtifactRepository.class) Closure closure);

    /**
     * Adds and configures a Maven repository.
     *
     * @param action The action to use to configure the repository.
     * @return The added repository.
     */
    MavenArtifactRepository maven(Action<? super MavenArtifactRepository> action);

    /**
     * Adds and configures an Ivy repository. Newly created instance of {@code IvyArtifactRepository} is passed as an argument to the closure.
     *
     * @param closure The closure to use to configure the repository.
     * @return The added repository.
     */
    IvyArtifactRepository ivy(@DelegatesTo(IvyArtifactRepository.class) Closure closure);

    /**
     * Adds and configures an Ivy repository.
     *
     * @param action The action to use to configure the repository.
     * @return The added repository.
     */
    IvyArtifactRepository ivy(Action<? super IvyArtifactRepository> action);

    /**
     * Declares exclusive content repositories. Exclusive content repositories are
     * repositories for which you can declare an inclusive content filter. Artifacts
     * matching the filter will then only be searched in the repositories which
     * exclusively match it.
     *
     * @param action the configuration of the repositories
     *
     * @since 6.2
     */
    void exclusiveContent(Action<? super ExclusiveContentRepository> action);
}

PluginResolutionStrategy插件解决策略

接下来我们看resolutionStrategy,它传入的是一个PluginResolutionStrategy。Kotlin DSL中有大量Action的用法。

kts 复制代码
pluginManagement {
    resolutionStrategy {
        eachPlugin {
            if (requested.id.namespace == "com.android.tools.build") {
                useModule("com.android.tools.build:gradle:7.1.2")
            }
            if (requested.id.namespace == "com.google.firebase") {
                useModule("com.google.firebase:firebase-crashlytics-gradle:2.9.2")
            }
        }
    }
}
java 复制代码
package org.gradle.plugin.management;

import org.gradle.api.Action;
import org.gradle.internal.HasInternalProtocol;

/**
 * Allows modification of {@link PluginRequest}s before they are resolved.
 *
 * @since 3.5
 */
@HasInternalProtocol
public interface PluginResolutionStrategy {

    /**
     * Adds an action that is executed for each plugin that is resolved.
     * The {@link PluginResolveDetails} parameter contains information about
     * the plugin that was requested and allows the rule to modify which plugin
     * will actually be resolved.
     */
    void eachPlugin(Action<? super PluginResolveDetails> rule);

}
java 复制代码
package org.gradle.plugin.management;

import javax.annotation.Nullable;

/**
 * Allows plugin resolution rules to inspect a requested plugin and modify which
 * target plugin will be used.
 *
 * @since 3.5
 */
public interface PluginResolveDetails {

    /**
     * Get the plugin that was requested.
     */
    PluginRequest getRequested();

    /**
     * Sets the implementation module to use for this plugin.
     *
     * @param notation the module to use, supports the same notations as {@link org.gradle.api.artifacts.dsl.DependencyHandler}
     */
    void useModule(Object notation);

    /**
     * Sets the version of the plugin to use.
     *
     * @param version version to use
     */
    void useVersion(@Nullable String version);

    /**
     * The target plugin request to use.
     */
    PluginRequest getTarget();

}

PluginResolveDetails这个类用来允许插件解析规则检查请求的插件并修改将使用目标插件。

DependencyResolutionManagement依赖解决管理

我们再来看看dependencyResolutionManagement和要传入DependencyResolutionManagement。这个类字面意思就告诉我们用来指定依赖解决管理,简单来说,就是我们项目中的那些implementation依赖的库等,从哪些库里面找。

kts 复制代码
dependencyResolutionManagement {
    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
    repositories {
        google()
        mavenCentral()
        maven {  setUrl("https://jitpack.io") }
    }
}

这里简单讲解下RepositoriesMode。

java 复制代码
package org.gradle.api.initialization.resolve;

import org.gradle.api.Incubating;

/**
 * The repository mode configures how repositories are setup in the build.
 *
 * @since 6.8
 */
@Incubating
public enum RepositoriesMode {
    /**
     * If this mode is set, any repository declared on a project will cause
     * the project to use the repositories declared by the project, ignoring
     * those declared in settings.
     *
     * This is the default behavior.
     */
    PREFER_PROJECT,

    /**
     * If this mode is set, any repository declared directly in a project,
     * either directly or via a plugin, will be ignored.
     */
    PREFER_SETTINGS,

    /**
     * If this mode is set, any repository declared directly in a project,
     * either directly or via a plugin, will trigger a build error.
     */
    FAIL_ON_PROJECT_REPOS;
}

PREFER_PROJECT表示,如果设置此模式,项目上声明的任何存储库都会导致项目使用项目声明的存储库,忽略在设置中声明的,简单来说就是项目中的存储库优先使用。这也是默认的模式。如果PREFER_SETTINGS,则正好相反。FAIL_ON_PROJECT_REPOS则表示,强制使用设置中的存储库。建议修改模式为FAIL_ON_PROJECT_REPOS强制全局都使用设置中的存储库,方便管理。无论你使用何种模式,你在dependencyResolutionManagement中配置下就能确保可以使用。

相关推荐
Meteors.1 小时前
Android约束布局(ConstraintLayout)常用属性
android
alexhilton1 小时前
玩转Shader之学会如何变形画布
android·kotlin·android jetpack
whysqwhw6 小时前
安卓图片性能优化技巧
android
风往哪边走6 小时前
自定义底部筛选弹框
android
Yyyy4827 小时前
MyCAT基础概念
android
Android轮子哥7 小时前
尝试解决 Android 适配最后一公里
android
雨白8 小时前
OkHttp 源码解析:enqueue 非同步流程与 Dispatcher 调度
android
风往哪边走9 小时前
自定义仿日历组件弹框
android
没有了遇见9 小时前
Android 外接 U 盘开发实战:从权限到文件复制
android
Monkey-旭10 小时前
Android 文件存储机制全解析
android·文件存储·kolin