Android中Gradle详细实用指南

TonIfe 8年前
   <h2>Android中Gradle实用指南</h2>    <p>Gradle让Android中的依赖管理、库管理、渠道管理以及一些动态地编译配置变得极为方便!!</p>    <p>本文是对Gradle在Android项目中进阶使用的知识点整理和简要讲解</p>    <h2>目录</h2>    <ul>     <li>Android工程中的Gradle</li>     <li>常用的Gradle Task</li>     <li>动态参数配置</li>     <li>Project:build.gradle      <ul>       <li>全局属性配置</li>       <li>整体结构和描述</li>      </ul> </li>     <li>Module: build.gradle      <ul>       <li>defaucltConfig</li>       <li>signConfigs</li>       <li>buidlTypes</li>       <li>sourceSets</li>       <li>productFlavors</li>       <li>compileOptions</li>       <li>lintOptions</li>       <li>build.gradle图形化配置</li>      </ul> </li>     <li>dependencies项目依赖</li>     <li>自定义方法def</li>     <li>Gradle编译提速优化      <ul>       <li>性能检测</li>       <li>禁用Task达到提速</li>       <li>AAPT</li>       <li>Gradle编译优化</li>      </ul> </li>     <li>认识Task</li>     <li>自定义Plugin      <ul>       <li>build.gradle中直接定义</li>       <li>当前工程中定义</li>       <li>独立Module自定义插件</li>      </ul> </li>     <li>最后</li>    </ul>    <h2>Android工程中的Gradle</h2>    <p>下面简述对我们工程最重要的几个Gradle文件,后续也会围绕他们进行详细讲解和补充</p>    <p>(请仔细看代码中的注释哈)</p>    <ul>     <li>工程Project 中的 build.gradle : 工程控制Gradle编译配置</li>     <li>模块module中的 build.gradle : 控制每个Module的编译过程</li>     <li>gradle.properties : gradle动态参数的配置文件</li>     <li>local.properties : 本地的配置,如:SDK位置</li>     <li>gradle-wrapper.properties :gradle本地代理,声明了指向目录和版本      <ul>       <li>distributionUrl : 指定gradle版本不存在时,就从Value的地址中去下载。很多时候,我们只要版本换成我们本地存在的gradle版本就可以了</li>      </ul> </li>     <li>settings.gradle : 配置Gradle中的Module管理 <h2>常用Gradle Task</h2> ~ 表示 gradlew (Mac 使用gradle ,没有w)</li>     <li>gradlew task -all : 罗列出所有Task ,同时携带具体作用和相互关系</li>     <li> <p>gradlew assembleDebug : 导出所有渠道测试包</p>      <ul>       <li>~ assembleRelease : 导出所有渠道正式包</li>       <li>~ assembleBaiduDebug --stacktrace : 导出指定渠道测试包,同时携带异常信息</li>      </ul> </li>     <li> <p>~ --stop : 立即停止编译</p> </li>     <li>~ check : 检查任务</li>     <li>~ build : 执行了 check和assemble</li>     <li>~ clean : 清除所有中间编译结果</li>    </ul>    <h2>动态参数配置</h2>    <p>在Gradle中动态配置资源参数</p>    <p>我们可以根据各自的需求在不同的领域(如:buildType 的debug, defaultConfig ...)下去动态替换或配置我们项目中所使用到的资源,如 log 开关, 针对不同渠道的对应内容字段,不同版本定义引入的不同值等等</p>    <p>首先说清一点,对于动态资源在 build.gradle 中多个领域中的使用,会遵循一下顺序来进行覆盖:</p>    <p>buildType > productFlavor > defaultConfig > Manifest中的配置 > 依赖的第三方库的配置 > 任意领域中的默认值(也就是没有设置值)</p>    <ol>     <li>Manifest 占位符: 可以动态配置Manifest的参数</li>    </ol>    <pre>  <code class="language-java">在Manifest的Application节点下          //这里以友盟为例          <!-- 友盟统计相关meta-data -->          <meta-data              android:name="UMENG_APPKEY"              android:value="balabalabala" />          <meta-data              android:name="UMENG_CHANNEL"              android:value="${UMENG_CHANNEL_VALUE}" />    在build.gradle中对参数进行动态配置   productFlavors {          baidu {              manifestPlaceholders = [UMENG_CHANNEL_VALUE: "baidu"]          }  }</code></pre>    <ol>     <li>gradle.properties 的使用      <ul>       <li>系统属性:<br> 配置: systemProp.proName=123<br> 使用: System.properties['proName']</li>       <li>自定义属性 :<br> 配置: 有key: ray.proName=123 ,无key : proName = 123<br> 使用: 有key: project。property('proName') , 无key : proName</li>      </ul> </li>    </ol>    <pre>  <code class="language-java">gradle.properties中的配置    #使用系统参数配置  systemProp.keyStore=ray.jks  #使用key/value键值对配置  ray.keyPassword=123456  #属性配置  mKeyAlias=ray    build.gradle中的使用  //签名打包          release {              //签名文件所在路径              storeFile file(System.properties['keyStore'])              //签名密码              storePassword "111111"              //别名              keyAlias mKeyAlias              keyPassword project.property('ray.keyPassword')          }</code></pre>    <ol>     <li>BuildConfig 文件      <ul>       <li>在 app/build/generated/source/buildConfig 文件夹下面</li>       <li>使用: buildConfigField "String" , "key" , "\"value\""<br> 配置 buildConfig 中的属性参数 String : 参数类型(int,boolean...), key : 属性的名字, value : 属性的值, `` 为转义字符</li>      </ul> </li>    </ol>    <ol>     <li>resValue 动态修改工程资源      <ul>       <li>和buildConfig 类似, resValue("string","key","value")</li>       <li>其中 string 表示 会在 app/build/generated/res/resValue/.../generated.xml 中生成对应的String 的 key 和Value, 代码中可以直接 getResources().getString(R.string.key); 获取到value</li>       <li><strong>注意:</strong> 因为Gradle编译的时候会将脚本配置和string.xml文件中配置进行merge,所以string.xml中已经存在的key在编译前要删除,否则会报错</li>      </ul> </li>    </ol>    <pre>  <code class="language-java">//下面模拟在不同渠道下修改资源参数  productFlavors{  baidu{    buildConfigField "String" , "productCode" , "\"baidu 1.0\""    resValue("string","productName","baidu")  }  }</code></pre>    <h2>Project : build.gradle</h2>    <h3>全局属性配置</h3>    <ol>     <li> <p>在project : build.gradle 的 buildscript 中声明 ext 和自定义属性,然后在其他module中就可以直接使用这个属性了</p> <p>如下:</p> </li>    </ol>    <pre>  <code class="language-java">Project : build.gradle  buildscript {      //自定义工程使用的属性      ext {          kotlin_version = '1.1.0'          compile_version = 25      }        //声明依赖Android Gradle 插件版本      dependencies {          classpath 'com.android.tools.build:gradle:2.3.0'          classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"      }  }    Module : build.gradle 中使用  Android  {  compileSdkVersion compile_version  }  dependencies  {   compile "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"   }</code></pre>    <ol>     <li> <p>新建自己的Gradle属性文件 text.gradle , 然后在 Project 中引入,最后就可以在其他的module中直接使用了,具体应用可以参考 <a href="/misc/goto?guid=4959644061905934379" rel="nofollow,noindex">印象笔记Github</a></p> <p>如下:</p> </li>    </ol>    <pre>  <code class="language-java">text.gradle 编写如下:  ext {      kotlinVersion = "1.1.0"      rxjavaLibVersion = "1.2.0"        dependencies = [              // Rx              rxJava: "io.reactivex:rxjava:$rxjavaLibVersion"      ]  }    Project : build.gradle 中引入  //就是引入他的相对根目录路径  apply from: 'config/text.gradle'    Module : build.gradle 中使用  rootProject.ext.XXXXX    dependencies {     def dependencies=rootProject.ext.dependencies        compile dependencies.rxJava        compile "org.jetbrains.kotlin:kotlin-stdlib:$rootProject.ext.kotlinVersion"    }</code></pre>    <h3>整体结构与描述</h3>    <pre>  <code class="language-java">//声明引入的参数配置文件  apply from: 'config/dependencies.gradle'  apply from: 'config/text.gradle'    //编译配置  buildscript {        //自定义参数      ext {          kotlin_version = '1.1.0'          compile_version = 25      }        //Gradle指定使用jcenter代码仓库      repositories {          jcenter()      }      //声明依赖Android Gradle 插件版本      dependencies {          classpath 'com.android.tools.build:gradle:2.3.0'          classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"      }  }    //这里可以为项目整体配置属性   allprojects{      repositories {          jcenter()      }  }    //任务:每次构建的时候删除指定目录  task clean(type: Delete) {      delete rootProject.buildDir  }</code></pre>    <h2>Module : build.gradle</h2>    <p>控制每个Module的编译过程以及具体的参数配置</p>    <h3>defaultConfig</h3>    <p>基本配置信息</p>    <pre>  <code class="language-java">//默认配置      defaultConfig {          //包名          applicationId "com.rayhahah.gradledemo"          //最低版本          minSdkVersion 19          //目标版本          targetSdkVersion 25          //版本代码          versionCode getVersinCode()          //版本          versionName "1.0"          //自动化测试          testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"            resValue "int","test","1"      }</code></pre>    <h3>signConfigs</h3>    <p>签名配置信息</p>    <pre>  <code class="language-java">signingConfigs {            //debug模式签名文件          debug {}          //签名打包          release {              //签名文件所在路径              storeFile file("ray.jks")              //签名密码              storePassword "111111"              //别名              keyAlias "rayhahah"              keyPassword "111111"          }            //自定义签名配置          ray{              //和上面的属性一致,根据个人需求实现不同配置          }      }</code></pre>    <h3>buildTypes</h3>    <p>编译类型 : 指定编译不同类型情况下的不同配置信息</p>    <p>这里是列举了部分属性和方法</p>    <pre>  <code class="language-java">//构建配置      buildTypes {          release {                //是否启用资源优化              minifyEnabled               //启用舍弃无用资源,只有当开启混淆才能够启用              shrinkResources false              //指定混淆文件              proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'                //指定我们release包的输出文件名就是我们的渠道名字              applicationVariants.all { variant ->                  variant.outputs.each { output ->                      def outputFile = output.outputFile                      if (outputFile != null && outputFile.name.endsWith(".apk")) {                            def fileName = "${variant.productFlavors[0].name}" + ".apk"                          output.outputFile = new File(outputFile.parent, fileName);                      }                  }              }          }            debug {            }            //继承  //        rayhahah.initWith(debug)            //自定义buildType          rayhahah {              //指定签名配置文件              signingConfig signingConfigs.debug              //包名增加后缀              applicationIdSuffix ".ray"            }      }</code></pre>    <h3>sourceSets</h3>    <p>配置资源逻辑组</p>    <ul>     <li>通过指定资源 文件夹路径构建自己的工程目录</li>    </ul>    <pre>  <code class="language-java">指定Android所需要文件夹所在具体路径    sourceSets {  //这样的配置适用于将Eclipse中的项目结构迁移到AndroidStudio中          main {              //指定src资源目标目录              java.srcDirs = ['src']              //指定asset的目标目录              assets.srcDirs = ['assets']              //指定res的目标目录              res.srcDirs = ['res']              //指定依赖C文件的目标目录              jni.srcDirs = ['jni']               //指定依赖so文件的目标目录              jniLibs.srcDirs = ['libs']              //指定Manifest的目标文件路径              manifest.srcFile 'AndroidManifest.xml'          }   }</code></pre>    <ul>     <li><strong>常用! 给自己的layout分包管理!!</strong></li>    </ul>    <pre>  <code class="language-java">1. 在res下新建文件夹 layouts(其实叫什么都无所谓)  2. 然后在 layouts下 新建你要分的包 如: activity,fragment 或按照业务模块来分  3. 在分包内新建Android resource directory -> layout 不要改名字  4. 在module:build gradle 如下配置  5. 然后将以前的layout文件拷贝到对应分包的layout下就可以使用了    PS:只有在Project目录才能看到,Android目录结构是看不到的     sourceSets {          main {              res.srcDirs = [                      'src/main/res/layouts/activity',                      'src/main/res/layouts/fragment',                      'src/main/res/layouts',                      'src/main/res'                ]          }      }</code></pre>    <h3>productFlavors</h3>    <p>打包渠道配置信息(仔细看代码注释)</p>    <pre>  <code class="language-java">//多渠道打包配置  //利用Manifest占位符动态参数配置  productFlavors {          baidu {              manifestPlaceholders = [UMENG_CHANNEL_VALUE: "baidu"]          }            wandoujia {              manifestPlaceholders = [UMENG_CHANNEL_VALUE: "wandoujia"]          }            googleplayer {              manifestPlaceholders = [UMENG_CHANNEL_VALUE: "googleplayer"]          }            //不想每一个都去配置渠道名称也可以用下面这个函数          //这个函数可以将 Manifest中的占位符替换成 每个渠道的名字          productFlavors.all {              flavor -> flavor.manifestPlaceholders = [UMENG_CHANNEL_VALUE: name]          }      }</code></pre>    <h3>compileOptions</h3>    <pre>  <code class="language-java">//编译配置项      //主要配置Java编译版本      compileOptions {          sourceCompatibility org.gradle.api.JavaVersion.VERSION_1_8          targetCompatibility org.gradle.api.JavaVersion.VERSION_1_8      }</code></pre>    <h3>lintOptions</h3>    <pre>  <code class="language-java">//lint配置项      lintOptions {            //启用出错停止grgradle构建        abortOnError false          // true--检查所有问题点,包含其他默认关闭项        checkAllWarnings true          // 关闭指定问题检查        disable 'TypographyFractions','TypographyQuotes'        // 打开指定问题检查        enable 'RtlHardcoded','RtlCompat', 'RtlEnabled'        // 仅检查指定问题        check 'NewApi', 'InlinedApi'          // true--生成HTML报告(带问题解释,源码位置,等)        htmlReport true        // html报告可选路径(构建器默认是lint-results.html )        htmlOutput file("lint-report.html")          // 忽略指定问题的规则(同关闭检查)        ignore 'TypographyQuotes'      }</code></pre>    <h3>build.gradle 图形化配置</h3>    <p>AndroidStuido 给我们提供了十分友好地对于Build.gradle 图形化配置的界面,使用如下:</p>    <ul>     <li> <p>File -> Project Structure -> 选择需要配置的 Module —> 选择需要配置的领域</p> <p>如图十分直观:</p> </li>    </ul>    <p style="text-align:center"><img src="https://simg.open-open.com/show/924b8bcc143239065bc366d92e1158ce.png"></p>    <p>图形化界面.png</p>    <h2>dependencies 项目依赖</h2>    <ol>     <li>build.gradle中dependencies中的配置解析</li>    </ol>    <pre>  <code class="language-java">//dependencies : 当前Android Module构建过程中所依赖的所有库  dependencies {      //依赖指定目录下所有指定后缀的文件      compile fileTree(dir: 'libs', include: ['*.jar'])      //测试工具依赖      testCompile 'junit:junit:4.12'      //远程库的依赖 (当从远程库中下载一次过后,就会缓存到本地了)      //默认远程库配置为 jcenter()       compile 'com.android.support:appcompat-v7:25.2.0'        //依赖指定文件(这里依赖的是jar包)      compile file('libs/test-1.0.0.jar')      //依赖本地项目库      compile project(':testLibrary')        //格式:  groupId: com.squareup.retrofit2      //         artifactId : retrofit      //         version:  2.1.0      // SNAPSHOT : 表示依赖 retrofit 及其依赖的所有项目,如果他所依赖的项目在本项目中重复出现依赖,则只依赖retrofit项目中的。      // @aar :  表示只依赖retrofit,不依赖他所依赖的项目      compile ('com.squareup.retrofit2:retrofit:2.1.0-SNAPSHOT@aar')      {           //强制刷新远程库,避免远程库刷新,本地未更新           transitive = true                    //exclude : 单独去除okhttp3的依赖           exclude module : 'com.squareup.okhttp3:okhttp:3.3.0'       }    }</code></pre>    <ol>     <li> <p>so库依赖</p>      <ul>       <li>在 src/main 目录下创建 jniLibs ,然后将so文件拷贝进去就可以了</li>       <li>当然也可以通过 sourceSet 指定 jniLib 的目标目录来自定义管理依赖的so文件存放</li>      </ul> </li>     <li> <p>本地Module依赖</p>      <ul>       <li>在 build.gradle 的 dependencies 领域中添加 compile project(':testLibrary')</li>       <li>在 setting.gradle 中添加module到 include 中 如: include ':app',':testLibrary'</li>      </ul> </li>    </ol>    <h2>方法def定义</h2>    <p>在Gradle中你可以写方法供 配置信息动态调用</p>    <pre>  <code class="language-java">//自定义函数  def getVersinCode() {  //    ......  }    Android{      defaultConfig{          versionCode getVersinCode()      }  }</code></pre>    <h2>Gradle编译提速优化</h2>    <h3>检测</h3>    <ul>     <li> <p>gradlew build -profile : 编译工程同时生成编译性能分析文件,在根目录 build/reports/profile/profile-xxxx.xxx....html ,通过浏览器打开以后</p> <p>如图: 我们需要优化的就是 Task Execution</p> </li>    </ul>    <p><img src="https://simg.open-open.com/show/aa9ac8bb5d8d39df4fc9dcb672694ada.png"></p>    <p>profile.png</p>    <ul>     <li>往下拉,可以看到TaskExcution的详细参数</li>    </ul>    <p><img src="https://simg.open-open.com/show/f33f84a2e09efba9fcf17829d22af323.png"></p>    <p>TaskExcution.png</p>    <p>可以看到lint耗时最多,然后我们就可以根据自己项目中的具体情况来做优化</p>    <h3>禁用Task达到提速</h3>    <ul>     <li>根据上面的耗时来对应禁用Task来达到提速的效果</li>     <li>在 Project:build.gradle 中的 buildScript 中动态配置编译时禁用即可, 代码: gradle.startParameter.excludedTaskNames.add('lint') 就可以实现禁用了,具体需要继续禁用的可以根据项目输出的编译分析文件来作出添加和调整</li>    </ul>    <h3>AAPT</h3>    <p>aapt即Android Asset Packaging Tool,在SDK的build-tools目录下。该工具可以查看,创建, 更新ZIP格式的文档附件(zip, jar, apk)。也可将资源文件编译成二进制文件,尽管你可能没有直接使用过aapt工具,但是build scripts和IDE插件会使用这个工具打包apk文件构成一个Android 应用程序(百度百科)</p>    <ul>     <li>在Debug模式下,我们需要优化AAPT来大量提速我们的编译(记得在release下改回来)</li>    </ul>    <pre>  <code class="language-java">aaptOtions{      cruncherEnabled = false  }</code></pre>    <h3>Gradle编译优化</h3>    <ul>     <li>提升Gradle本身编译速度      <ul>       <li>gradle.properties 中配置</li>      </ul> </li>    </ul>    <pre>  <code class="language-java">//开启守护线程支持  org.gradle.daemon=true    //开启并行编译  org.gradle.parallel=true  //按需编译  org.gradle.configureondemand=true    //手动配置Gradle编译时内存分配  # Default value: -Xmx10248m -XX:MaxPermSize=256m  org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8    # 开启JNI编译支持过时API  android.useDeprecatedNdk=true</code></pre>    <ul>     <li>build.gradle 中配置</li>    </ul>    <pre>  <code class="language-java">//增加编译内存到4g  dexOptions{      incremental true          javaMaxHeapSize "4g"  }</code></pre>    <h2>认识Task</h2>    <ul>     <li>Task基本使用:</li>    </ul>    <pre>  <code class="language-java">task testTask << {        println 'testTask << print'        // 表示在task最前面来执行的过程      doFirst {          println 'testTask do first'}      // << 和 doLast表示对当前task追加执行过程,效果是一样的      doLast{          println 'testTask do last!'}  }    //task之间的依赖 dependsOn  //当执行存在依赖的task时,会先执行他的父类也就是依赖目标  task testDependsOn(dependsOn:testTask){      println 'testDependsOn default print '  }  //或者  testDependsOn.dependsOn testTask  //当执行testDependsOn是 打印顺序: testDependsOn  default print -> testTask do first -> testTask << print -> testTask do last!  //顺序总结为:  //1.不加doLast和doFirst的最先执行  //2.依赖task优先级高于自己的doFirst和doLast  //3.同一个task中的doLast按从上向下顺序执行  //4.同一个task中的doFirst按从下到上倒序执行  //5.同一个task的doFirst优先级高于doLast    //显示声明类型为Copy, 不声明默认为defaultTask  task testCopy(type : Copy){      //将当前gradle文件从src目录拷贝到dst目录      from "src"      into "dst"  }  //每一个特定的Task类型还可以含有特定的Property,比如Copy的from和to等。    //自定义property  ext.testProperty = ""    task testExtProperty << {      //直接使用自定义的property      println testProperty  }</code></pre>    <ul>     <li>自定义Task:</li>    </ul>    <pre>  <code class="language-java">//局部自定义Task  //直接在build.gradle中自定义Task  //但是也只能在当前module中引用  class TestCustomTask extends DefaultTask {      //@Optional,表示在配置该Task时,message是可选的。      @Optional      String message = 'I am jjx'      //@TaskAction表示该Task要执行的动作,即在调用该Task时,hello()方法将被执行      @TaskAction      def hello() {          println "hello world $message"      }  }    //hello使用了默认的message值  task hello(type: TestCustomTask)    //重新设置了message的值  task helloOne(type: TestCustomTask) {      message = "I am a android developer"  }      全局自定义Task  如果需要自定义大量的Task,就要新建一个Gradle文件来统一管理  通过apply来引入使用  //这是插件  apply plugin: 'com.android.application'  //这里gradle-quality.gradle就是另外单独定义了task的gradle  apply from: '../build-config/gradle-quality.gradle'</code></pre>    <h2>自定义Plugin</h2>    <p>自定义Plugin可以让我们在工程编译根据需求中自动去完成一些操作</p>    <p>下面就是一个编译后自动打印当前时间的Plugin</p>    <h3>build.gradle中直接定义</h3>    <pre>  <code class="language-java">与自定义Task十分类似  可以在build.gradle中自定义plugin  apply plugin: DateAndTimePlugin    dateAndTime {      timeFormat = 'HH:mm:ss.SSS'      dateFormat = 'MM/dd/yyyy'  }    class DateAndTimePlugin implements Plugin<Project> {      //该接口定义了一个apply()方法,在该方法中,我们可以操作Project,      //比如向其中加入Task,定义额外的Property等。      void apply(Project project) {          //加载Extension          project.extensions.create("dateAndTime", DateAndTimePluginExtension)            //使用Extension配置信息          project.task('showTime') << {              println "Current time is " + new Date().format(project.dateAndTime.timeFormat)          }            project.tasks.create('showDate') << {              println "Current date is " + new Date().format(project.dateAndTime.dateFormat)          }      }  }  //每个Gradle的Project都维护了一个ExtenionContainer,  //我们可以通过project.extentions进行访问  //比如读取额外的Property和定义额外的Property等。  //向Project中定义了一个名为dateAndTime的extension  //并向其中加入了2个Property,分别为timeFormat和dateFormat  class DateAndTimePluginExtension {      String timeFormat = "MM/dd/yyyyHH:mm:ss.SSS"      String dateFormat = "yyyy-MM-dd"  }</code></pre>    <h3>工程中定义</h3>    <p>其实本质上就是对上面的自定义Plugin结构化拆解</p>    <ol>     <li> <p>Plugin目录创建</p>      <ul>       <li>在根目录下创建 buildSrc</li>       <li>子目录结构如下: buildSrc/src/main/groovy/com/ray 和 buildSrc/src/main/resources/META-INF/gradle-plugins</li>      </ul> </li>     <li> <p>创建 buildSrc/build.gradle , 配置如下</p> </li>    </ol>    <pre>  <code class="language-java">apply plugin:'groovy'    dependecies{      compile gradleApi()      compile localGroovy()  }</code></pre>    <ol>     <li> <p>Plugin 逻辑实现</p> <p>自定义Plugin的主要实现逻辑</p> <p>在 buildSrc/src/main/groovy/com/ray 下创建 DateAndTimePlugin</p> </li>    </ol>    <pre>  <code class="language-java">class DateAndTimePlugin implements Plugin<Project> {      void apply(Project project) {          //加载Extension          project.extensions.create("dateAndTime", DateAndTimePluginExtension)            //使用Extension中的配置信息          project.task('showTime') << {              println "Current time is " + new Date().format(project.dateAndTime.timeFormat)          }            project.tasks.create('showDate') << {              println "Current date is " + new Date().format(project.dateAndTime.dateFormat)          }      }  }</code></pre>    <ol>     <li> <p>Extension 实现</p> <p>Extension 相当于Gradle配置信息(相当于实体类),然后主项目的 build.gradle 通过 Extension 传递配置(相当于赋值)</p> </li>    </ol>    <p>同样在 buildSrc/src/main/groovy/com/ray 下创建 DateAndTimePluginExtension</p>    <pre>  <code class="language-java">//每个Gradle的Project都维护了一个ExtenionContainer,  //我们可以通过project.extentions进行访问  //比如读取额外的Property和定义额外的Property等。  //向Project中定义了一个名为dateAndTime的extension  //并向其中加入了2个Property,分别为timeFormat和dateFormat  class DateAndTimePluginExtension {      String timeFormat = "MM/dd/yyyyHH:mm:ss.SSS"      String dateFormat = "yyyy-MM-dd"  }</code></pre>    <ol>     <li> <p>Plugin命名</p> <p>自定义外部引用时Plugin的名字</p> <p>在 buildSrc/src/main/resources/META-INF/gradle-plugins 下创建</p> <p>timePlugin.properties ,内容只有一行代码 : implementation-class = com.ray.DateAndTimePlugin</p> </li>     <li> <p>Plugin的使用</p> 主项目中 apply plugin:'timePlugin' <p>可选:配置 Extension :</p> </li>    </ol>    <pre>  <code class="language-java">timePlugin{      //动态修改和配置Extension属性      //这里修改了日期格式      timeFormat = 'MM/dd/yyyy'  }</code></pre>    <h3>独立Module自定义插件</h3>    <ol>     <li>新建plugin目录结构如图:</li>    </ol>    <p style="text-align:center"><img src="https://simg.open-open.com/show/952d09ba2857d9a741f53639d39692f9.png"></p>    <p>module_plugin目录.png</p>    <ol>     <li>module_name/build.gradle 的修改 如下:</li>    </ol>    <pre>  <code class="language-java">apply plugin: 'groovy'  //增加Maven的支持  apply plugin: 'maven'    version = 1.0  group = 'com.ray.plugin'  archivesBaseName = 'timeplugin'  repositories.mavenCentral()    dependencies {      compile gradleApi()      groovy localGroovy()  }    //将插件部署到repo目录下  uploadArchives {      repositories.mavenDeployer {          repository(url: uri('../repo'))      }  }</code></pre>    <ol>     <li>发布:和其他Module一样发布到中央库中</li>     <li>使用插件,主项目中配置如下:</li>    </ol>    <pre>  <code class="language-java">apply plugin: 'timePlugin'    buildscript {      repositories {          maven {              url uri('../repo')          } }      dependencies {          classpath group: 'com.ray.plugin', name: 'timePlugin',                  version: '1.0'      }  }</code></pre>    <h2>最后</h2>    <p>以上就是总结的Gradle实用的进阶指南,让我们可以更加随心所欲地去管理我们的工程。以后如果有一些新的认识或者想法,我也会在这里实时更新的。也算是自己对Gradle认识和学习的总结整理吧。</p>    <p>正确使用Gradle的配置是为了让我们开发更加便捷、效率更高,千万不要本末倒置了。</p>    <p>如果哪里理解错误,欢迎大家指出纠正</p>    <p>如果文章对你有用的话,请点赞鼓励一下哈O(∩_∩)O~~</p>    <p> </p>    <p> </p>    <p>来自:http://www.jianshu.com/p/ed4ef3b96a29</p>    <p> </p>