Gradle的构建过程都不会?带你全面了解Android如何自定义Gradle 插件

目前 Android 工程的默认构建工具为 Gradle,咱们在构建 APK 的时候每每会执行 ./gradlew assembleDebug 这样的命令。。java

那么这个命令到底表明着什么含义呢?命令的执行到底是在作什么事情呢?咱们能不能在命令执行的过程当中作一些本身的操做呢?接下来咱们来具体的进行分析。android

Gradle 的构建过程

Gradle Wrapper 是个啥

当咱们在 Android Studio 中新建一个工程时,你会发如今工程的根目录下会建立如下几个文件:git

在这里插入图片描述github

实际上这几个文件是经过执行 $ Gradle Wrapper 生成的。Gradle Wrapper,顾名思义就是对 Gradle 构建工具的一层封装。面试

在和其余同事共同管理某个 Android 工程的时候,确定会存在同事 A 电脑上的 Gradle 版本和同事 B 电脑上的 Gradle 版本不同,那么这个不同可能致使的问题是须要在 build.gradle 文件中添加不一样的配置,甚至有的 Gradle 版本都没法成功跑通工程。bootstrap

因此,Gradle 的工程师们将 Gradle 添加了一层简单的封装,Linux 用户能够经过执行 gradlew 来代替 gradle 命令,Windows 用户能够经过 gradlew.bat 来代替,实际上这俩文件就是个可执行脚本,咱们能够直接打开这个脚原本看里面到底有什么。api

# 只贴上主要代码 gradlew 文件
...
JAVACMD="java"
...
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
...
exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 

从里面的代码咱们能够看到,实际上 gradlew 的脚本也只是执行了一下 Java 命令,assembleDebug 只是执行脚本的参数。咱们修改一下脚本打印出来这个命令:app

java -Xdock:name=Gradle -Xdock:icon=/media/gradle.icns -Dorg.gradle.appname=gradlew -classpath /xxx/food/gradle/wrapper/gradle-wrapper.jar
 org.gradle.wrapper.GradleWrapperMain assembleDebug -s 

从这里能够看到,脚本所作的事情就是经过 Java 命令来执行 /gradle/wrapper/ 下的 gradle-wrapper.jar 包。经过 JD-GUI 工具打开这个可执行 jar 包,找到那个 jar 包的入口类,也就是 org.gradle.wrapper.GradleWrapperMain,咱们大体看一下这个 jar 包到底干了什么。dom

// org.gradle.wrapper.GradleWrapperMain文件
public static void main(String[] args) throws Exception {

  File wrapperJar = wrapperJar(); // 获取这个可执行jar包的具体路径
  File propertiesFile = wrapperProperties(wrapperJar); // 获取gradle-wrapper.properties的位置
  File rootDir = rootDir(wrapperJar); // 获取工程的根目录

  // 下面的一段代码用来解析命令行,咱们暂时不去管它
  CommandLineParser parser = new CommandLineParser(); 

  ... 

  WrapperExecutor wrapperExecutor = WrapperExecutor.forWrapperPropertiesFile(propertiesFile);
  // 下面这个方法即是解析gradle/wrapper/gradle-wrapper.properties文件里面的内容,而后根据里面的配置到相应的地址需下载另外一个可执行jar包
  wrapperExecutor.execute(
    args,
    new Install(logger, new Download(logger, "gradlew", wrapperVersion()), new PathAssembler(gradleUserHome)),
    new BootstrapMainStarter());
} 

经过分析 execute() 方法的执行,咱们会发现,这个方法执行了 gradle-wrapper.properties 文件的解析和下载工做,咱们先看一下这个文件里面有什么:jvm

// gradle/wrapper/gradle-wrapper.properties 文件配置
distributionBase=GRADLE_USER_HOME // GRADLE_USER_HOME的地址默认在用户目录下的.gradle/文件夹里
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https://services.gradle.org/distributions/gradle-4.4-all.zip 

如上所示,代码会找到 distributionUrl 这个路径,而后下载相应的文件。在这里,工程会指定固定的一个 Gradle 版本,而后全部的开发者都会在相同的路径下下载到相同的 ZIP 包,这样也就保证了在不一样电脑上执行构建操做结果的一致性。下载文件的过程就很少述了,由于比较简单。

文件下载之后,当前就会去执行这个文件:

