美文网首页
Android和java构建工具gradle语言深入了解与插件开

Android和java构建工具gradle语言深入了解与插件开

作者: 进击的大东 | 来源:发表于2019-03-11 00:33 被阅读0次

    Gradle3.0编程与自动化构建

    gradle是一款最新的,功能强大的构建工具,它使用程序代替传统的XML配置,构建项目更加灵活。gradle有丰富的第三方插件。

    Gradle相关介绍及开发环境搭建

    gradle相关概念介绍

    要了解Gradle首先需要了解DSL和groovy与gradle的关系
    • 领域特定语言DSL介绍(gradle属于DSL中一种)

      • 全称domain specific language:它分三类,包含建模语言,sql,html,groovy等

        • 外部DSL

        • 内部DSL

        • 语言工作台

      • 优点

        1、提高开发效率,通过DSL来抽象构建模型,抽取公共的代码,减少重复的劳动;

        2、和领域专家沟通,领域专家可以通过DSL来构建系统的功能;

        3、执行环境的改变,可以弥补宿主语言的局限性。

      • DSL语言与系统编程语言相辅相成,核心思想是求专不求全,解决特定问题

    • groovy详解和初探(Gradle使用的语言就是groovy)

      • 介绍

        • groovy是一种基于JVM的敏捷开发语言

        • 结合了Python、Ruby和Smalltalk的许多强大特性

        • groovy可以与Java完美结合,而且可以使用java所有的库

      • 特性

        • 语法上支持动态类型,闭包等新一代语言特性

        • 无缝集成所有已经存在的java类库

        • 即支持面向对象编程也支持面向过程编程

    • groovy优势

      • 一种更加敏捷的编程语言

      • 入门非常的容易,但是功能非常的强大

      • 既可以作为编程语言也可以作为脚本语言

      • 有java基础很容易上手groovy

    各系统平台下gradle开发环境搭建及工程创建

    • mac/linux环境下,groovy开发环境搭建

      • 安装jdk

      • 到官网下载groovy,解压到合适位置

      • 配置groovy环境变量

      • 输入groovy -version测试

    • windows环境下groovy开发环境搭建

      • 安装jdk

      • 到官网下载groovy,解压到合适位置

      • 配置groovy环境变量

      • 输入groovy -version测试

    • IntelliJ IDEA开发工具安装及groovy环境配置

      • 下载安装idea基础版(无需破解支持groovy)

      • 旧版本安装groovy插件

    • 在idea中创建一个groovy工程

      • 创建项目,选择groovy,指定groovy和jdk目录

      • 新建groovy.class,groovy不仅能写java,也能写脚本语言

        class HelloGroovy{
            static void main(args){
                println "hello groovy"
            }
        }
        

    Gradle核心语法详解及实践

    groovy基本类型会自动转为对象类型

    字符串特殊用法

    • String

      • 可以通过def来定义
    • GString

      • 常用的三种定义方式

        • 一般使用单引号:单引号是普通字符串,类似java中的双引号字符串

        • 双引号:可扩展字符串,通过变量来拼接--》def sayHello="hello: ${n}" ,这时它的类型是GStringImpl

        • 三引号:预输出字符串,类似html中p标签

      • 新增字符串操作

        • 字符串扩展可以字符串和任意表达式拼接
      • 新增API讲解

        • println str.center(8,'a''):表示用a填充字符串,原字符串在中间

        • println str.padLeft(8,'a')向左添加至字符串长度为8位,也有向右添加方法

        • 字符串可以直接通过大于小于号进行比较,也可以通过compareTo()函数比较

        • 字符串获取其中的:str[0],也可以str.getAt(0),可以获取多个-》str[0..1]

        • 字符串减法:str.minus(str2)也可以直接用减号-》str-str2

        • 字符串倒序操作:str.reverse()

        • str.capitalize():首字母大写

        • 判断是否是int类型字符串:str.isNumber()

        • 字符串直接转类型:str.toDouble()

    gradle常见数据结构包含(list,map,range...)使用

    • 逻辑控制

      • 顺序逻辑:单步往下执行

      • 条件逻辑:if/else,swtch/case

        • if/else和其它语言使用基本一样

        • switch/case

          • 支持任意类型的case(list,range,string,int,double),列表中包含的时候会匹配到
      • 循环逻辑:while,for

        • while和其它语言使用基本一样

        • for:可以使用范围0..9特有数据结构

           def sum=0
           //范围循环
          
           for (i in 0..9){
          
               sum+=i
          
           }
           //循环list,list在这更像一个数组
           for (i in [1,2,3,4,56,78,9]){
               sum +=i
          
           }
           //map循环
            for (i in ['lili':1,'luck':3,'xiaoming':5]){
               sum+=i.value
          
            }
          
    • 闭包

      • groovy闭包基础

        • 闭包概念

          • 闭包定义:闭包可以说是定义在函数中的函数,其实闭包就是一个代码块

            //定义闭包
            def clouser = {println 'hello groovy'}
            clouser.call()//简单执行
            
          • 闭包调用:clouser.call(‘will’)/clouser()

        • 闭包参数

          //带参数闭包,这里使用双引号可以取出参数并拼接
          def clouser1 = {String name ->println "hello groovy ${name}"}
          
        • 闭包返回值

          def clouser = {return "hell ${it}"}//这里it表示输出默认参数,return返回值
          
      • groovy闭包使用-》常用的

        • 与基本类型的结合使用

          int x=fab(5)
          println x
          //结合upto函数,实现阶乘
          int fab(int number){
              int result=1
              1.upto(number,{num->result*=num})
              return result
          }
          //结合downto函数实现阶乘
          int fab2(int number){
          
              int result =1
              number.downto(1){
                  num->result*=num
              }
              return result
          }
          //闭包累加
          int z=numAdd(6)
          println z
          int numAdd(int number){
              int result =0
              number.times {
                  num -> result+= num
              }
              return result
          }
          
        • 与String结合使用

          Str
          ing str ='the 2 and 3 is 5'
          //字符串遍历,方法后面加闭包
          str.each {
              String temp -> print temp+','
          }
          //find查找符合条件的第一个
          println str.find{
              String s-> s.isNumber()
          }
          //闭包查找所有字符串
          def list=str.findAll{String s-> s.isNumber()}
          println list.toListString()
          //any方法和闭包判断是否包含数字
          def result=str.any {
              String s-> s.isNumber()
          }
          println result
          str.every//此方法是所有都符合返回ture,否则false
          //闭包遍历字符串转换大写
          def listToUpper=str.collect {it.toUpperCase()}
          
        • 闭包进阶

        • 与数据结构结合使用

        • 与文件结合使用

      • 闭包进阶<a id="clouser" href="#"></a>

        • 闭包的关键变量

              def scriptClouser={
              println "scriptClouser this:"+this
              println "scriptClouser owner:"+owner
              println "scriptClouser delegate:"+delegate
             }
             //三个变量输出结果一样
          
              scriptClouser.call()
          
          • this:代表闭包定义处的类

          • owner:代表闭包定义处的类或者对象

          • delegate:代表任意对象,默认值与owner一致

          在类中定义一个闭包,this、owner、delegate三个对象一致;在闭包中定义闭包,this和其它两个就不同;delegate对象被修改后会和owner不同
          class Person{
              def classClouser={
                  println "classClouser this:"+this
                  println "classClouser owner:"+owner
                  println "classClouser delegate:"+delegate
              }
          }
          Person p=new Person()
          p.classClouser.call()
          //闭包中定义闭包
          def nestClouser={
              def innerClouser={
                  println "innerClouser this:"+this
                  println "innerClouser owner:"+owner
                  println "innerClouser delegate:"+delegate
              }
              innerClouser.delegate=p//修改默认的delegate
              innerClouser.call()
          }
          
        • 闭包委托策略

          • 有四种委托策略(OWNER_FIRST,OWNER_ONLY,DELEGATE_FIRST,DELEGATE_ONLY),默认委托策略是OWNER_FIRST
          class Person{
              String name
              def pretty ={"My name is ${name}"}
              String toString() {
                  pretty.call()
              }
              def classClouser={
                  println "classClouser this:"+this
                  println "classClouser owner:"+owner
                  println "classClouser delegate:"+delegate
              }
          }
          class Teacher{
              String name
          }
          Person p=new Person()
          p.classClouser.call()
          def nestClouser={
              def innerClouser={
                  println "innerClouser this:"+this
                  println "innerClouser owner:"+owner
                  println "innerClouser delegate:"+delegate
              }
              innerClouser.delegate=p//修改默认的delegate
              innerClouser.call()
          }
          def stu=new Person(name:'xiaoming')
          def tea=new Teacher(name:'lili')
          stu.pretty.delegate=tea//修改默认delegate
          stu.pretty.resolveStrategy=Closure.DELEGATE_FIRST//指定闭包的委托策略
          println '输出'+stu.toString()
          

      闭包数据结构
    • 列表

      • 列表的定义

        def list=[1,2,-3,4,5,6]//定义和初始化,默认是ArrayList
        def list=[1,2,3,4,5,6] as int[]//int类型数组,也可以和java一样定义
        //groovy数组操作和list一样
        
      • 列表的操作

        • list.addAll([10,15])
          list.add(6)
          
        • assert [1,'2',3,1,1,1].removeAll(['2',3])
          assert list.remove(2)
          assert list.removeAll([4,5])
          list.removeAt(1)
          print list
          
        • //循环list,list在这更像一个数组
           for (i in [1,2,3,4,56,78,9]){
            print i
           }
           //简洁循环
           [1,2,3].each{it -> store += it}
           //find查找符合条件的第一个
           println str.find{
           String s-> s.isNumber()
          }
          //查找所有奇数
          def findList=[-3,9,6,2,-7,1,5]
          def result=findList.findAll{return it%2!=0}
          print result
          //any和every方法
          findList.any{return it%2!=0}
          findList.every{return it%2!=0}
          //查找最大和最小值;也可以闭包指定规则
          findList.min()
          findList.max{return Math.abs(it)}//闭包绝对最大值
          findList.count()
          
        • def list=[1,2,-3,4,5,6]
          Comparator mc={
              a,b-> a==b? 0:Math.abs(a)return it.size()}//按照字符串长度排序
          
    • map与map类型映射

      def colors=[red:'ff0000',green:'00ff00',blue:'0000ff']
      //索引方式
      println colors['red']
      colors.red
      //添加元素
      colors.leftShift(white:"fffff")
      colors.yellow='ffff00'
      colors.complex=[a:1,b:2]//可以添加任意元素到map
      println colors.toMapString()
      println colors.getClass()//LinkedHashMap默认是LinkedHashMap,可以通过as关键字修改映射类型
      //遍历
      colors.each {
          def color->
              println "this key is ${color.key},"+
                      "the value is ${color.value}"
      }
      colors.eachWithIndex{ def entry, int i ->
          println "this key is ${entry.key},"+
              "this index is ${i},"+
                  "the value is ${entry.value}"
      }
      colors.each {
          def key,def value->
              println "this key is ${key},"+
                      "the value is ${value}"
      }
      //查找
      def entry=colors.find {def c->
          return c.value.equals('0000ff')
      }
      println entry
      
      def students=[
              1:[number:'001',name:'Bob',score:55,sex:'male'],
              2:[number:'002',name:'Amey',score:60,sex:'male'],
              3:[number:'003',name:'Leo',score:77,sex:'male'],
              4:[number:'004',name:'Habby',score:99,sex:'male']
      ]
      //强大的函数直接分组
      def group=students.groupBy {def student->
          return student.value.score>=60? '及格':'不及格'
      }
      println group.toMapString()
      
    • 范围

      • 范围的基本概念:范围继承list,但是比list简单点

      • 范围操作:

        def range=1..10
        println range[0]
        println range.contains(10)
        println range.from
        println range.to
        //遍历
        range.each {
            print it
        }
        def result=getGrade(75)
        println result
        def getGrade(Number number){
            def result
            switch (number){
                case 0..<60:
                    result='不及格'
                    break
                case 60..<70:
                    result='及格'
                    break
                case 70..<80:
                    result='良好'
                    break
                case 80..<100:
                    result='优秀'
                    break
            }
            return result
        }
        

    gradle面向对象特性

    • groovy中类,接口等的定义和使用
    //class Person implements Action{//实现接口
    class Person implements DefaultAction{//实现Trait类
    
        String name
        Integer age
        def increaseAge(Integer years){
            this.name+=years
        }
        @Override
        void eat() {
        }
        @Override
        void drink() {
        }
    
        @Override
        void play() {
    
        }
    }
    //定义接口
    interface Action {
        void eat()
        void drink()
        void play()
    
    }
    //定义trait类型,类似接口,但是可以有实现类
    trait DefaultAction {
        abstract void eat()
        void play(){
            println 'i can play'
        }
    }
    
    • groovy中的元编程

      • groovy在执行方法的时候先判断类中是否有此方法-》有调用,没有-》判断MetaClass中是否有此方法-》判断是否重写了methodMissing()方法-》判断是否重写了InvokeMethod方法-》以上没通过抛出MissingMethodException

        //class Person implements Action{
        class Person  {
            String name
            Integer age
            def increaseAge(Integer years){
                this.name+=years
            }
            //一个方法找不到时调用它来代替,否则抛出MissingMethodException
            def invokeMethod(String name,Object args){
                return "the method is ${name},the params is ${args}没有此方法"
            }
            //一个方法找不到时先调用这个方法然后调用invokeMethod方法
            def methodMissing(String name,Object args){
                return "this method ${name} is missing"
            }
        }
        
        def person=new Person(name:"will",age:25)
        //println person.age
        println person.cry()//调用一个不存在的方法
        //为类动态添加一个属性
        Person.metaClass.sex='male'
        //为类动态添加方法
        Person.metaClass.sexUpperCase={-> sex.toUpperCase()}
        def person2=new Person(name:"will",age:25)
        println person2.sexUpperCase()
        //为类动态添加静态方法
        Person.metaClass.static.createPerson={
            String name,int age->new Person(name:name,age:age)
        }
        def person3=Person.createPerson("Amey",30)
        println person3.name
        

    Gradle高级用法实践

    gradle中json文件处理及json,model互转,网络json处理

    import groovy.json.JsonOutput
    import groovy.json.JsonSlurper
    
    def list=[new Person(name:'John',age:25)
            ,new Person(name: 'mary',age:26)]
    def jsonStr= JsonOutput.toJson(list)
    println jsonStr
    println JsonOutput.prettyPrint(jsonStr)
    def jsonSlpuer=new JsonSlurper()
    //jsonSlpuer.parse()
    println jsonSlpuer.parseText(jsonStr)
    //从网络获取json并解析
    def response=getNetWorkData('https://www.sojson.com/open/api/lunar/json.shtml')
    println response.data.suit//输出网络数据
    //获取数据返回对象
    def getNetWorkData(String url){
        //发送http请求
        def connection=new URL(url).openConnection()
        connection.setRequestMethod('GET')
        connection.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)")
        connection.connect()
        def responese=connection.content.text
        //将json对象转化为实体对象
        def jsonSluper=new JsonSlurper()
        return jsonSluper.parseText(responese)
    }
    

    xml文件读取和生成

    import groovy.xml.MarkupBuilder
    
    final String xml='''
    
    NOAA's National Weather Service
    http://weather.gov/
    
    http://weather.gov/images/xml_logo.gif
    NOAA's National Weather Service
    http://weather.gov
    
    New York/John F. Kennedy Intl Airport, NY
    KJFK
    40.66
    -73.78
    Mon, 11 Feb 2008 06:51:00 -0500 EST
    
    A Few Clouds
    11
    -12
    36
    West
    280
    18.4
    29
    1023.6
    30.23
    -11
    -24
    -7
    -22
    10.00
    
    http://weather.gov/weather/images/fcicons/
    nfew.jpg
    http://weather.gov/disclaimer.html
    http://weather.gov/disclaimer.html
    
    '''
    //开始解析xml数据
    def xmlSluper=new XmlSlurper()
    def response=xmlSluper.parseText(xml)
    println response.current_observation.credit
    //自带深度遍历
    def taglist=response.depthFirst().findAll {
        wind_dir ->
            return wind_dir.text
    }
    println taglist
    //children()方法实现广度遍历
    //生成xml
    def sw=new StringWriter()
    def xmlBuilder=new MarkupBuilder(sw)//用来生成xml文件的核心类
    //根节点langs创建
    xmlBuilder.langs(type:'current',count:'3',mainstream:'true'){
        //第一个language节点
        language(flavor:'static',version:'1.5',value:'java'){
            age('24')
        }
        language(flavor:'dynamic',version:'1.5',value:'groovy'){
            age('16')
        }
        language(flavor:'dynamic',version:'1.5',value:'javaScript')
    }
    println sw
    //对象生成xml
    def langs=new Langs()
    xmlBuilder.langs(type:langs.type,count:langs.count,mainstream:langs.mainstream){
        langs.languages.each {lang->
            languge(flavor:lang.flavor,
            version:lang.version,lang.value)
        }
    }
    println sw
    class Langs{
        String type='current'
        int count =3
        boolean mainstream=true
        def languages=[new Language(flavor: 'static',version: '1.5',value: 'java'),
                       new Language(flavor: 'static',version: '17',value: '.c++'),
                       new Language(flavor: 'dynamic',version: '8.0',value: 'javaScript'),
                       new Language(flavor: 'dynamic',version: '3.5',value: 'python'),
                       new Language(flavor: 'dynamic',version: '2.4',value: 'groovy'),
        ]
    }
    class Language{
        String flavor
        String version
        String value
    }
    

    普通文件的读写,文件下载功能实现

    def file=new File('../HelloGroovy.iml')
    def text=file.getText()//获取文件内容
    //def result=file.readLines()
    println text
    //拷贝文件实现
    def result=copyFile("../HelloGroovy.iml",'../HelloGroovy2.text')
    println result
    def copyFile(String sourcePath,String destationPath){
        try{
            //创建目标文件
            def desFile=new File(destationPath)
            if(!desFile.exists()){
                desFile.createNewFile()
            }
            new File(sourcePath).withReader {reader->
                def lines=reader.readLines()
                desFile.withWriter {writer->
                    lines.each {line->
                        writer.append(line+'\r\n')
                    }
                }
            }
            return true
        }catch(Exception e){
            e.printStackTrace()
        }
    }
    def person=new Person(name: 'Cherry',age:19)
    //saveObject(person,"../person.bean")
    def objResult=readObject("../person.bean")
    println objResult
    //存储类到文件
    def saveObject(Object object,String path){
        try{
            //创建目标文件
            def desFile=new File(path)
            if(!desFile.exists()){
                desFile.createNewFile()
            }
            desFile.withObjectOutputStream {out->
                out.writeObject(object)
            }
            return true
        }catch(Exception e){
            e.printStackTrace()
        }
        return false
    }
    //在文件中读取类
    def readObject(String path){
        def obj=null
        try{
            def file=new File(path)
            if(file==null||!file.exists())return null
            //从文件中读取对象
            file.withObjectInputStream{input->
                obj=input.readObject()
            }
        }catch(Exception e){
    
        }
        return obj
    }
    
    groovy与java对比
    • 写法上:没有java那么多限制

    • 功能上:java中的类和方法都可以直接用,对java的功能扩展后,groovy实现功能更方便简洁

    • 作用上:既可以编写应用,也可以编写脚本

    Gradle概述

    gradle是什么,gradle能做什么

    • gradle不仅仅是构建工具,也可以看做是一种编程框架

      • gradle组成部分

        • groovy核心语法

        • build script block

        • gradle api

      • 优势

        • 更加灵活:Maven和ant不能自己修改构建过程,gradle可以写构建脚本

        • 粒度上:gradle开源,构建每一步都清晰可见,可修改

        • 扩展性:支持插件,可以复用插件

        • 兼容性:gradle吸取了所有构建工具的长处

      • gradle执行分三阶段

        • initialization初始化阶段:解析整个工程中的所有project,构建所有project对应的project对象

        • Configuration配置阶段:解析所有project对象中的task,构建好所有task的拓扑图

        • Execution执行阶段:执行具体的task及其依赖task

          /*Android gradle构建阶段监听*/
          /*首先在环境变量配置好gradle,具体百度*/
          /*在Terminal终端输入-gradlew clean测试*/
          /*在project下的build.gradle中添加如下代码*/
          /*配置阶段开始前的回调监听*/
          this.beforeEvaluate{
              println '开始'
          }
          /*配置阶段完成以后的回调监听*/
          this.afterEvaluate{
              println '完成'
          }
          /*gradle执行完毕后的回调监听*/
          this.gradle.buildFinished{
              println '结束'
          }
          /*在setting.gradle中输出*/
          println '初始化阶段开始'
          /*执行gradlew clean查看终端输出*/
          

    Gradle核心类之Project详解及实践

    projectAPI组成
    • gradle生命周期api

      /*配置阶段开始前的回调监听*/
      this.beforeEvaluate{
          println '开始'
      }
      /*配置阶段完成以后的回调监听*/
      this.afterEvaluate{
          println '完成'
      }
      /*gradle执行完毕后的回调监听*/
      this.gradle.buildFinished{
          println '结束'
      }
      /*project相关api*/
      this.getProjects()
      def getProjects(){
          println '--------------------'
          println 'Root project'
          println '--------------------'
          this.getAllprojects().eachWithIndex{Project project,int i->
              if(i==0){
                  println "Root project--- :${project.name}"
              }else {
                  println "+---*** project: ${project.name}"
              }
          }
      }
      
    • project相关api

      /*project api讲解*/
      project('app'){Project project->
      //    println project.name
          applay plugin:'com.android.application'
          dependencies {}
          android {}
      }
      /*配置当前工程和其所有子工程*/
      allprojects{
          group 'com.will'
          version '1.0.0=release'
      }
      /*配置所有子工程*/
      subprojects{ Project project->
          if(project.plugin.hasPlugin('com.android.library')){
              applay from:'../publishToMaven.gradle'//引入Maven配置文件
          }
      }
      
    • task相关api

    • 属性相关api

      /*自定义属性*/
      def mCompileSdkVersion =26
      def mLibAndroidSupportAppcompatV7 ='com.android.support:appcompat-v7:26.+'
      /*通用扩展属性,在根build中定义一次,所有子moudle都可以使用*/
          ext {
           compileSdkVersion =26
           libAndroidSupportAppcompatV7 ='com.android.support:appcompat-v7:26.+'
          }
       /*在moudel中使用*/
       android {
          compileSdkVersion this.rootProject.compileSdkVersion
          buildToolsVersion "26.0.3"
          ...
      }
      /*因为继承关系也可以直接调用*/
      dependencies { compile this.libAndroidSupportAppcompatV7
      }
      /**
      我们可以把所有属性通过扩展属性的方式定义到一个新的common.gradle中,在根gradle中通过
      apply from:this.file('common.gradle')来引用
      */
      ![5c846d0725918](https://i.loli.net/2019/03/10/5c846d0725918.png)
      //moudle中使用
      android{
          compileSdkVersion rootProject.ext.android.compileSdkVersion
      }
      //在gradle.properties中定义属性
      isLoadTest=false
      isLoadPullRefresh=true
      mCompileSdkVersion=26
      //使用,在setting.gradle
      include ':app'
      println '初始化阶段开始'
      if(hasProperty('isLoadPullRefresh')? isLoadPullRefresh.toBoolean():false){
          include  ':pullToRefresh'
      }
      //在moudel下gradle 
      compileSdkVersion mCompileSdkVersion.toInteger()
      
      • common.gradle

        5c846d0725918 5c846d0725918
    • file相关api

      • 路径获取相关api

        println "根目录路径"+getRootDir().absolutePath
        println "build下路径"+getBuildDir().absolutePath
        println "project的目录"+getProjectDir().absolutePath
        
      • 文件操作相关api

        /*gradle拷贝文件,可以拷贝整个目录*/
        copy {
            from file('app.iml')
            into getRootProject().getBuildDir()
            //此方法闭包过滤不想拷贝的文件
            exclude{}
        }
        //文件树遍历
        fileTree('build/outputs/apk/'){FileTree fileTree->
            fileTree.visit{FileTreeElement element->
                println 'the file name is:'+element.file.name
                copy {
                    from element.file
                    into getRootProject().getBuildDir().path+'/test/'
                }
            }
        }
        
    • 其它api

      
        //当有依赖包冲突时可以使用此命令去除冲突的部分 
        compile this.libAndroidSupportAppcompatV7{
              exclude module:'support-v4'
              //排除指定包下的所有库
              exclude group:'com.android.support'     
              transitive false//禁止传递依赖,是否使用引入的库的第三方依赖       
      
        }
      
      //compile 依赖打包时会把依赖的类和资源打包到apk,provided依赖编译时使用依赖资源,打包时不会打包依赖资源,provided会避免重复引用,尽量使用provided
      
      //使用外部命令
      task(name:'apkcopy'){
          doLast{
              //在gradle执行阶段去执行
              def sourcePath=this.buildDir.path+'outputs/apk'
              def desationPath='users/Andministrotor/Download/'
              def command="mv -f ${sourcePath} ${desationPath}"
              exec {
                  try{
                      executable 'bash'
                      args '-c', command
                      println 'the command is execute success'
                  }catch(Exception e){
                      println 'the command is execute failed'
                  }
              }
          }
      }
      //buildscript配置maven仓库
      buildscript { ScriptHandler scriptHandler->
          //配置我们的仓库地址
          scriptHandler.repositories { RepositoryIdHelper repositoryIdHelper->
              repositoryIdHelper.jcenter()
              mavenCentral()
              mavenLocal()
              //私有的maven仓库配置,可以配置多个
              maven {
                  name 'personal'
                  url 'http://localhost:8081:/nexus/repositories'
                  creadentials{
                      username ='admin'
                      password = 'admin123'
                  }
              }
          }
      
          //buildscript中的此方法配置我们工程的'插件'依赖地址
          dependencies {
              //此插件指定项目为Android项目
      //        classpath 'com.android.tools.build:gradle.2.2.2'
              classpath 'com.tencent.tinker-patch-gradle-plugin:1.7.7'//引入腾讯热修复框架
          }
      
      }
      

    Gradle核心之task详解及实践

    task定义及使用,task执行流程

    使用gradle task命令查看当前项目的task
    //创建task,配置组名和描述
    task helloTask(group:'will',description:'task study'){
        println 'i am helloTask'
        doFirst{//可以多次调用,在gradle的执行周期执行,原有的task之前执行
            println 'the task group is:'+group
        }
        doLast{}//原有的task之后执行
    
    }
    helloTask.doFirst{//外部调用先执行
        println 'the task description is'+description
    }
    //通过TaskContainer创建task
    this.tasks.create(name:'helloTask2'){
        //使用set设置组名
        setGroup('will')
        println 'i am helloTask2'
    }
    
    //计算build执行时长的功能
    def startBuildTime,endBuildTime
    this.afterEvaluate{Project project->
        //保证要找的task已经执行完毕
        def preBuildTask=project.tasks.getByName('preBuild')
        preBuildTask.doFirst {//在此task之前执行
            startBuildTime=System.currentTimeMillis()
            println 'the startTime is:'+startBuildTime
        }
        def buildTask=project.tasks.getByName('build')
        buildTask.doLast{
            endBuildTime=System.currentTimeMillis()
            println "the build time is:${endBuildTime-startBuildTime}"
        }
    }
    
    5c8498db9288c 5c8498db9288c

    task依赖关系与输入输出,task继承与实现

    task taskX {
        doLast {
            println 'taskX'
        }
    }
    task taskY {
        doLast {
            println 'taskY'
        }
    }
    task taskZ(dependsOn: [taskX,taskY]) {
        dependsOn  this .tasks.findAll{ task->
            return task.name.startsWith('lib')//动态指定依赖所有lib开头的
        }
        doLast {
            println 'taskZ'
        }
    }
    task lib1 <<{println 'lib1'}
    task lib2 <<{println 'lib2'}
    
    //task生成版本说明文件
    task handlerReleaseFile {
        def srcFile=file('releases.xml')
        def destDir=new File(this.buildDir,'generated/release/')
        doLast{
            println '开始解析对应的xml...'
            destDir.mkdir()
            def releases=new XmlParser().parse(srcFile)
            releases.release.each{ releaseNode->
                //解析每个release节点的内容
                def name=releaseNode.name.text()
                def versionCode=releaseNode.versionCode.text()
                def versionInfo=releaseNode.versionInfo.text()
                //创建文件并写入节点数据
                def destFile=new File(destDir,"release-${name}.text")
                destFile.withWriter{ writer->
                    writer.write("${name} -> ${versionCode} -> ${versionInfo}")
                }
            }
        }
    }
    task handlerReleaseFileTest(dependsOn:handlerReleaseFile){
        def dir =fileTree(this.buildDir.path+'generated/release/')
        doLast {
            dir.each {
                println 'the file name is:'+it
            }
            println '输出完成...'
        }
    }
    

    task修改默认构建流程,task源码解读

    通过脚本把构建版本信息写入xml,然后在把写入方法添加到构建过程中
    //生成版本信息xml和读取,在构建流程中加入添加版本信息到xml
    //实际开发中可以把一个独立的gradle功能代码写入单独的gradle文件,然后引入
    ext {
    
        versionName = '1.0.0'
    
        versionCode = '100'
    
        versionInfo = 'App的第一个版本,上线了一些最基础的核心功能'
    
        destFile = file('releases.xml')
    
        if (destFile != null && !destFile.exists()) {
    
            destFile.createNewFile()
    
        }
    
    }
    
    task writeTask {
    
        //为task指定输入
    
        inputs.property('versionCode', this.versionCode)
    
        inputs.property('versionName', this.versionName)
    
        inputs.property('versionInfo', this.versionInfo)
    
        //为task指定输出
    
        outputs.file destFile
    
        doLast {
    
            def data = inputs.getProperties()
    
            File file = outputs.getFiles().getSingleFile()
    
            def versionMsg = new VersionMsg(data)
    
            def sw = new StringWriter()
    
            def xmlBuilder = new MarkupBuilder(sw)
    
            if (file.text != null && file.text.size() <= 0) {
    
                xmlBuilder.release {
    
                    release {
    
                        versionCode(versionMsg.versionCode)
    
                        versionName(versionMsg.versionName)
    
                        versionInfo(versionMsg.versionInfo)
    
                    }
    
                }
    
                file.withWriter {writer->
    
                    writer.append(sw.toString())
    
                }
    
            }else{
    
                xmlBuilder.release {
    
                    versionCode(versionMsg.versionCode)
    
                    versionName(versionMsg.versionName)
    
                    versionInfo(versionMsg.versionInfo)
    
                }
    
                //将生成的数据插入到根节点之前
    
                def lines=file.readLines()
    
                def lengths=lines.size()-1
    
                file.withWriter {writer->
    
                    lines.eachWithIndex{ String line, int index ->
    
                        if(index!=lengths){
    
                            writer.append(line+'\r\n')
    
                        }else if(index==lengths){
    
                            writer.append('\r\r\n'+sw.toString() +'\r\n')
    
                            writer.append(lines.get(lengths))
    
                        }
    
                    }
    
                }
    
            }
    
        }
    
    }
    
    task readTask {
    
        inputs.file this.destFile
    
        doLast {
    
            def file=inputs.files.singleFile
    
            println file.text
    
        }
    
    }
    
    task taskTest {
    
        dependsOn readTask ,writeTask
    
    //    shouldRunAfter
    
    //    mustRunAfter
    
        doLast {
    
            println '输入输出任务结束'
    
        }
    
    }
    
    class VersionMsg {
    
        String versionCode
    
        String versionName
    
        String versionInfo
    
    }
    //在构建流程中加入添加版本信息到xml
    this.project.afterEvaluate {project->
    
        def buildTask=project.tasks.getByName("build")
    
        if(buildTask==null){
    
            throw GradleException('the build task is not found')
    
        }
    
        buildTask.doLast {
    
            writeTask.execute()//每次构建项目时把版本信息写入xml文件
    
        }
    
    }
    
    通过查看腾讯tinker源码我们可以知道它把自己的方法插入到gradle构建流程中,在processReleaseManifest之后,在processReleaseResource之前
    5c84d0cf851d0 5c84d0cf851d0
    为了自定义task方便,官方文档提供了很多不同类型的task
    5c84d143ce2a3 5c84d143ce2a3

    自动化实现工程插件更新功能

    Gradle核心之其它模块详解与实践

    第三方库依赖管理及gradle如何处理依赖原理详解

    工程初始化核心类Setting类作用及自定义

    • settings类在setting.gradle中体现其作用,通过include 引入子工程,并且可以通过自定义属性判断什么条件引入某个工程

    源码管理类SourceSet详解及实际工作中的妙用

    • sourceSet类按照约定来管理java中的类和资源,默认从java下获取源码,从res获取资源进行编译;其主要作用就是管理资源、源码、库;Android时通过AndroidSourceSet类管理,java通过javaSourceSet管理

    • sourceSet修改so库即jni默认目录

       sourceSets {
      
              main {
      
                  //修改默认so库jni目录到libs下
      
                  jniLibs.srcDirs=['libs']
      
              }
      
          }
      
    • SourceSet修改默认的资源文件路径为多路径,对资源进行分类

      5c84d787e1a8b 5c84d787e1a8b

    插件类plugin

    自定义plugin需要继承plugin类
    • 首先创建一个plugin工程,工程目录结构如下,代码在groovy中,引入配置路径在resources中

      5c85205e2b6ad 5c85205e2b6ad
      //plugin工程gradle文件
      apply plugin: 'groovy'
      
      sourceSets {
      
          main {
      
              groovy {
      
                  srcDir 'src/main/groovy'
      
              }
      
              resources {
      
                  srcDir 'src/main/resources'
      
              }
      
          }
      
      }
      
      //资源文件下配置引入路径代码
      implementation-class=com.will.gradle.study.GradleStudyPlugin
      //自定义插件groovy类,需要继承plugin类
      class GradleStudyPlugin implements Plugin {
      
          /**
      
           * 唯一需要实现的就是这个方法,参数就是引入了当前插件的Project对象
      
           * @param project
      
           */
      
          @Override
      
          void apply(Project project) {
      
              println '这里导入了自定义插件'
      
              //创建扩展属性
      
              project.extensions.create('imoocReleaseInfo',
      
                      ReleaseInfoExtension)
      
              //创建Task
      
              project.tasks.create('imoocReleaseInfoTask',
      
                      ReleaseInfoTask)
      
          }
      
      }
      //自定义ReleaseInfoExtension类,与自定义plugin进行参数传递
      class ReleaseInfoExtension {
      
          String versionCode
      
          String versionName
      
          String versionInfo
      
          String fileName
      
          ReleaseInfoExtension() {
      
          }
      
          @Override
      
          String toString() {
      
              """| versionCode = ${versionCode}
      
                 | versionName = ${versionName}
      
                 | versionInfo = ${versionInfo}
      
                 | fileName = ${fileName}
      
              """.stripMargin()
      
          }
      
      }
      //引入plugin
      apply plugin: 'com.will.gradle.study'
      //在app下gradle 中调用plugin定义的方法传递参数
      imoocReleaseInfo {
      
          versionCode = rootProject.ext.android.versionCode
      
          versionName = rootProject.ext.android.versionName
      
          versionInfo = '第八个版本。。。'
      
          fileName = 'releases.xml'
      
      }
      //在plugin中自定义task,在gradle执行过程中把版本信息写入xml
      package com.imooc.gradle.study
      
      import groovy.xml.MarkupBuilder
      
      import org.gradle.api.DefaultTask
      
      import org.gradle.api.tasks.TaskAction
      
      /**
      
       * 自定义Task,实现维护版本信息功能
      
       */
      
      class ReleaseInfoTask extends DefaultTask {
      
          ReleaseInfoTask() {
      
              group = 'imooc'
      
              description = 'update the release info'
      
          }
      
          /**
      
           * TaskAction注解的代码执行于gradle执行阶段的代码
      
           */
      
          @TaskAction
      
          void doAction() {
      
              updateInfo()
      
          }
      
          //真正的将Extension类中的信息呢,写入指定文件中
      
          private void updateInfo() {
      
              //获取将要写入的信息
      
              String versionCodeMsg = project.extensions.
      
                      imoocReleaseInfo.versionCode
      
              String versionNameMsg = project.extensions.
      
                      imoocReleaseInfo.versionName
      
              String versionInfoMsg = project.extensions.
      
                      imoocReleaseInfo.versionInfo
      
              String fileName = project.extensions.
      
                      imoocReleaseInfo.fileName
      
              def file = project.file(fileName)
      
              //将实体对象写入到xml文件中
      
              def sw = new StringWriter()
      
              def xmlBuilder = new MarkupBuilder(sw)
      
              if (file.text != null && file.text.size() <= 0) {
      
                  //没有内容
      
                  xmlBuilder.releases {
      
                      release {
      
                          versionCode(versionCodeMsg)
      
                          versionName(versionNameMsg)
      
                          versionInfo(versionInfoMsg)
      
                      }
      
                  }
      
                  //直接写入
      
                  file.withWriter { writer -> writer.append(sw.toString())
      
                  }
      
              } else {
      
                  //已有其它版本内容
      
                  xmlBuilder.release {
      
                      versionCode(versionCodeMsg)
      
                      versionName(versionNameMsg)
      
                      versionInfo(versionInfoMsg)
      
                  }
      
                  //插入到最后一行前面
      
                  def lines = file.readLines()
      
                  def lengths = lines.size() - 1
      
                  file.withWriter { writer ->
      
                      lines.eachWithIndex { line, index ->
      
                          if (index != lengths) {
      
                              writer.append(line + '\r\n')
      
                          } else if (index == lengths) {
      
                              writer.append('\r\r\n' + sw.toString() + '\r\n')
      
                              writer.append(lines.get(lengths))
      
                          }
      
                      }
      
                  }
      
              }
      
          }
      
      }
      

    Jenkins持续集成

    Jenkins持续集成步骤
    • 创建jenkins环境变量

    • 下载jenkins.war包

    • 执行java -jar jenkins.war,安装jenkins到环境变量指定的位置,期间会有密码输出

    • 输入localhost:8080 访问网页进入jenkins,输入密码配置jenkins

    相关文章

      网友评论

          本文标题:Android和java构建工具gradle语言深入了解与插件开

          本文链接:https://www.haomeiwen.com/subject/vmvguqtx.html