Java和Android构建工具Gradle深入了解

2024-08-30 17:18

本文主要是介绍Java和Android构建工具Gradle深入了解,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Gradle3.0编程与自动化构建

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

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

gradle相关概念介绍
  • 领域特定语言DSL介绍

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

      • 外部DSL

      • 内部DSL

      • 语言工作台

    • 优点

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

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

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

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

  • 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…)使用
gradle面向对象特性
  • groovy中类,接口等的定义和使用
//class Person implements Action{//实现接口
class Person implements DefaultAction{//实现Trait类String nameInteger agedef increaseAge(Integer years){this.name+=years}@Overridevoid eat() {}@Overridevoid drink() {}@Overridevoid 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 nameInteger agedef increaseAge(Integer years){this.name+=years}//一个方法找不到时调用它来代替,否则抛出MissingMethodExceptiondef 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.JsonSlurperdef 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.MarkupBuilderfinal String xml='''NOAA's National Weather Service
http://weather.gov/http://weather.gov/images/xml_logo.gif
NOAA's National Weather Service
http://weather.govNew York/John F. Kennedy Intl Airport, NY
KJFK
40.66
-73.78
Mon, 11 Feb 2008 06:51:00 -0500 ESTA Few Clouds
11
-12
36
West
280
18.4
29
1023.6
30.23
-11
-24
-7
-22
10.00http://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 =3boolean mainstream=truedef 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 flavorString versionString 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=nulltry{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.nameapplay 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 =26libAndroidSupportAppcompatV7 ='com.android.support:appcompat-v7:26.+'}/*在moudel中使用*/android {compileSdkVersion this.rootProject.compileSdkVersionbuildToolsVersion "26.0.3"...
    }
    /*因为继承关系也可以直接调用*/
    dependencies { compile this.libAndroidSupportAppcompatV7
    }
    /**
    我们可以把所有属性通过扩展属性的方式定义到一个新的common.gradle中,在根gradle中通过
    apply from:this.file('common.gradle')来引用
    */
    ![5c846d0725918](https://i-blog.csdnimg.cn/blog_migrate/58ea7fa9b7bdeda6a55a6f2039ec3aab.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

      5c846d07259185c846d0725918

  • 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.namecopy {from element.fileinto 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', commandprintln '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}"}
}

5c8498db9288c5c8498db9288c

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 destFiledoLast {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()-1file.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.destFiledoLast {def file=inputs.files.singleFileprintln file.text}
}
task taskTest {dependsOn readTask ,writeTask
//    shouldRunAfter
//    mustRunAfterdoLast {println '输入输出任务结束'}
}
class VersionMsg {String versionCodeString versionNameString 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之前

5c84d0cf851d05c84d0cf851d0

为了自定义task方便,官方文档提供了很多不同类型的task

5c84d143ce2a35c84d143ce2a3

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

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修改默认的资源文件路径为多路径,对资源进行分类

    5c84d787e1a8b5c84d787e1a8b

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

    5c85205e2b6ad5c85205e2b6ad

    //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*/@Overridevoid apply(Project project) {println '这里导入了自定义插件'//创建扩展属性project.extensions.create('imoocReleaseInfo',ReleaseInfoExtension)//创建Taskproject.tasks.create('imoocReleaseInfoTask',ReleaseInfoTask)}
    }
    //自定义ReleaseInfoExtension类,与自定义plugin进行参数传递
    class ReleaseInfoExtension {String versionCodeString versionNameString versionInfoString fileNameReleaseInfoExtension() {}@OverrideString 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.versionCodeversionName = rootProject.ext.android.versionNameversionInfo = '第八个版本。。。'fileName = 'releases.xml'
    }
    //在plugin中自定义task,在gradle执行过程中把版本信息写入xml
    package com.imooc.gradle.studyimport 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执行阶段的代码*/@TaskActionvoid doAction() {updateInfo()}//真正的将Extension类中的信息呢,写入指定文件中private void updateInfo() {//获取将要写入的信息String versionCodeMsg = project.extensions.imoocReleaseInfo.versionCodeString versionNameMsg = project.extensions.imoocReleaseInfo.versionNameString versionInfoMsg = project.extensions.imoocReleaseInfo.versionInfoString fileName = project.extensions.imoocReleaseInfo.fileNamedef 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() - 1file.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