// org.gradle.wrapper.BootstrapMainStarter
public class BootstrapMainStarter {
    public void start(String[] args, File gradleHome) throws Exception {
        File gradleJar = findLauncherJar(gradleHome);
        URLClassLoader contextClassLoader = new URLClassLoader(new URL[]{gradleJar.toURI().toURL()}, ClassLoader.getSystemClassLoader().getParent());
        Thread.currentThread().setContextClassLoader(contextClassLoader);
       // 经过反射找到org.gradle.launcher.GradleMain 进行具体的调用
        Class<?> mainClass = contextClassLoader.loadClass("org.gradle.launcher.GradleMain");
        Method mainMethod = mainClass.getMethod("main", String[].class);
        mainMethod.invoke(null, new Object[]{args});
        if (contextClassLoader instanceof Closeable) {
            ((Closeable) contextClassLoader).close();
        }
    }
} 

如上所示,Java 代码找到下载的 jar 包,而后经过 ClassLoader 加载到内存里,加载之后经过反射调用里面的入口类。

到此,Gradle Wrapper 的整个调用过程结束了,它的功能就是保证多个电脑上可以以相同的 Gradle 版本构建 Android 的工程代码,后续的执行则是开启了 Gradle 的真正构建过程,咱们接下来进行分析。

Gradle 的构建生命周期

Gradle 的整个构建过程共分为三个阶段:init 初始化阶段、config 配置阶段和 build 执行阶段。下面简单说一下这三个阶段分别作什么工做。

init 初始化阶段

初始化阶段主要是解析 settings.gradle 文件,查看该工程引入了多少个 module。以下所示,能够在 settings.gradle 文件下定义须要引入的 module 和其对应的目录:

include ':app'

include ':library'
project(':library').projectDir = new File('../library') 
config 阶段

在 config 阶段即是去解析每一个 module 里的 build.gradle 文件,并逐行执行,完成对 project 的配置,并构造 Task 任务依赖关系图以便在执行阶段按照依赖关系执行 Task。

build 执行阶段

执行阶段即是根据 config 阶段生成的 Task 依赖关系图,来挨个地去执行各个 Task。每一个 Task 能够看作是一个功能体,好比说,在构建过程当中 Java 文件须要先转换为 class 文件,而后 class 文件要再次转换成 dex 文件,而后 dex 文件最终组合生成 APK,这个过程当中每一步都是由一个 Task 来执行的。后续在介绍自定义 Gradle 插件的时候会讲到 Task 相关的东西。

Gradle 构建过程代码分析

刚才梳理了一下 Gradle 构建过程的生命周期,分为上面那三个阶段,那么,具体到代码是如何实现这三个声明周期的呢?咱们具体进行一下分析。

在 Gradle Wrapper 的末尾,咱们提到构建过程走到了经过反射找到 org.gradle.launcher.GradleMain 进行具体的调用。那么咱们就继续跟着源码走。

// org.gradle.launcher.GradleMain
public class GradleMain {
    public static void main(String[] args) throws Exception {
        new ProcessBootstrap().run("org.gradle.launcher.Main", args);
    }
} 

org.gradle.launcher.GradleMain 是真正执行构建过程的入口类,深刻到 new ProcessBootstrap().run() 方法中继续执行。

private void runNoExit(String mainClassName, String[] args) throws Exception {
  ClassPathRegistry classPathRegistry = new DefaultClassPathRegistry(new DefaultClassPathProvider(new DefaultModuleRegistry(CurrentGradleInstallation.get())));
  ClassLoaderFactory classLoaderFactory = new DefaultClassLoaderFactory();
  ClassPath antClasspath = classPathRegistry.getClassPath("ANT");
  ClassPath runtimeClasspath = classPathRegistry.getClassPath("GRADLE_RUNTIME");
  ClassLoader antClassLoader = classLoaderFactory.createIsolatedClassLoader(antClasspath);
  // 咱们发现经过新建classLoader,在classLoader增长了新的依赖项,但这些依赖项不知道是什么。不过这不是咱们关注的重点,咱们继续代码的执行
  ClassLoader runtimeClassLoader = new VisitableURLClassLoader(antClassLoader, runtimeClasspath);
  ClassLoader oldClassLoader = Thread.currentThread().getContextClassLoader();
  Thread.currentThread().setContextClassLoader(runtimeClassLoader);

  try {
    // 在此处经过反射调用了org.gradle.launcher.Main这个类的run方法,
    Class<?> mainClass = runtimeClassLoader.loadClass(mainClassName);
    Object entryPoint = mainClass.newInstance();
    Method mainMethod = mainClass.getMethod("run", String[].class);
    mainMethod.invoke(entryPoint, new Object[]{args});
  } finally {
    ...
  }
} 

