看不懂的 build.gradle 代码

Posted dasuAndroidTv

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了看不懂的 build.gradle 代码相关的知识,希望对你有一定的参考价值。


android Studio 这么强大的工具,就算我们不懂 gradle, groovy, 也照样能借助AS对 Android 项目进行编译、调试、运行、打包等操作。build.gradle 这个文件接触这么久了,基本的项目配置也基本很熟悉了,毕竟每次自动创建的 build.gradle 里的代码就那么几项配置,看一下那些英文单词也基本猜到是什么配置。

但是,不知道你们会不会跟我一样,在 github 上 clone 大神的项目后,总会发现他们的 build.gradle 里多了很多平常没看见过的代码,而且还看不懂代码要做什么;

或者是比如当需要进行签名时,网上资料会让你在 Android 标签内加个 signingConfigs, 然后在它里面进行各种配置,比如 storeFile, keyAlias 等等之类的。还有其他类似这种情况,比如当需要打包时,在哪个地方加个什么标签再对它进行各种配置之类的。不知道你们会不会也跟我一样会有这样的疑问,这个标签名怎么来的,为什么要放在这个位置,它里面有哪些属性可以进行配置?

疑惑久了,总想去了解下这是为什么,所以花了一段时间来学习 gradle 的相关知识,这次在这里记录也分享一下,如果有错的地方,还望指点一下。

本次计划是写个 gradle 系列博客,大概会有3-4篇,第一篇只是简单的针对某个具体的 build.gradle 文件代码进行注释解释以及抛出一些疑问,当然这个 build.gradle 不会是AS自动创建的那么简单的代码。然后再写1-2篇介绍 gradle, groovy, 相关的资料网上很多,所以不会写得很基础,大概是挑选一些我认为比较重要的知识点进行介绍。最后在前面的基础上,对 build.gradle 里面的代码进行分析讲解,比如介绍说都有哪些标签,哪里去找这些标签等等。

好了,废话就唠叨到这,下面就开始正文。


系列索引

build.gradle系列一:看不懂的build.gradle代码
build.gradle系列二:学点Groovy来理解build.gradle代码
build.gradle系列三:如何用Android Studio查看build.gradle源码
...


build.Gradle

