Gradle系列(3)——Gradle extension(gradle扩展),如何自定义gradle扩展,AppPlugin,AppExtension原理

Android Gradle扩展「Android Gradle Extension」-crx插件 在developer.android.com中为类引用添加Gradle依赖文本。 一个Chrome扩展程序,添加了Gradle依赖项以用于Android API类参考页。 然后,用户可以复制Gradle依赖项文本并在其代码中使用它。 Android是Google Inc.的商标。GradleGradle,Inc.的商标。图标是从Android Asset Studio生成的。 支持语言:English 立即下载


系列: Gradle系列(2)——如何自定以Gradle 插件

在上一篇Gradle系列(2)——如何自定以Gradle 插件 中,我们了解了什么是 Gradle Plugin以及如何用Gradle Plugin在项目构建中实现更多强力而有趣的功能。尽管在demo中我们已经实现了在整个公司的不同团队通过本地json文件实现平台化的配置,但是仍然存在某个项目需要个性化的配置,或者在构建过程中需要一些灵活便捷的自定义的构建,那么上一篇实现的功能就不能满足我们的需求,于是本篇就引入了如何自定义Gradle Extensions


1.什么是Extensions

  • 我们其实经常接触Gradle Extension

Gradle Extensions 是Gradle Plugin 的一种扩展机制,通过实现自定义的Extension,我们可以在Gradle 脚本(例如build.gradle)中增加自己的配置,例如android(其实例为com.android.build.gradle.internal.dsl.BaseAppModuleExtensioncom.android.build.gradle.LibraryExtension),
Gradle在configuration阶段可以读取这些配置里面的内容。

2.如何自定义Extension

关于这点,百度搜索有许多好多大量海量千篇一律毫无区别的帖子告诉你怎么定义一个自定义扩展并注册,我不再展开,就按照他们写的简单写个小demo

  • 定义一个扩展

public class TestExtension {

    public String anyString;
}

  • 在Plugin实现类注册这个扩展

public class RocketPlugin implements Plugin<Project>  {

    @Override
    public void apply(Project project) {
        super.apply(project);
        project.getExtensions().create("anyTest", TestExtension.class);
    }
}


我们给build.gradle内注册了一个TestExtension的实例,名字为anyTest

  • 使用这个扩展
    在app/library build.gradle内
plugins {
    id("com.android.application")
    id("gradle-rocket")
}

anyTest{
    topic = "extension test"
}

  • 获取插件的配置信息

在Plugin实现类内:


public class RocketPlugin implements Plugin<Project>  {

    @Override
    public void apply(Project project) {
        super.apply(project);
        TestExtension anyTest = project.getExtensions().create("anyTest", TestExtension.class);
          project.afterEvaluate(new Action<Project>() {
            @Override
            public void execute(Project project) {
                System.out.println("    afterEvaluate :anyTest:"+anyTest.topic);
            }
        });
    }
}


然后同步就可以看到输出:

!请添加图片描述

按照大家的说法,到这一步我们实现了一个简单的扩展。

3.问题来了——如何通过自定义Extension给Plugin传递数据

到上一节,我们实现了一个扩展,简单说明如何定义注册使用扩展,但,这只是一个简陋的扩展,甚至不能称之为扩展,我称之为扩展都感觉十分脸红惭愧甚至觉得丢人。

回想看过的十数篇帖子,不由得内心怒骂好几次:

这TM是扩展?!!这TM是扩展?!!这TM是扩展?!!

你们这些灌水的人给我翻译翻译,什么TM的叫TM的扩展?!!

为什么这个东西不能叫扩展?

我们回到开头的“什么是Extensions”,扩展的核心诉求是在gradle构建脚本(比如build.gradle)中增加我们自己的配置应用到我们的自定义gradle plugin中。而在以上篇章我们的扩展在哪里应用了,可以看到一行代码:

   estExtension anyTest = project.getExtensions().create("anyTest", TestExtension.class);

   project.afterEvaluate(new Action<Project>() {
            @Override
            public void execute(Project project) {
                System.out.println("    afterEvaluate :anyTest:"+anyTest.topic);
            }
        });
        //外部直接打印
      System.out.println("    afterEvaluate :anyTest:"+anyTest.topic);


