zoukankan      html  css  js  c++  java
  • 从编程的角度理解gradle脚本﹘﹘Android Studio脚本构建和编程[魅族Degao]

    本篇文章由嵌入式企鹅圈原创团队、魅族资深project师degao撰写。

    随着Android 开发环境从Eclipse转向Android Studio,我们每一个人都開始或多或少要接触gradle脚本。大多数人将gradle看做构建工具。出现故障不知怎样着手分析,仅仅能寄希望百度能找到解决方式,事实上大可不必。

    假设我们把gradle看做编程框架,并理清gradle脚本与gradle对象的关系,通过查阅文档,不但能清晰理解gradle脚本,并且出现故障再也不用百度,通过查阅文档就能轻松解决这个问题。

    本文就通过一个最普通的gradleproject。告诉大家怎样通过查阅api文档来看懂Android里面的gradle 脚本。

    一、gradle介绍

    gradle基于的语言是groovy,而groovy语言是基于java语言的一个扩展。它全然兼容java语言的类库,所以在gralde脚本中你全然能够使用你熟悉的java语言来编程。在本文最后我们会给出一个直接在gradle脚本中使用java编程的样例。

    因为本文仅仅是让大家能看懂脚本,而不是自己去编写。所以groovy和gradle的细节不是本文的重点。有须要的同学自行百度。

    这里要提的一点是groovy语言的函数调用是尽管和java相似,可是它是能够省略括号的,特别是当它的最后一个參数是闭包的时候。

    println(“aaa” )//这个是能够的,

    println“aaa” //这个也没有问题。

    是不是发现了一个秘密:我们在gradle脚本里全是各种函数调用!!

    Gradle api文档路径:https://docs.gradle.org/current/dsl/

    因为我们也用到了Android 插件,所以我们也须要插件的文档,这个文档比較特殊,它是一个gitproject,在线浏览老是显示html的源代码而非页面,所以我建议大家将它clone回本地,然后用浏览器打开,project地址:https://github.com/google/android-gradle-dsl.git


    二、gradle脚本和gradle 类相应关系

    稍稍浏览下gradle的文档。我们会发现project里面的gradle脚本,事实上和gradle的对象是相应的:

    1.Gradle:全局对象,一次gradle构建相应一个Gradle对象。

    2.Project:每一个project都是一个Project对象,它相应一个build.gradle文件。

    3.Settings:相应一个Setting.gradle文件;

    4.Task:代表要运行的工作,一个Project会有一个或多个Task用于完毕构建的工作。Project会通过合理设置Task之间的依赖来组织构建流程,完毕终于的构建任务。


    三、脚本运行流程与对象生成

    1.每次调用gradle 运行时,会先生成一个Gradle对象,里面保存一些全局的信息;

    2.然后会解析setting.gradle,生成Settings对象。一般在setting.gradle中主要是调用include方法,导入project下的各个子模块。

    3.接下来会运行导入的各个子project的build.gradle,生成并配置Project对象。

    一般在build.gradle中,会调用Project的apply方法,引入插件,在插件中完毕定义各种属性以及创建所需的Task。


    四、实例解析

    我们以一个Android studio 默认app样例project结构为例,project包括的gradle脚本文件夹结构:

    1. setting.gradle

    setting.gradle仅仅有一行语句:

    include ':app'

    这里的include事实上是Setting的一个函数,‘:app' 是函数调用的參数。

    那我们在setting.gradle里面还能写什么呢?因为setting.gradle相应的是gradle中的Settings对象。那查下Settings的文档(https://docs.gradle.org/current/dsl/org.gradle.api.initialization.Settings.html)。看下它都有哪些方法。哪些属性,就知道在setting.gradle能写什么了:

    比方:

    include ':Common'

    project(':Common').projectDir = new File(settingsDir,'../../SDK/Common/')//include 调用后,生成了一个名为:CommonProject对象,project(':Common')取出这个对象,设置ProjectprojectDir属性。

    那projectDir哪里来的?请看Project类的文档。


    2. build.gradle

    接下来我们来看build.gradle。build.gradle相应一个Project对象,而Project本身是一个Build script

    而BuildScript能够包括哪些东西呢?


    是不是看到了非常多老朋友?buildscript , dependencies 。。

    看了这里我们应该就能明确在build.gradle里面能够写哪些东西了。


    这里要说明的一个重要的点是buildscript不论什么一个build.gradle运行的时候,会优先处理buildscript,它是来给脚本建立运行环境的,什么是运行环境?

    一般而言就是下载所须要的插件,举个样例,androidproject都须要android插件。它们都是通过以下的方式引入的:

    buildscript {

       repositories {//告诉假设本地没有缓存。去哪个远程仓库下载插件

            mavenCentral()

       }

       dependencies {

            //这就是我们在applyplugin:com.android.application时的插件jar

            classpath 'com.android.tools.build:gradle:1.3.0'

            // NOTE: Do not place your application dependencies here; theybelong

            //in the individual module build.gradle files

       }

    }

    repositories {//告诉假设本地没有缓存。去哪个远程仓库下载编译时依赖的库

            mavenCentral()

        }

    上面的repositories。 dependencies都是函数调用哦~~

    看到上面的两个一模一样的repositories 了吗?他们的作用是不一样的。在buildscript里面的那个是插件初始化环境用的,用于设定插件的下载仓库,而外面的这个是设定project依赖的一些远程library的下载仓库的。

    在build.gradle中引入插件。是我们常见的动作:

    apply plugin: 'com.android.application'

    查阅Project的文档(https://docs.gradle.org/current/dsl/org.gradle.api.Project.html).apply是Project的一个方法,

    3. android相关部分

    查阅android插件的文档:(file:///home/test/android-gradle-dsl/1.5/index.html

    上面就是我们在android{}里面能写的全部block的信息,然后在每一个block里面能写什么继续点击进去察看有哪些属性和方法就能够了,

    比方signingConfigs:

    signingConfigs{

       release {

            storeFile file('../sign/release.jks')

            storePassword "5mall@ndro!d"

            keyAlias "small"

            keyPassword"5mall@ndro!d"

       }

    }

    本文至此能够告一段落,相信大家结合文档应该能弄明确gradle脚本里面的每一个代码块的意义了。

    五、Androidproject间的父子关系

    须要补充的是:上面样例project的结构中,project之间是存在父子关系的,比方RxJava-Android-Samples/build.gradle相应的Project是RxJava-Android-Samples/app/build.gradle相应的Project的父亲,而在父Project中做的操作是会被子Project继承的,比方假设在 父Project引入过了android 插件,则在子Project中可直接引用。不须要重写一个buildscript块。

    1.   RxJava-Android-Samples/build.gradle

    buildscript {

       repositories {

            mavenCentral()

       }

       dependencies {

            classpath 'com.android.tools.build:gradle:1.3.0'

            // NOTE: Do not place your application dependencies here; theybelong

            //in the individual module build.gradle files

       }

    }

    allprojects {

       repositories {

            mavenCentral()

       }

    }

     

    2.   RxJava-Android-Samples/app/build.gradle

    //直接引用android插件。没有buildscript准备插件;

    apply plugin:'com.android.application'

    dependencies {

       compile 'com.android.support:support-v13:23.0.1'

       compile 'io.reactivex:rxandroid:1.0.1'

       // BecauseRxAndroid releases are few and far between, it is recommended you also

       // explicitly depend on RxJava'slatest version for bug fixes and new features.

       compile 'io.reactivex:rxjava:1.0.14'

       compile 'io.reactivex:rxjava-math:1.0.0'

       compile 'com.jakewharton.rxbinding:rxbinding:0.2.0'

       compile 'com.jakewharton:butterknife:5.1.1'

       compile 'com.jakewharton.timber:timber:2.4.2'

       compile 'com.squareup.retrofit:retrofit:1.6.1'

       compile 'com.squareup.okhttp:okhttp:2.0.0'

       compile 'com.squareup.okhttp:okhttp-urlconnection:2.0.0'

       compile 'com.alibaba:fastjson:1.2.4'

       debugCompile 'com.squareup.leakcanary:leakcanary-android:1.3'

       releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.3'

    }

    android {

       compileSdkVersion 23

       buildToolsVersion '23.0.1'

       defaultConfig {

            applicationId "com.morihacky.android.rxjava"

            minSdkVersion14

            targetSdkVersion22

            versionCode1

            versionName"1.0"

       }

       buildTypes {

            release {

                minifyEnabled true

                proguardFilesgetDefaultProguardFile('proguard-android.txt'),'proguard-rules.pro'

            }

       }

    }

    六、在gradle中使用java语言编程的样例

           直接上代码,想学习的就劳心理解啦,编辑器对代码不太友好啊。

    1. build.gradle

    buildscript {

        repositories{

        maven {

            url 'http://artifactory.rnd.meizu.com/artifactory/all'

        }

    }

        dependencies {

            classpath 'org.aspectj:aspectjtools:1.8.6'

        }

    }

    importorg.aspectj.bridge.IMessage

    import org.aspectj.bridge.MessageHandler

    importorg.aspectj.tools.ajc.Main

    dependencies{

    compile'org.aspectj:aspectjrt:1.8.6'

    }

    android.applicationVariants.all{ variant ->

        JavaCompile javaCompile = variant.javaCompile

        //println javaCompile.properties

        javaCompile.doLast {

            String[] args = [

                    "-showWeaveInfo",

                    "-1.5",

                    "-inpath", javaCompile.destinationDir.toString(),

                    "-aspectpath",javaCompile.classpath.asPath,

                    "-d", javaCompile.destinationDir.toString(),

                    "-classpath",javaCompile.classpath.asPath,

                    "-bootclasspath",android.bootClasspath.join(File.pathSeparator)

            ]

            MessageHandler handler = newMessageHandler(true);

            new Main().run(args, handler)

            def log = project.logger

            for (IMessage message : handler.getMessages(null,true)) {

                switch (message.getKind()) {

                    case IMessage.ABORT:

                    case IMessage.ERROR:

                    case IMessage.FAIL:

                        log.error message.message,message.thrown

                        break;

                    case IMessage.WARNING:

                    case IMessage.INFO:

                        log.info message.message,message.thrown

                        break;

                    case IMessage.DEBUG:

                        log.debug message.message,message.thrown

                        break;

                }

            }

            println "aspect args : " +args.toString()

        }

    }

    2. groovy

    以下这段代码展示了groovy中变量定义,函数定义,List,Map,Range,闭包。

    1)变量定义

    defvariable1 = 1   //能够不使用分号结尾 

    2)函数定义。

    StringtestFunction(arg1,arg2){//无需指定參数类型 

          ... 

    3)List变量由[]定义,比方 

    defaList = [5,'string',true] //List由[]定义,其元素能够是不论什么对象

    4)List存取

    aList[100]= 100 //设置第101个元素的值为10 

    assertaList[100] == 100

    5)Map变量由[:]定义,比方

    defaMap = ['key1':'value1','key2':true] 

    Map由[:]定义。注意当中的冒号。冒号左边是key,右边是Value。key必须是字符串,value能够是不论什么对象。另外,key能够用''或""包起来,也能够不用引號包起来。比方:

    defaNewMap = [key1:"value",key2:true]//当中的key1和key2默认被处理成字符串"key1"和"key2" 

    只是Key要是不使用引號包起来的话,也会带来一定混淆。比方 

    defkey1="wowo" 

    defaConfusedMap=[key1:"who am i?

    "] 

    //aConfuseMap中的key1究竟是"key1"还是变量key1的值“wowo”?显然,答案是字符串"key1"。假设要是"wowo"的话,则aConfusedMap的定义必须设置成: 

    defaConfusedMap=[(key1):"who am i?

    "] 

    6)Range类,Range类型的变量 由begin值+两个点+end值表示

    def aRange =1..5 

    //假设不想包括最后一个元素,则 

    defaRangeWithoutEnd = 1..<5 

    //包括1,2,3,4这4个元素

    7)闭包

    defxxx = {paramters -> code}  //或者 

    defxxx = {无參数,纯code}

    比方: 

    defgreeting = { "Hello, $it!" } 

    assertgreeting('Patrick') == 'Hello, Patrick!'

    当函数的最后一个參数是闭包的话。能够省略圆括号。

    public static<T> List<T>each(List<T> self, Closure closure) 

    上面这个函数表示针对List的每一个元素都会调用closure做一些处理。

    这里的closure。就有点回调函数的感觉。可是,在使用这个each函数的时候。我们传递一个怎样的Closure进去呢?比方: 

    def iamList =[1,2,3,4,5]  //定义一个List 

    iamList.each{//调用它的each,这段代码的格式看不懂了吧?each是个函数,圆括号去哪了?

          println it 

    上面代码有以下知识点: 

    each函数调用的圆括号不见了!

    原来。Groovy中,当函数的最后一个參数是闭包的话,能够省略圆括号。比方 

    deftestClosure(int a1,String b1, Closure closure){ 

          //dosomething 

         closure() //调用闭包 

    那么调用的时候,就能够免括号!

     

    testClosure4, "test", { 

       println"i am in closure" 

    }

     

    開始你的Gradle构建和编程之旅吧~~


    很多其它的嵌入式linux和android、物联网、汽车自己主动驾驶等领域原创技术分享请关注微信公众号:


     

  • 相关阅读:
    java修改应用程序标题栏
    电动双轮车
    Oracle执行计划相关(待补充)
    SQL中IN和EXISTS用法的区别
    union all与union all
    equals与hashcode
    文件上传的整个流程
    adwords与adsence
    struts2文件上传大小
    为什么是UUID做主键
  • 原文地址:https://www.cnblogs.com/cxchanpin/p/7097362.html
Copyright © 2011-2022 走看看