主流程是经过反射调用了 org.gradle.launcher.Main 这个类的 run 方法,咱们具体看一下这段代码。

// org.gradle.launcher.Main
public class Main extends EntryPoint {
    public static void main(String[] args) {
        new Main().run(args);
    }
    protected void doAction(String[] args, ExecutionListener listener) {
        UnsupportedJavaRuntimeException.assertUsingVersion("Gradle", JavaVersion.VERSION_1_7);
        createActionFactory().convert(Arrays.asList(args)).execute(listener);
    }
    CommandLineActionFactory createActionFactory() {
        return new CommandLineActionFactory();
    }
} 

org.gradle.launcher.Main 这个类实际上继承了 org.gradle.launcher.bootstrap.EntryPoint 这个类,而它的 run 方法实际也就是提供了对 Main 中 doAction 方法的回调。

// org.gradle.launcher.cli.CommandLineActionFactory
public Action<ExecutionListener> convert(List<String> args) {
  ServiceRegistry loggingServices = createLoggingServices();

  LoggingConfiguration loggingConfiguration = new DefaultLoggingConfiguration();

  return new WithLogging(loggingServices,
              buildLayoutFactory,
              args,
              loggingConfiguration,
              new ExceptionReportingAction(
              new ParseAndBuildAction(loggingServices, args),
              new BuildExceptionReporter(loggingServices.get(StyledTextOutputFactory.class), loggingConfiguration, clientMetaData())));
} 

CommandLineActionFactory.convert 返回 WithLogging 的实例,而后调用了 WithLogging 的 execute 方法。

而后通过各类回调等,最终调用的是 ParseAndBuildAction 的 execute 方法(中间的回调过程略过,有兴趣的同窗能够本身查看一下,咱们只分析主流程的代码):

// org.gradle.launcher.cli.CommandLineActionFactory#ParseAndBuildAction
public void execute(ExecutionListener executionListener) {
  List<CommandLineAction> actions = new ArrayList<CommandLineAction>();
  // BuildInActions 是处理help version 这些命令的
  actions.add(new BuiltInActions());
  // 若是不是上面的两条命令行参数,则执行BuildActionsFactory里的参数。
  createActionFactories(loggingServices, actions);

  CommandLineParser parser = new CommandLineParser();
  for (CommandLineAction action : actions) {
    action.configureCommandLineParser(parser);
  }

  Action<? super ExecutionListener> action;
  try {
    ParsedCommandLine commandLine = parser.parse(args);
    action = createAction(actions, parser, commandLine);
  } catch (CommandLineArgumentException e) {
    action = new CommandLineParseFailureAction(parser, e);
  }

  action.execute(executionListener);
}

private Action<? super ExecutionListener> createAction(Iterable<CommandLineAction> factories, CommandLineParser parser, ParsedCommandLine commandLine) {
  for (CommandLineAction factory : factories) {
    // 根据命令行参数选中相关的处理的Action,好比说在gradle参数后面跟着 help 或者version 参数,则选中BuiltInActions 
    Runnable action = factory.createAction(parser, commandLine);
    if (action != null) {
      return Actions.toAction(action);
    }
  }
  throw new UnsupportedOperationException("No action factory for specified command-line arguments.");
} 

若是在 gradlew 参数后面加 help 或者 version 时,将交给 BuiltInActions 进行处理,其它的则会交给 BuildActionsFactory 类处理。咱们直接查看一下 BuildActionsFactory 的执行代码。

// org.gradle.launcher.cli.BuildActionsFactory
public Runnable createAction(CommandLineParser parser, ParsedCommandLine commandLine) {
  Parameters parameters = parametersConverter.convert(commandLine, new Parameters());
  parameters.getStartParameter().setInteractive(ConsoleStateUtil.isInteractive());

  parameters.getDaemonParameters().applyDefaultsFor(jvmVersionDetector.getJavaVersion(parameters.getDaemonParameters().getEffectiveJvm()));
  // 下面是经过各类不一样的参数
  if (parameters.getDaemonParameters().isStop()) { /
    return stopAllDaemons(parameters.getDaemonParameters(), loggingServices);
  }
  if (parameters.getDaemonParameters().isStatus()) {
    return showDaemonStatus(parameters.getDaemonParameters(), loggingServices);
  }
  if (parameters.getDaemonParameters().isForeground()) {
    DaemonParameters daemonParameters = parameters.getDaemonParameters();
    ForegroundDaemonConfiguration conf = new ForegroundDaemonConfiguration(
      UUID.randomUUID().toString(), daemonParameters.getBaseDir(), daemonParameters.getIdleTimeout(), daemonParameters.getPeriodicCheckInterval());
    return new ForegroundDaemonAction(loggingServices, conf);
  }
  if (parameters.getDaemonParameters().isEnabled()) {
    return runBuildWithDaemon(parameters.getStartParameter(), parameters.getDaemonParameters(), loggingServices);
  }
  if (canUseCurrentProcess(parameters.getDaemonParameters())) {
    return runBuildInProcess(parameters.getStartParameter(), parameters.getDaemonParameters(), loggingServices);
  }

  return runBuildInSingleUseDaemon(parameters.getStartParameter(), parameters.getDaemonParameters(), loggingServices);
} 