这个 build.Gradle 文件来自 drakeet 大神的 Meizi 项目
我直接在代码上加注释,参照着注释看代码就行,是不是发现有很多代码平时都没看见过。

 
   
   
 
  1. //Model都有各自的build.gradle,这里声明该Model作为主项目,常见的还有另一个取值:

  2. //apply plugin: 'com.android.library' 声明该Model作为库使用,当然还有其他取值,后面博客会介绍

  3. apply plugin: 'com.android.application'

  4. //这里是在as里引入一个retrolambda插件,具体我也不大懂,可以看看这篇博客:

  5. //http://blog.csdn.net/zhupumao/article/details/51934317?locationNum=12

  6. apply plugin: 'me.tatarka.retrolambda'

  7. //这里是groovy的代码了,定义了一个获取时间的方法,groovy是兼容java,它可以直接使用jdk里的方法

  8. def releaseTime() {

  9.    return new Date().format("yyyy-MM-dd", TimeZone.getTimeZone("UTC"))

  10. }

  11. //file()是Project.java里的一个方法,这里定义一个File类型的对象,Project后面博客会介绍到

  12. def keyStore = file('meizhi.keystore')

  13. android {

  14.    //这个大家应该很熟悉了,有疑问的应该是后面的代码,这里表示获取一些全局变量

  15.    //这些变量的值在根目录下的build.gradle中定义,具体可以看看这篇博客:

  16.    //http://blog.csdn.net/fwt336/article/details/54613419

  17.    compileSdkVersion rootProject.ext.android.compileSdkVersion

  18.    buildToolsVersion rootProject.ext.android.buildToolsVersion

  19.    //同理,这里都是通过获取全局设置的变量值来进行相关配置,这样做的好处在于当

  20.    //你的项目里有多个model时,可以方便修改这些公共的配置,只需要修改一个地方就可以同步了

  21.    defaultConfig {

  22.        applicationId rootProject.ext.android.applicationId

  23.        minSdkVersion rootProject.ext.android.minSdkVersion

  24.        targetSdkVersion rootProject.ext.android.targetSdkVersion

  25.        versionCode rootProject.ext.android.versionCode

  26.        versionName rootProject.ext.android.versionName

  27.    }

  28.    //这里应该是设置打包后的apk里的META-INF移除指定的文件吧

  29.    packagingOptions {

  30.        exclude 'META-INF/DEPENDENCIES.txt'

  31.        //省略部分exclude 代码...

  32.    }

  33.    //关闭指定的lint检查

  34.    lintOptions {

  35.        disable 'MissingTranslation', 'ExtraTranslation'

  36.    }

  37.    //lint检查到错误时不中断编译,好像是说lint检查是为优化代码,发现的错误其实并不会导致程序异常

  38.    //所以有的时候及时发现Lint检查错误还是可以直接运行查看效果

  39.    lintOptions {

  40.        abortOnError false

  41.    }

  42.    //签名的相关配置

  43.    signingConfigs {

  44.        //这个标签名可以随意命名,这里的作用大概类似于定义一个对象,该对象里设置好了签名需要的各种配置

  45.        //可以定义不止一种配置的签名对象,例如常见的还有 debug{...}, release{...},然后在buildTypes{}里

  46.        //通过 signingConfigs.app1 进行调用

  47.        app1 {

  48.            //签名的相关配置,网上资料很多,STOREPASS, KEYALIAS, KEYPASS 这些常量是定义在

  49.            //gradle.properties 文件里,如果没有该文件手动创建即可,这样可以保证安全

  50.            //只有定义在 gradle.properties 里的常量才可以直接通过常量名引用

  51.            storeFile file('meizhi.keystore')

  52.            storePassword project.hasProperty('STOREPASS') ? STOREPASS : ''

  53.            keyAlias project.hasProperty('KEYALIAS') ? KEYALIAS : ''

  54.            keyPassword project.hasProperty('KEYPASS') ? KEYPASS : ''

  55.        }

  56.    }

  57.    //编译,打包的项目配置

  58.    buildTypes {

  59.        debug {

  60.            //在 BuildConfig 里自定义一个 boolean 类型的常量

  61.            //更多资料可以查看:http://stormzhang.com/android/2015/01/25/gradle-build-field/

  62.            buildConfigField "boolean", "LOG_DEBUG", "true"

  63.            debuggable true

  64.            applicationIdSuffix ".debug"

  65.        }

  66.        release {

  67.            buildConfigField "boolean", "LOG_DEBUG", "false"

  68.            debuggable false

  69.            //开启混淆

  70.            minifyEnabled true

  71.            //删除无用的资源

  72.            shrinkResources true

  73.            //混淆文件

  74.            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'

  75.            if (keyStore.exists()) {

  76.                println "Meizhi: using drakeet's key"

  77.                //根据在signingConfigs.app1里的签名配置进行签名

  78.                signingConfig signingConfigs.app1

  79.            } else {

  80.                println "Meizhi: using default key"

  81.            }

  82.            //这段代码应该会在大神的项目里挺常见的,我在很多项目里都看见过了

  83.            //这也是groovy的代码,这里的代码作用是重命名最后打包出来的apk

  84.            //根据 def fileName 设置的格式来命名,${}表示的是某个变量的引用

  85.            //例如根据设置的格式最后apk命名可能是: Meizhi_v1.0.0_2017-03-28_fir.apk

  86.            //至于 applicationVariants 这些变量含义后面博客会介绍

  87.            applicationVariants.all { variant ->

  88.                variant.outputs.each { output ->

  89.                    def outputFile = output.outputFile

  90.                    if (outputFile != null && outputFile.name.endsWith('.apk')) {

  91.                        def fileName = "Meizhi_v${defaultConfig.versionName}_${releaseTime()}_${variant.productFlavors[0].name}.apk"

  92.                        output.outputFile = new File(outputFile.parent, fileName)

  93.                    }

  94.                }

  95.            }

  96.        }

  97.        //这里的作用跟 singingConfigs 差不多,只是为不同的 flavor 设置一些属性

  98.        //常见的设置比如设置不同的渠道编号,设置不同的 api 服务器等等

  99.        productFlavors {

  100.            fir {

  101.                //这个的作用是将 AndroidManifest.xml 里的占位符 ¥{UMENG_CHANNEL_VALUE} 的值替换成fir

  102.                manifestPlaceholders = [UMENG_CHANNEL_VALUE: "fir"]

  103.            }

  104.            GooglePlay {

  105.                manifestPlaceholders = [UMENG_CHANNEL_VALUE: "GooglePlay"]

  106.            }

  107.            Umeng {

  108.                manifestPlaceholders = [UMENG_CHANNEL_VALUE: "Umeng"]

  109.            }

  110.        }

  111.    }

  112.    //设置JDK的版本通过compileOptions

  113.    compileOptions {

  114.        sourceCompatibility JavaVersion.VERSION_1_8

  115.        targetCompatibility JavaVersion.VERSION_1_8

  116.    }

  117.    //lint的相关配置吧

  118.    lintOptions {

  119.        disable "InvalidPackage"

  120.        lintConfig file("lint.xml")

  121.    }

  122. }

  123. //这里就不用说了

  124. dependencies {

  125.    compile fileTree(dir: 'libs', include: ['*.jar'])

  126.    compile project(":libraries:headsupcompat")

  127.    compile project(":libraries:smooth-app-bar-layout")

  128.    //as默认会去下载传递依赖,下面是指定不需要去下载传递依赖

  129.    compile ('com.squareup.retrofit2:retrofit:2.1.0') {

  130.        exclude module: 'okhttp'

  131.    }

  132.    retrolambdaConfig 'net.orfjackal.retrolambda:retrolambda:2.3.0'

  133.    //省略部分compile代码...

  134. }

疑问

1.apply plugin: 'com.android.application' 听说这是调用一个方法?

2.rootProject.ext.android.compileSdkVersion, 不用 ext 来设置全局变量是否可以?

3.defaultConfig{}, packagingOptions{}, signingConfigs{}, buildTypes{} 等等这些,我怎么知道 Android{} 里都有哪些可以使用?

...

参考资料

·徐宜生写的《Android群英传:神兵利器》第4章:与Gradle的爱恨情仇
·retrolambda使用教程
·Gradle配置全局变量
·GRADLE自定义你的BUILDCONFIG  



以上是关于看不懂的 build.gradle 代码的主要内容,如果未能解决你的问题,请参考以下文章

搞笑如何写出别人看不懂自己也看不懂的代码

一段看不懂的代码(关于描述符)

Java进阶知识点2:看不懂的代码 - 协变与逆变

学习宝典XSS攻击进阶篇——那些年我们看不懂的XSS

Java小白也能轻松写一个大神都看不懂的程序,绝对让人佩服

Java小白也能轻松写一个大神都看不懂的程序,绝对让人佩服