我们注意project.afterEvaluate这个方法,在我的上一篇Gradle系列(2)——如何自定以Gradle 插件 中我简单讲了gradle的生命周期以及监听,afterEvaluate表示,gradle 的configuration阶段已经完成了。而上述代码表示,在项目配置完成后,输出一下我们扩展配置的值

  • 实际问题

由于我们做的是平台化项目,androidharmony双平台打包的,两个平台应用的三方库,签名机制也不一样,所以我需要知道编译的是哪个平台,是否需要支持双平台,所以我添加了一个扩展来配置这个信息,然而我在上述afterEvaluate生命周期去做签名的时候,发现报错(当时忘了截图,大概意思是说buildType已经创建好了,此时修改太晚了)

我们尝试在外部直接打印,你会发现,根本没有值!

那么问题来了——我们这里实现的扩展还有什么用呢?

答案是,没卵用!

你去搜索相关的帖子,千篇一律,都是这样,甚至你看官网,他们的demo也是这样!我请问一下,这样一个不能给插件传送数据,只能看没有实际用处的花架子,它叫扩展吗?

4.BaseAppModuleExtension和AppPlugin部分原理

那么到底在构建脚本怎么通过我们的扩展给插件传递数据呢?我想,我们可以看Android的AppExtension和AppPlugin是如何实现的呀。

注意:

  • com.android.application,com.android.library 实现类分别为com.android.build.gradle.internal.plugins.AppPlugincom.android.build.gradle.internal.plugins.LibraryPlugin

  • build.gradle中声明的“android”扩展的实例根据module是应用的插件不同,其实例可能是com.android.build.gradle.internal.dsl.BaseAppModuleExtensioncom.android.build.gradle.LibraryExtension

BuildTypes是如何创建并传递数据给AppPlugin的?

我们以build.gradle.kts中buildTypes为例:


plugins {
    id("com.android.application")
    id("gradle-rocket")
}
android {
	//。。。

        create("test") {
            isMinifyEnabled = false
            isDebuggable = true
            signingConfigs { }
        }

	//。。。
}

其实build.gradle的dsl写法我们可以理解为一种极致的lambda,buildTypes完整写法应该是


    buildTypes {

        create("test", object : Action<ApplicationBuildType> {

            override fun execute(t: ApplicationBuildType) {
                t.isMinifyEnabled = false
                t.isDebuggable = true
            }
        })
    }

我们点进去这个create方法,
在这里插入图片描述

可以看到,这是一个抽象类,点击左侧图标查看源码:

在这里插入图片描述

看得出来这个类应用还是比较广泛的,一时难以确定实现类是哪个。我们转变思路看AppPlugin:

AppPlugin是如何接收数据的?

查看AppPlugin源码