后三个方法中都会调用到 runBuildAndCloseServices,这也是执行 Gradle 构建的方法。

最终代码会执行到 RunBuildAction 的 run 方法。

// org.gradle.launcher.cli.RunBuildAction
public void run() {
  try {
    // 这个executer其实是 InProcessBuildActionExecuter 的实例
    executer.execute(
      new ExecuteBuildAction(startParameter),
      new DefaultBuildRequestContext(new DefaultBuildRequestMetaData(clientMetaData, startTime), new DefaultBuildCancellationToken(), new NoOpBuildEventConsumer()),
      buildActionParameters,
      sharedServices);
  } finally {
    if (stoppable != null) {
      stoppable.stop();
    }
  }
} 

最终查看 InProcessBuildActionExecuter 执行的代码。

public Object execute(BuildAction action, BuildRequestContext buildRequestContext, BuildActionParameters actionParameters, ServiceRegistry contextServices) {
  // 最终经过调用获取到了GradleLauncher的实例,他的一个实现类DefaultGradleLauncher
  GradleLauncher gradleLauncher = gradleLauncherFactory.newInstance(action.getStartParameter(), buildRequestContext, contextServices);
  try {
    RootBuildLifecycleListener buildLifecycleListener = contextServices.get(ListenerManager.class).getBroadcaster(RootBuildLifecycleListener.class);
    buildLifecycleListener.afterStart();
    try {
      GradleBuildController buildController = new GradleBuildController(gradleLauncher);
      buildActionRunner.run(action, buildController);
      return buildController.getResult();
    } finally {
      buildLifecycleListener.beforeComplete();
    }
  } finally {
    gradleLauncher.stop();
  }
} 

在 GradleLauncher 的实现类中,咱们看到了熟悉的东西:

private enum Stage {
  Load, Configure, Build
} 

而后代码便会调用到 DefaultGradleLauncher 的 run ()->doBuild () 方法

private BuildResult doBuild(final Stage upTo) {
  // TODO:pm Move this to RunAsBuildOperationBuildActionRunner when BuildOperationWorkerRegistry scope is changed
  final AtomicReference<BuildResult> buildResult = new AtomicReference<BuildResult>();
  WorkerLeaseService workerLeaseService = buildServices.get(WorkerLeaseService.class);
  workerLeaseService.withLocks(workerLeaseService.getWorkerLease()).execute(new Runnable() {
    @Override
    public void run() {
      Throwable failure = null;
      try {
        // 开始构建以前
        buildListener.buildStarted(gradle);
        // 开始构建
        doBuildStages(upTo);
      } catch (Throwable t) {
        failure = exceptionAnalyser.transform(t);
      }
      buildResult.set(new BuildResult(upTo.name(), gradle, failure));
      // 构建完成以后
      buildListener.buildFinished(buildResult.get());
      if (failure != null) {
        throw new ReportedException(failure);
      }
    }
  });
  return buildResult.get();
} 

而后咱们看一下开始构建时的代码:

private void doBuildStages(Stage upTo) {
   if (stage == Stage.Build) {
     throw new IllegalStateException("Cannot build with GradleLauncher multiple times");
   }
   if (stage == null) {
     // Evaluate init scripts
     initScriptHandler.executeScripts(gradle);
     // 初始化阶段,解析Settings.gradle文件夹
     settings = settingsLoader.findAndLoadSettings(gradle);
     stage = Stage.Load;
   }
   if (upTo == Stage.Load) {
     return;
   }
   if (stage == Stage.Load) {
     // 配置阶段 
     buildOperationExecutor.run(new ConfigureBuild());
     stage = Stage.Configure;
   }

   if (upTo == Stage.Configure) {
     return;
   }

   stage = Stage.Build;
   // 绘制task的依赖树
   buildOperationExecutor.run(new CalculateTaskGraph());
   // 执行task。
   buildOperationExecutor.run(new ExecuteTasks());
 } 