这篇关于Java和Android构建工具Gradle深入了解的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1121442

相关文章

JVM 的类初始化机制

前言 当你在 Java 程序中new对象时,有没有考虑过 JVM 是如何把静态的字节码(byte code)转化为运行时对象的呢,这个问题看似简单,但清楚的同学相信也不会太多,这篇文章首先介绍 JVM 类初始化的机制,然后给出几个易出错的实例来分析,帮助大家更好理解这个知识点。 JVM 将字节码转化为运行时对象分为三个阶段,分别是:loading 、Linking、initialization

Spring Security 基于表达式的权限控制

前言 spring security 3.0已经可以使用spring el表达式来控制授权,允许在表达式中使用复杂的布尔逻辑来控制访问的权限。 常见的表达式 Spring Security可用表达式对象的基类是SecurityExpressionRoot。 表达式描述hasRole([role])用户拥有制定的角色时返回true (Spring security默认会带有ROLE_前缀),去

浅析Spring Security认证过程

类图 为了方便理解Spring Security认证流程,特意画了如下的类图,包含相关的核心认证类 概述 核心验证器 AuthenticationManager 该对象提供了认证方法的入口,接收一个Authentiaton对象作为参数; public interface AuthenticationManager {Authentication authenticate(Authenti

Spring Security--Architecture Overview

1 核心组件 这一节主要介绍一些在Spring Security中常见且核心的Java类,它们之间的依赖,构建起了整个框架。想要理解整个架构,最起码得对这些类眼熟。 1.1 SecurityContextHolder SecurityContextHolder用于存储安全上下文(security context)的信息。当前操作的用户是谁,该用户是否已经被认证,他拥有哪些角色权限…这些都被保

Spring Security基于数据库验证流程详解

Spring Security 校验流程图 相关解释说明(认真看哦) AbstractAuthenticationProcessingFilter 抽象类 /*** 调用 #requiresAuthentication(HttpServletRequest, HttpServletResponse) 决定是否需要进行验证操作。* 如果需要验证,则会调用 #attemptAuthentica

Spring Security 从入门到进阶系列教程

Spring Security 入门系列 《保护 Web 应用的安全》 《Spring-Security-入门(一):登录与退出》 《Spring-Security-入门(二):基于数据库验证》 《Spring-Security-入门(三):密码加密》 《Spring-Security-入门(四):自定义-Filter》 《Spring-Security-入门(五):在 Sprin

Java架构师知识体认识

源码分析 常用设计模式 Proxy代理模式Factory工厂模式Singleton单例模式Delegate委派模式Strategy策略模式Prototype原型模式Template模板模式 Spring5 beans 接口实例化代理Bean操作 Context Ioc容器设计原理及高级特性Aop设计原理Factorybean与Beanfactory Transaction 声明式事物

关于数据埋点,你需要了解这些基本知识

产品汪每天都在和数据打交道,你知道数据来自哪里吗? 移动app端内的用户行为数据大多来自埋点,了解一些埋点知识,能和数据分析师、技术侃大山,参与到前期的数据采集,更重要是让最终的埋点数据能为我所用,否则可怜巴巴等上几个月是常有的事。   埋点类型 根据埋点方式,可以区分为: 手动埋点半自动埋点全自动埋点 秉承“任何事物都有两面性”的道理:自动程度高的,能解决通用统计,便于统一化管理,但个性化定

【前端学习】AntV G6-08 深入图形与图形分组、自定义节点、节点动画(下)

【课程链接】 AntV G6:深入图形与图形分组、自定义节点、节点动画(下)_哔哩哔哩_bilibili 本章十吾老师讲解了一个复杂的自定义节点中,应该怎样去计算和绘制图形,如何给一个图形制作不间断的动画,以及在鼠标事件之后产生动画。(有点难,需要好好理解) <!DOCTYPE html><html><head><meta charset="UTF-8"><title>06

Java进阶13讲__第12讲_1/2

多线程、线程池 1.  线程概念 1.1  什么是线程 1.2  线程的好处 2.   创建线程的三种方式 注意事项 2.1  继承Thread类 2.1.1 认识  2.1.2  编码实现  package cn.hdc.oop10.Thread;import org.slf4j.Logger;import org.slf4j.LoggerFactory