public class AppPlugin
        extends AbstractAppPlugin<
                com.android.build.api.dsl.ApplicationExtension,
                ApplicationAndroidComponentsExtension,
                ApplicationVariantBuilderImpl,
                ApplicationVariantImpl> {
    @Inject
    public AppPlugin(
            ToolingModelBuilderRegistry registry,
            SoftwareComponentFactory componentFactory,
            BuildEventsListenerRegistry listenerRegistry) {
        super(registry, componentFactory, listenerRegistry);
    }

    @NonNull
    @Override
    protected BaseExtension createExtension(
            @NonNull DslServices dslServices,
            @NonNull GlobalScope globalScope,
            @NonNull
                    DslContainerProvider<DefaultConfig, BuildType, ProductFlavor, SigningConfig>
                            dslContainers,
            @NonNull NamedDomainObjectContainer<BaseVariantOutput> buildOutputs,
            @NonNull ExtraModelInfo extraModelInfo) {
        ApplicationExtensionImpl applicationExtension =
                dslServices.newDecoratedInstance(ApplicationExtensionImpl.class, dslServices, 

          //..忽略一万行代码

          //创建“android”,注入到所有Extensions中
        return project.getExtensions()
                .create(
                        "android",
                        BaseAppModuleExtension.class,
                        dslServices,
                        globalScope,
                        buildOutputs,
                        dslContainers.getSourceSetManager(),
                        extraModelInfo,
                        applicationExtension);
    }

}

AppPluginLibraryPlugin代码都相当简单,主要区别在各自的泛型以及createExtensionandroid的实现类不同。逻辑都在其父类com.android.build.gradle.internal.plugins.BasePlugin,这个类也实现了Plugin接口,我们主要看apply方法


    @Override
    public final void apply(@NonNull Project project) {
        CrashReporting.runAction(
                () -> {
                    basePluginApply(project);
                    pluginSpecificApply(project);
                    project.getPluginManager().apply(AndroidBasePlugin.class);
                });
    }


接着进入basePluginApply


    private void basePluginApply(@NonNull Project project) {
        // We run by default in headless mode, so the JVM doesn't steal focus.
        System.setProperty("java.awt.headless", "true");

        this.project = project;

        //...
        
        configuratorService.recordBlock(
                ExecutionType.BASE_PLUGIN_PROJECT_CONFIGURE,
                project.getPath(),
                null,
                this::configureProject);

        configuratorService.recordBlock(
                ExecutionType.BASE_PLUGIN_PROJECT_BASE_EXTENSION_CREATION,
                project.getPath(),
                null,
                this::configureExtension);

        configuratorService.recordBlock(
                ExecutionType.BASE_PLUGIN_PROJECT_TASKS_CREATION,
                project.getPath(),
                null,
                this::createTasks);
    }


这3方法都比较重要,但我们要看configureExtension


    private void configureExtension() {
        DslServices dslServices = globalScope.getDslServices();

        final NamedDomainObjectContainer<BaseVariantOutput> buildOutputs =
                project.container(BaseVariantOutput.class);

        project.getExtensions().add("buildOutputs", buildOutputs);

        //1.创建BuildType 工厂类
        variantFactory = createVariantFactory(projectServices, globalScope);

        variantInputModel =
                new LegacyVariantInputManager(
                        dslServices,
                        variantFactory.getVariantType(),
                        new SourceSetManager(
                                project,
                                isPackagePublished(),
                                dslServices,
                                new DelayedActionsExecutor()));
         //2.子类中重载的方法                       	
        extension =
                createExtension(
                        dslServices, globalScope, variantInputModel, buildOutputs, extraModelInfo);
        //3.把扩展添加到全局作用域       
        globalScope.setExtension(extension);

        androidComponentsExtension = createComponentExtension(dslServices, variantApiOperations);

        variantManager =
                new VariantManager(
                        globalScope,
                        project,
                        projectServices.getProjectOptions(),
                        extension,
                        variantApiOperations,
                        variantFactory,
                        variantInputModel,
                        projectServices);

        registerModels(
                registry,
                globalScope,
                variantInputModel,
                extension,
                extraModelInfo);

        // create default Objects, signingConfig first as its used by the BuildTypes.
        //创建默认的buildType和签名
        variantFactory.createDefaultComponents(variantInputModel);

        createAndroidTestUtilConfiguration();
    }


这段代码我们需要了解的有三处:

  • createVariantFactory创建了我们的buildTypes工厂
  • 调用熟悉的createExtension创建我们的扩展实例,就是在上面提到子类中重载的方法。
  • 把扩展实例添加到全局作用域
  • 创建默认的buildType和签名

那么我们接下来createVariantFactory是怎么创建的,继而看我们的BuildType到底怎么创建的。

    protected abstract VariantFactory<VariantBuilderT, VariantT> createVariantFactory(
            @NonNull ProjectServices projectServices, @NonNull GlobalScope globalScope);

这是个抽象方法,我们看实现类

在这里插入图片描述

能看到AppPlugin,这个类是BaseAppModuleExtension的父类


    @NonNull
    @Override
    protected ApplicationVariantFactory createVariantFactory(
            @NonNull ProjectServices projectServices, @NonNull GlobalScope globalScope) {
        return new ApplicationVariantFactory(projectServices, globalScope);
    }

最终到了ApplicationVariantFactory


class ApplicationVariantFactory(
    projectServices: ProjectServices,
    globalScope: GlobalScope
) : AbstractAppVariantFactory<ApplicationVariantBuilderImpl, ApplicationVariantImpl>(
    projectServices,
    globalScope
) {
	//。。。
}

这个类的父类是AbstractAppVariantFactory,我们先记住这个类,返回到configureExtension,查看variantFactory.createDefaultComponents(variantInputModel);

    fun createDefaultComponents(
            dslContainers: DslContainerProvider<DefaultConfig, BuildType, ProductFlavor, SigningConfig>)

这是VariantFactory接口的抽象方法,接着看实现类AbstractAppVariantFactory

    override fun createDefaultComponents(
            dslContainers: DslContainerProvider<DefaultConfig, BuildType, ProductFlavor, SigningConfig>) {
        // must create signing config first so that build type 'debug' can be initialized
        // with the debug signing config.
        //创建默认的debug签名
        dslContainers.signingConfigContainer.create(BuilderConstants.DEBUG)
        //创建默认的debug和release buildType
        dslContainers.buildTypeContainer.create(BuilderConstants.DEBUG)
        dslContainers.buildTypeContainer.create(BuilderConstants.RELEASE)
    }


这个方法里做了两件事:

  • 创建默认的debug签名
  • 创建默认的debug和releae buildType

这就解释了为什么我们项目为什么不配置签名也能安装,以及两个默认的buidType从何而来。(这段代码救了我的命,在做平台化Flavor和签名的时候要配置我们的签名密钥,创建SigningConfig遇到问题,就是看这段代码找到了解决方法)

好,我们接着往下看dslContainers.buildTypeContainer.create(BuilderConstants.DEBUG)

在这里插入图片描述

是不是回到了远点,又是NamedDomainObjectContainer

buildTypeContainer

那么我们的buildTypeContainer从何而来呢?

我们要看dslContainers;

createDefaultComponents(),从方法形参可以看到它的类型是DslContainerProvider

往回退到configureExtension(),可以看到dslContainers就是variantInputModel;在configureExtension开始的地方创建的:


        variantInputModel =
                new LegacyVariantInputManager(
                        dslServices,
                        variantFactory.getVariantType(),
                        new SourceSetManager(
                                project,
                                isPackagePublished(),
                                dslServices,
                                new DelayedActionsExecutor()));



我们再看这个LegacyVariantInputManager的代码:


class LegacyVariantInputManager(
    dslServices: DslServices,
    variantType: VariantType,
    sourceSetManager: SourceSetManager
) : AbstractVariantInputManager<DefaultConfig, BuildType, ProductFlavor, SigningConfig>(
    dslServices,
    variantType,
    sourceSetManager
) {

    override val buildTypeContainer: NamedDomainObjectContainer<BuildType> =
        dslServices.domainObjectContainer(
            BuildType::class.java, BuildTypeFactory(dslServices)
        )
    override val productFlavorContainer: NamedDomainObjectContainer<ProductFlavor> =
        dslServices.domainObjectContainer(
            ProductFlavor::class.java,
            ProductFlavorFactory(dslServices)
        )
    override val signingConfigContainer: NamedDomainObjectContainer<SigningConfig> =
        dslServices.domainObjectContainer(
            SigningConfig::class.java,
            SigningConfigFactory(
                dslServices,
                getBuildService(
                    dslServices.buildServiceRegistry,
                    AndroidLocationsBuildService::class.java
                ).get().getDefaultDebugKeystoreLocation()
            )
        )

    override val defaultConfig: DefaultConfig = dslServices.newInstance(
        DefaultConfig::class.java,
        BuilderConstants.MAIN,
        dslServices
    )
}

这里我特意多粘贴了点代码,是不是看着很熟悉,有productFlavorsigningConfigContainer, defaultConfig

我们接着看buildTypeContainer = dslServices.domainObjectContainer,它是接口DslServices的方法,唯一实现类DslServicesImpl


class DslServicesImpl constructor(
    projectServices: ProjectServices,
    override val sdkComponents: Provider<SdkComponentsBuildService>
) : BaseServicesImpl(projectServices), DslServices {



    override fun <T> domainObjectContainer(
        type: Class<T>,
        factory: NamedDomainObjectFactory<T>
    ): NamedDomainObjectContainer<T> =
        projectServices.objectFactory.domainObjectContainer(type, factory)

}

继续点进去domainObjectContainer,他是接口ObjectFactory的方法,它的有效实现类是DefaultObjectFactory,查看它的方法:


    @Override
    public <T> NamedDomainObjectContainer<T> domainObjectContainer(Class<T> elementType, NamedDomainObjectFactory<T> factory) {
        return domainObjectCollectionFactory.newNamedDomainObjectContainer(elementType, factory);
    }

继续点进去仍然是个接口DomainObjectCollectionFactory:

public interface DomainObjectCollectionFactory {
    <T> NamedDomainObjectContainer<T> newNamedDomainObjectContainer(Class<T> elementType, NamedDomainObjectFactory<T> factory);
}

接着看它唯一实现类DefaultDomainObjectCollectionFactory:

是不是很绕啊,确实这么绕,山高水远,道阻且长,说实话

BaePlugin


public class DefaultDomainObjectCollectionFactory implements DomainObjectCollectionFactory {

    @Override
    public <T> NamedDomainObjectContainer<T> newNamedDomainObjectContainer(Class<T> elementType, NamedDomainObjectFactory<T> factory) {
        Instantiator instantiator = instantiatorFactory.decorateLenient();
        return Cast.uncheckedCast(instantiator.newInstance(FactoryNamedDomainObjectContainer.class, elementType, instantiator, new DynamicPropertyNamer(), factory, mutationGuard, collectionCallbackActionDecorator));
    }


}

看到这里就没有必要继续往下看了,其实已经能看出来了,这里其实就是反射创建了FactoryNamedDomainObjectContainer的实例,那我们接着看它


public class FactoryNamedDomainObjectContainer<T> extends AbstractNamedDomainObjectContainer<T> {
    
    public FactoryNamedDomainObjectContainer(Class<T> type, Instantiator instantiator, Namer<? super T> namer, NamedDomainObjectFactory<T> factory, MutationGuard crossProjectConfiguratorMutationGuard, CollectionCallbackActionDecorator collectionCallbackActionDecorator) {
        super(type, instantiator, namer, collectionCallbackActionDecorator);
        this.factory = factory;
        this.crossProjectConfiguratorMutationGuard = crossProjectConfiguratorMutationGuard;
    }

    @Override
    protected T doCreate(String name) {
        return factory.create(name);
    }
}

最终,我们找到了dslContainers.buildTypeContainer的实现类NamedDomainObjectContainer

(这里我特意贴了构造函数和一个方法,先记住,然后往后看)

它并没有实现create方法,我们接着看它的父类


public abstract class AbstractNamedDomainObjectContainer<T> extends DefaultNamedDomainObjectSet<T> implements NamedDomainObjectContainer<T>, HasPublicType {
   
    @Override
    public T create(String name) {
        assertMutable("create(String)");
        return create(name, Actions.doNothing());
    }

        @Override
    public T create(String name, Closure configureClosure) {
        assertMutable("create(String, Closure)");
        return create(name, ConfigureUtil.configureUsing(configureClosure));
    }

    @Override
    public T create(String name, Action<? super T> configureAction) throws InvalidUserDataException {
        assertMutable("create(String, Action)");
        assertCanAdd(name);
        //创建BuildType实例
        T object = doCreate(name);
        //添加到集合中
        add(object);
        //传递给我们的回调,让我们自己配置
        configureAction.execute(object);
        return object;
    }

}

可以看到实现了NamedDomainObjectContainer的3个create方法,最主要的是第三个方法,我们再次回顾一下build.gradle里面


    buildTypes {

        create("test", object : Action<ApplicationBuildType> {

            override fun execute(t: ApplicationBuildType) {
                t.isMinifyEnabled = false
                t.isDebuggable = true
            }
        })
    }

对比一下上面的方法,是不是觉得柳暗花明了😎😎😎

我们知道,create创建的就是BuildType实例(它实现了ApplicationBuildType),这里主要做了3件事:

  • 创建BuildType实例
  • 添加到缓存集合中
  • 传递给我们的回调,由我们自己去配置

看到希望了,我们接着往下看,我们的BuildType是怎么创建出来的,doCreate是个抽象方法,FactoryNamedDomainObjectContainer:


    @Override
    protected T doCreate(String name) {
        return factory.create(name);
    }

看到这个方法,我震惊了🙃🙃🙃我费尽心思追了这么久想看factory是什么终于找到了FactoryNamedDomainObjectContainer,你告诉我创建BuildType的还不是它?🤦‍♂️可是我能有什么办法啊,为了维护世界和平,为了沉没成本,只能继续看啊!

那我们看factory是哪里来的,记得我说前面特意贴的构造函数吗,竟然是构造函数传进来的,那我就返回往前看,发现我们来时的路上每一个方法的参数都是它的身影,直到LegacyVariantInputManager

    override val buildTypeContainer: NamedDomainObjectContainer<BuildType> =
        dslServices.domainObjectContainer(
            BuildType::class.java, BuildTypeFactory(dslServices)
        )

看它的第二个参数点进去:


public class BuildTypeFactory implements NamedDomainObjectFactory<BuildType> {

    @NonNull private DslServices dslServices;

    public BuildTypeFactory(@NonNull DslServices dslServices) {
        this.dslServices = dslServices;
    }

    @NonNull
    @Override
    public BuildType create(@NonNull String name) {
        return dslServices.newInstance(BuildType.class, name, dslServices);
    }
}


诺,就是这里了,后面我实在不想浪费时间继续贴了,相信大家已经看腻了,总结六个字——反射创建实例


流程总结

ok,到这一步,我们就明白了:

  • BuildType是由FactoryNamedDomainObjectContainer创建的;
  • 实例是由BuildTypeFactory反射创建的;
  • BuildType实例创建后添加到了FactoryNamedDomainObjectContainer,然后又给到我们的回调由我们自己配置

AppPlugin创建默认BuildType和我们自己在build.gradle 添加方式是一样的。

5. 回归初心——扩展是如何传递数据给插件的呢?

我们回溯上篇章的内容,找到各个类的从属关系:AppExtension持有ApplicationVariantFactory,后者在前者实例化时通过构造函数注入,它又持有DslServiceImpl… :

  • AppExtension -> ApplicationVariantFactory ->DslServiceImpl->FactoryNamedDomainObjectContainer->BuildType,
  • 而 ApplicationVariantFactory 和 DslServiceImpl 是BasePlugin的成员变量

简单的结构图:

在这里插入图片描述

总结

所以我们可以直观的理解为,ApplicationVariantFactory 就是注入A品牌Extension的一个callback,build.gralde里面看似调用AppExtension的函数,实则调用AppPlugin的成员。

经过千难万险,坎坷曲折,一路不停的追踪代码,最终我们得出这样一个很简单额结论,是不是很开心呢😂

6 应用

好,既然我们已经明白了这个原理,那么我们就可以在我们插件中应用。

改造我们的扩展:


public class RocketExtensions {

    //多平台支持。如若支持,会默认配置多个flavor
    private RocketConfigs mExtensionContainer;


    public RocketExtensions(BoosterConfigs container) {
        mExtensionContainer = container;
    }

    public void setMultiFlavor(boolean multi) {
        mExtensionContainer.setMultiFlavor(multi);
    }
}


新增一个配置类RocketConfigs:


public class RocketConfigs {

    public boolean isMultiFlavor;

    public void setMultiFlavor(boolean multi) {
        System.out.println("setMultiFlavor:" + multi);
        this.isMultiFlavor = multi;
        //doSth
    }
}

插件类:


public class BoosterPlugin implements Plugin {

    @Override
    public void apply(Project project) {
        super.apply(project);

        //初始化配置类
        RocketConfigs container = new BoosterConfigs();
        //注入扩展
        project.getExtensions().create("rocket", RocketExtensions.class, container);
    }
}

然后发布,在应用的build.gradle里使用:


plugins {
    id("com.android.application")
    id("gradle-rocket")
}


rocket {
    setMultiFlavor(true)
}
android{
	//...
}

同步一下就可以看到build输出

在这里插入图片描述


为了看明白这块儿代码真的费尽心思,弯弯绕绕,脑袋都晕了,不过最终搞懂这些东西还是非常开心的。

好了,本篇到此结束

Gradle | Extension扩展详解 我们先来看一段Android应用的Gradleandroid {release {相信做Android应用开发的同学,对这段代码都快看吐了吧。记得当初刚从eclipse转到的时候,看这些配置就像看天书一样,只知道按规定配置就可以了。但是为什么要这样配置?除此外还支持哪些配置?为什么一定要在android这个命名空间下配置呢?可以不可以定义自己的特殊配置呢?上面这个android打包配置,就是GradleExtension,翻译成中文意思就叫扩展。它的作用就是通过实现自定义Extension 阅读详情

相关推荐

Gradle ExtenionContainer 创建和使用扩展参数(extensions)详解

Gradle ExtenionContainer 创建和使用扩展参数(extensions)详解 我们在开发 Gradle 插件时,大多数插件都需要从构建脚本中获取一些配置,这样就可以根据项目的不同,对 Gradle 插件传递不同的配置,而不需要修改插件内的代码。我们可以使用 ExtensionContainer 来实现 Gradle扩展(参数传递能力)。 ExtenionContainer 每个 Gradle 的 Project 都维护了一个 ExtenionContainer,我们可以通过 pro

卜大爷的博客 3721

【Android Gradle 插件】Gradle 自定义 Plugin 插件 ③ ( 自定义插件作用 | Android Gradle 插件的扩展 | 自定义 Extension 扩展 )

一、自定义插件作用、 二、Android Gradle 插件的 AppExtension 扩展、 三、自定义 Extension 扩展

让 学习 成为一种 习惯 ( 韩曙亮 の 技术博客 ) 1689

Android Gradle自定义Extension

就是 GradleExtension,翻译成中文意思就叫扩展。它的作用就是通过实现自定义Extension,可以在 Gradle 脚本中增加类似 android 这样命名空间的配置,Gradle 可以识别这种配置,并读取里面的配置内容。

star_nwe的博客 730

Android Gradle学习() Extension详解

前面我们已经详细讲解了 Gradle 的 Task、Project 等基本用法,现在我们还要学习一个很重要的概念 Extension,它在 Gradle 中几乎随处可见,特别是在 Android 打包配置中。 1. 什么是Extension 我们先来看一段 Android 应用的 Gradle 配置代码: android { compileSdkVersion 26 default...

假装你是大灰狼的专栏 3168

android gradle配置_【Android 修炼手册】Android Gradle Plugin 插件主要流程

预备知识理解 gradle 的基本开发了解 gradle task 和 plugin 使用及开发了解 android gradle plugin 的使用看完本文可以达到什么程度了解 android gradle plugin 的构建流程了解 android gradle plugin 的主要 task 的实现学会 hook android 构建流程,添加自己想要的功能阅读前准备工作1.项目添加 a...

weixin_31931045的博客 664

【Android Gradle 插件】Module 目录下 build.gradle 配置文件 ( android 闭包块配置 | AppExtension 扩展类型参考文档 )

该 android 方法定义在 AppExtension 扩展类型中 , 下面简单介绍该扩展类型;android 方法中的配置参考。

浪漫之圣 534

找不到 org.gradle:gradle-tooling-api:jar:7.1.1

gradle-tooling-api:jar:7.1.1 找不到

gs80140的专栏 2058

Gradle插件-extensions

简单实例,在工程的build.gradle文件中添加如下代码 class CustomParamsExtensions{ def happyDes = 'very happy' def happyLevel = 3 } class CustomParamsNestExtensions{ def dataParams = 'NestParam' } project.

zlcjssds的博客 2794

Gradle系列()-扩展属性

另外我们还可以在gradle.properties下直接定义全局属性.如上所示,我们定义test属性.这里定义的属性我们是可以直接调用的根目录的build.gradle中调用println "根目录build.gradle:" + testandroid {...

赵航的博客 5980

Gradle插件探究

Gradle插件基础知识

mayday_sanshui的博客 2573

【Android Gradle 插件】Extension 扩展类型 ( Module 引入插件类型 | application 插件 | library 插件 | Variants 变体列表 )

一、Module 引入插件类型、 1、com.android.application 插件、 2、com.android.library 插件、 二、Extension 扩展类型、 三、applicationVariants 变体与 libraryVariants 变体、

让 学习 成为一种 习惯 ( 韩曙亮 の 技术博客 ) 2991

gradle自定义插件

学习资料 Writing Custom Plugins 总体来说思路和自定义任务很类似,也是三种方式 概述 创建一个Gradle插件,需要编写一个实现Plugin接口的类。当插件被应用到一个项目时,Gradle创建了一个插件类的实例,并调用了实例的plugin.apply(T)方法。项目对象作为一个参数传递,插件可以使用它来配置项目,但是它需要这样做。 直接写在构建文件中 简单插...

约会远行的专栏 5442

Google Cloud Platform App Gradle Plugin 使用教程

Google Cloud Platform App Gradle Plugin 使用教程 项目介绍 Google Cloud Platform App Gradle Plugin 是一个用于构建和部署 Google App Engine 应用的 Gradle 插件。该插件提供了多种任务,帮助开发者简化应用的构建和部署流程。自 2024 年 2 月起,该库已迁移至 appengine-plugins...

gitblog_00368的博客 937

AGP7.0|kts 搞一个加固插件

每次都要手动使用工具去手动加固,非常麻烦,所以自己搞一个加固插件来提高生产力 开发环境使用的AGP7.0.2 ,相比较之前的版本,改动还是蛮大的,自己也踩了不少坑。 更多AGP7.0的内容可以关注一下虾哥的文章 掘金:https://juejin.cn/post/7056395437544046606 我们分为以下几步去完成: 获取apk产物 获取签名 获取加固工具 进行加固 获取APK AGP7获取apk 的方式跟以前也大不相同了 ,我们需要借助Variant API apk 来进行获取 Var

WangYilei0318的博客 1927

gradle 自定义Extension

创建和使用android自定义plugin中的extension

simple_a的博客 683

暴力突破 Gradle 自动化项目构建(七)- 其他模块及自定义 Gradle 插件

Setting SourceSet

lerendan的博客 823

Android Gradle揭秘

Gradle是一款非常优秀的自动化构建工具,Android Studio是基于Android Gradle插件实现项目构建的。作为一名Android开发者,我们不仅仅要知道应该怎么配置项目,还要知道为什么要这样配置,我们还能编写自己的构建脚本和插件。如果我们能掌握Gradle的相关知识,将会对项目架构有一个全新的认识,这对我们来说是非常重要的。

上一篇: Android插件化原理(三)——加载插件资源
下一篇: Android截屏录屏MediaProjection分享
cry kid
博客等级 码龄10年 144粉丝 24原创
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值