到最后一步,感受全部的努力都没有白费,终于看到了熟悉的 Gradle 构建的三个阶段。原来 Gradle 的构建也是用代码写出来的,并无想象的那么高深。

Gradle 插件

什么是 Gradle 插件

咱们上面讲解过,Gradle 的构建过程实际上就是各个 Task 的执行过程,那么这些执行的 Task 从哪里来呢?答案就是从 Gradle 插件里来。

咱们发现当咱们新建一个 Android 工程时,在 App 这个 module 的 build.gradle 文件的第一行里会有如下代码:

apply plugin: 'com.android.application' 

这句代码的做用即是将构建 Android 应用的全部须要 Task 都加载进来了。因此咱们看到,Gradle 生命周期的三个阶段仅仅是个壳子,若是想构建 Android 工程,那么就用 apply plugin: 'com.android.application' 引入全部的构建 Android 应用所须要的 Task;若是想要构建 Java 工程,那么只须要经过 apply plugin: 'java' 来引入 Java 工程所须要的 Task 即可。

那么知道了 Gradle 插件的强大功能,咱们将如何按照本身的须要自定义 Gradle 插件呢?咱们下面来进行讲解。

自定义 Gradle 插件

咱们在自定义 Gradle 插件的时候,须要解决如下问题:

  • 问题一:如何自定义一个 Gradle Plugin?

  • 问题二:Gradle Plugin 怎么调试?

  • 问题三:Gradle Plugin 的 apply 方法是何时触发的?

下面以实际的例子来介绍如何自定义 Gradle 插件,并对 Gradle 插件进行调试。在这个实际的例子中,Gradle 插件的定义和使用分别在两个不一样的工程中,这样定义出来的 plugin 可以供外部使用。

问题一:自定义一个插件

新建两个工程 CustomPlugin、GradleProject。前者是定义插件的地方,后者是使用插件的地方。咱们先定义插件。

下面是完成插件自定义之后的目录结构,咱们先来一个总览。

在这里插入图片描述

新建一个 module,删除里面的全部文件,而后新建成如上图所示的目录结构。其中 MyCustomPlugin 是定义的插件类,而 mycustomplugin.properties 是配置的插件属性。

首先在 build.gradle 文件中添加以下代码。

// 应用另外两个插件
apply plugin:"groovy"
apply plugin: "maven"

dependencies {
    // 使用gradle的api
    compile gradleApi()
    // 使用groovy的api
    compile localGroovy()
}

repositories {
    // 下载api相关文件的仓库
    mavenCentral()
} 

添加之后点击 Sync Project with Gradle 按钮,就是这个:

在这里插入图片描述

而后 Android Studio 就会识别出 groovy 文件夹,groovy 文件夹就变成了蓝色。

而后在 MyCustomPlugin.groovy 添加以下代码,在 apply 方法中具体执行咱们想要这个插件去作的事情。

class MyCustomPlugin implements Plugin<Project> {

    @Override
    void apply(Project project) {

        println("start mycustomplugin")

        println(project.name)
    }
} 

最后一步,在 mycustomplugin.properties 文件中添加以下代码,用来指明插件的处理类:

implementation-class=com.dianping.myplugin.MyCustomPlugin 

其中 mycustomplugin.properties 中的 mycustomplugin,表明着这个插件在使用时的名称,例如,使用时就是 apply plugin:'mycustomplugin’。使用方经过名称找到这个插件的配置文件,而后根据配置文件找到这个插件具体执行的类。

到此,自定义一个插件的基本工做就完成了,下面就讲一讲如何使用。

如何使用

打包

在 myplugin 这个 module 中的 build.gradle 文件中添加一些代码,添加后整个代码结构以下。

apply plugin:"groovy"
apply plugin: "maven"

dependencies {
    compile gradleApi()
    compile localGroovy()
}

repositories {
    mavenCentral()
}
// 此处为新添加的代码
// 定义组
group='com.dianping.myplugin'
//定义版本
version='1.0.0'

uploadArchives {
    repositories {
        mavenDeployer {
            // 定义插件打包后上传的位置,能够随意指定,可是在使用时须要指定一样的文件才能找到
            repository(url: uri('../../repo'))
        }
    }
} 

