美文网首页
Gradle —— 自定义 Plugin(2):NamedDom

Gradle —— 自定义 Plugin(2):NamedDom

作者: 你可记得叫安可 | 来源:发表于2019-12-19 11:31 被阅读0次

创建一个领域配置对象(DSL configuration container)

我们在 Android 的主工程 build.gradle 中一定见过以下代码:

buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
        debug {
            ...
        }
    }

上面的 releasedebug 都是我们自己取的名字,我们可以写任意多个、取任意名字,但是 releasedebug 却是内置、有限的。这是怎么实现的呢?
其实是使用了 NamedDomainObjectContainer

NamedDomainObjectContainer

下面我们来实现如下效果:

apply plugin: ServerEnvironmentPlugin

// environment 后面闭包里的内容其实是一个 container
environments {
    // 每一组都是一个 ServerEnvironment 对象
    dev {
        url = 'http://localhost:8080'
    }

    staging {
        url = 'http://staging.enterprise.com'
    }

    production {
        url = 'http://prod.enterprise.com'
    }
    ...
}

environment 是我们自定义的一个扩展名,它对应的是一个 NamedDomainObjectContainer,也就是说,在 ExtensionContainer 中,keyenvironment,而 valueNamedDomainObjectContainer 的一个实例。既然是个 Container 那么它就是一个集合,而这个集合中的元素,就是用户需要添加的。
我们先写这个集合元素类 ServerEnvironment

public class ServerEnvironment {
    private final String name;
    private Property<String> url;

    @Inject
    public ServerEnvironment(String name, ObjectFactory objectFactory) {
        this.name = name;
        this.url = objectFactory.property(String.class);
    }

    public void setUrl(String url) {
        this.url.set(url);
    }

    public String getName() {
        return name;
    }

    public Property<String> getUrl() {
        return url;
    }
}

上面的写法中,注意构造函数需要使用 @Inject 来注解,只有这样 ObjectFactory 才能被注入进来。上面例子中还是用了 Property 属性来进行延迟加载。
ServerEnvironment 就代表我们使用时的:

dev {
    url = 'http://localhost:8080'
}

下面我们来写 Plugin

public class ServerEnvironmentPlugin implements Plugin<Project> {
    @Override
    public void apply(Project target) {
        NamedDomainObjectContainer<ServerEnvironment> serverEnvironmentsContainer = target.container(ServerEnvironment.class,
                name -> target.getObjects().newInstance(ServerEnvironment.class, name, target.getObjects()));
        target.getExtensions().add("environments", serverEnvironmentsContainer);

        serverEnvironmentsContainer.all(serverEnvironment -> {
            String env = serverEnvironment.getName();
            String capitalizedServerEnv = env.substring(0, 1).toUpperCase() + env.substring(1);
            String taskName = "deployTo" + capitalizedServerEnv;
            target.getTasks().register(taskName, Deploy.class, deploy -> deploy.getUrl().set(serverEnvironment.getUrl()));
        });
    }
}
  • 首先通过方法 Project#container(Class<T> type, NamedDomainObjectFactory<T> factory) 创建一个NamedDomainObjectContainer 对象。第二个参数是 NamedDomainObjectFactory 它只有一个方法,接收一个 String 类型的 name。这个 name 就是我们写代码时那个自定义的名字,也就是上面例子中的 dev, staging, production。然后通过 Project#getObjects()#newInstance() 来实例化一个 ServerEnvironment 对象。注意,newInstance() 方法第一个是我们要实例化的类型Class,后面的参数就是 ServerEnvironment 构造方法接收的参数列表。
  • 我们向 ProjectExtensionContainer 中添加一个元素,它的keyenvironmentsvalue 为上面实例化出来的 serverEnvironemtContainer 对象。这样我们就可以在代码中使用 environments
  • 遍历 serverEnvironmentContainer,根据 ServerEnvironment 中的内容动态注册 Task

我们此时再执行 gradle tasks --all,就能看到我们动态注册的 Task 了。

tasks

我们执行 deployToDev 就可以得到我们想要的结果。

deployToDev

相关文章

网友评论

      本文标题:Gradle —— 自定义 Plugin(2):NamedDom

      本文链接:https://www.haomeiwen.com/subject/ttlpnctx.html