添加完成后再次点击:

在这里插入图片描述

而后会在 Gradle project 面板中出现 uploadArchives 的 Task。

在这里插入图片描述

双击它,就会在 …/…/repo 目录下出现相关文件。

使用

在 GradleProject 的根级别的 build.gradle 中 buildscript 节点上添加代码,添加完后以下所示:

buildscript {

    repositories {
        google()
        jcenter()
        // 添加的代码
        maven {
            url uri('../repo') // 指定路径,这个路径和上面的生成路径是一致的
        }
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:3.0.0'
        // 添加的代码。myplugin是上面定义的时候module的名称,com.dianping.myplugin是group。
        classpath 'com.dianping.myplugin:myplugin:1.0.0'

    }
} 

最后在 app 这个 module 中添加插件使用。

apply plugin: 'mycustomplugin' 

添加完后执行 ./gradlew :app:assembleDebug 就能看到打印结果:

start mycustomplugin
app 

至此,使用上也讲完了。下面该讲一讲如何调试了。

问题二:如何调试

在刚才的 CustomPlugin 工程下在菜单栏中选择 Run >> Edit Configurations。而后点击 remote,新建远程调试,其余东西都不用改,直接点击 OK 就行。

在这里插入图片描述

新建完成之后再 GradleProject 中运行以下命令:

./gradlew :app:assembleDebug -Dorg.gradle.debug=true 

而后在 CustomPlugin 须要断点的地方打上断点,点击下面红框里的按钮,启动调试。断点处就会终止执行。

在这里插入图片描述

至此,插件的开发也可以调试了。

问题三:apply 方法何时执行

Gradle 构建的过程总共分为三个阶段:初始化阶段、配置阶段、运行阶段。初始化阶段是执行 settings.gradle 文件中的内容,看看这个 Project 须要构建哪几个 module。在配置阶段是从根 Project 依次遍历 module,并为每一个 module 生成一个 Project 对象。配置阶段完成时就造成了一个完整的 Task 依赖图。而后就是执行阶段执行相关的 Task。

那么 apply 方法是何时执行的呢?是在配置阶段遇到 apply plugin:'mycustomplugin’ 就开始执行,咱们能够在先后打 log 来验证。结果和预期同样。apply 方法中传入的 Project 对象就是某个使用该插件的 Project 的对象。

println 'before'
apply plugin: 'mycustomplugin'
println 'after' 

非独立工程定义和使用插件

若是想要在本身的工程里面使用 Gradle 插件,那么更加简单。

新建一个 Project,叫作 PluginDemo, 在 app 的 build.gradle 中写上以下代码:

class ApkDistPlugin implements Plugin<Project> {

    @Override
    void apply(Project project) {
        project.task("apkdist") << {
            println 'hello world'
        }
    }
}
apply plugin: ApkDistPlugin
命令行输入:
./gradlew -q -p app/ apkdist

// 输出结果为:

hello world 

让插件是能够配置的

大多数插件都须要在 build script 中获取到必定的配置信息。其中一个方法就是经过 Extension 类来进行,Project 类中持有了 ExtensionContainer 对象,包含了对这个 Project 全部的配置。那么咱们就能够经过它来添加咱们本身的配置。下面是一个例子。

class ApkDistExtension {
    Closure nameMap = null
    String destDir = null
}
class GreetingPluginExtension {
    String message = null
}
class ApkDistPlugin implements Plugin<Project> {

    @Override
    void apply(Project project) {
        project.extensions.create("apkdistconf",ApkDistExtension)
        def extension = project.extensions.create("greet",GreetingPluginExtension)
        project.task("apkdist") << {
            def closure = project['apkdistconf'].nameMap
            closure('hello world closure')
            println 'hello world'
            println project['apkdistconf'].destDir
            println extension.message
        }
    }
}
apply plugin: ApkDistPlugin

apkdistconf {
    nameMap { name ->
        println "$name haha"
    }
    destDir 'heiheihei'

}
greet.message = "greet" 

下面是运行结果

// 执行的命令
./gradlew -q -p app/ apkdist

// 运行的结果

hello world closure haha
hello world
heiheihei
greet

如今都说互联网寒冬,其实只要自身技术能力够强,我们就不怕!我这边专门针对Android开发工程师整理了一套【Android进阶学习视频】、【全套Android面试秘籍】、【Android知识点PDF】。若有须要获取资料文档的朋友,能够点击我GitHub免费获取!

相关文章
相关标签/搜索