gradle打包简介

来源:互联网 发布:淘宝店铺一颗心 编辑:程序博客网 时间:2024/06/01 07:42

一、gradle特点

ANT是最早的构建工具,基于idea,好象是2000年有的,当时是最流行java构建工具,不过它的XML脚本编写格式让XML文件特别大。对工程构建过程中的过程控制特别好。
Maven它是用来给Ant补坑的,Maven第一次支持了从网络上下载的功能,仍然采用xml作为配置文件格式,它的问题是不能很好的相同库文件的版本冲突。Maven专注的是依赖管理,构建神马的并不擅长。
Gradle属于结合以上两个的优点,它继承了Ant的灵活和Maven的生命周期管理,它实际上是Maven+Ant的一套更加用户友好的界面。不考虑IDE辅助的情况下,基于Groovy的DSL相比XML配置文件可以少写不少代码。此外因为是基于Groovy的DSL,可以更细致地控制编译过程。比如,Ant要做if-else条件选择特别麻烦,换做gradle的话可以直接套用java的编程风格 if(){}else{}。
总之,gralde 简单,高效,灵活

二、gradle 配置

(app/build.gradle)

apply plugin: 'com.android.application'android {    compileSdkVersion 23    buildToolsVersion "23.0.2"    defaultConfig {        applicationId "gradlecomple.ndh.com.gradlecomplie"        minSdkVersion 9        targetSdkVersion 23        versionCode 1        versionName "1.0"    }    buildTypes {        release {            minifyEnabled false            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'        }    }}dependencies {    compile fileTree(dir: 'libs', include: ['*.jar'])    testCompile 'junit:junit:4.12'    compile 'com.android.support:appcompat-v7:23.1.1'}

我们都知道一个app工程下build.gradle第一句:apply plugin: ‘com.android.application’ 表示我们需要使用该插件的一些功能。弱弱问一句:
1、你怎么知道这里引用的插件是com.android.application?
2、android 下的各种配置是什么意思?
3、android下还有些什么配置?
一开始我也是一头雾水,完全搞不明白,需要用什么功能网上一顿乱搜,完全使用别人的经验,直到我访问了以下网址:
http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Build-Tasks

页面上有一句让你链接到android gradle 详细的DSL(domain specific language/领域专用语言)

Please see the [Android Plugin DSL Reference](http://google.github.io/android-gradle-dsl/current/) for a complete list of build properties that can be configured and their default values.

进入到页面你会看到:
这里写图片描述
这里就告诉你android用的有三种插件。
点开AppExtension瞧瞧:
这里写图片描述
这些就是android下可以配置的属性。
比如说你想看defaultConfig里面还有些什么配置:
点击defalutConfig一项:
这里写图片描述
再次点开ProductFlavor:
这里写图片描述
看看这些是不是你想要的?

三、gradle打包
需求:打包一个sdk(带布局文件),并将jar包命名为mylib.jar,并将生成的文件拷贝到app工程
步骤分析:
1 打包资源文件生成R.java文件
2 依赖生成的R.java 打包java源码
3 拷贝资源文件和jar包到app工程
打包资源文件使用aapt命令,然而我没有找到对应的taskType,因此只好使用命令行方式。

1.1打资源包
(mylibrary/build.gradle)

#定义一个变量baseDir,表示当前目录def basedir = rootDir.getAbsolutePath()#定义编译资源的tasktask compileRes() {    doLast {    #这里表示 执行命令行        exec {            commandLine gradle.aapt,                    'package',                    '-f',                    '-m',                    '-J',                    "${basedir}/mylibrary/gen",                    '-M',                    "${basedir}/mylibrary/src/main/AndroidManifest.xml",                    '-S',                    "${basedir}/mylibrary/src/main/res",                    '-A',                    "${basedir}/mylibrary/src/main/assets",                    '-I',                    gradle.home,                    '-F',                    "${basedir}/mylibrary/gen/${resName}"        }    }}

ps:taskType简介
gadle脚本中可执行的东西叫task ,gradle定义了一系列的task类型-taskType。其文档在这:https://docs.gradle.org/current/dsl/index.html#N10335
打开后可以看到:

这里写图片描述

1.2 编译class
java编译class刚好gradle有提供任务类型 JavaCompile:https://docs.gradle.org/current/dsl/org.gradle.api.tasks.compile.JavaCompile.html:
其相关可配置属性如下:
这里写图片描述
具体编译任务如下:
(mylibrary/build.gradle)

task compileLib(type: JavaCompile, dependsOn: 'compileRes') {//保证build_new一定存在,因为生成的class文件需要放到该目录下    doFirst {        def file = new File("${basedir}/mylibrary/build_new")        if (!file.exists()) {            file.mkdir()        }    }    //配置java代码    source "${basedir}/mylibrary/src/main/java"    //配置工程引用的R.java文件(R.java文件由任务compileRes生成到gen目录下)    source "${basedir}/mylibrary/gen/hotfix"    //设置编译好的class文件存放目录    destinationDir = new File("${basedir}/mylibrary/build_new")    //这里用到的gradle.home 配置到local.property里,具体如何引用请看下面介绍 3.2    FileCollection fc = files(new File(gradle.home))    //设置classpath(包括所有依赖jar)    classpath = fc}

1.3打jar包
通过寻找,我们看到gradle自带有jar任务类型https://docs.gradle.org/current/dsl/org.gradle.api.tasks.bundling.Jar.html:
这里写图片描述
baseName:表示 将生成的jar重命名
encoding:表示使用的编码规则
另外在文档下方方法区里有这么一个方法:
这里写图片描述
这里配置当前Jar任务类型需要的sourcePaths
具体任务如下:
(mylibrary/build.gradle)

task compileJar(type: Jar, dependsOn: 'compileLib') {    baseName = "${jarName}"    encoding = "utf-8"    from "${basedir}/mylibrary/build_new"//    into "${basedir}/mylibrary/out"}执行完该任务会在build/libs下生成一个mylib.jar(系统默认是classes.jar,因为上边配置的baseName的原因更改了默认文件名)

1.4 拷贝编译的资源文件,jar包到app目录
(mylibrary/build.gradle)

//拷贝jar包到app/libstask copyLibFile(type: Copy, dependsOn: 'compileJar') { copyFile("${basedir}/mylibrary/build/libs/${jarName}.jar", "${basedir}/app/libs")}//拷贝aapt打包的资源到app工程assets目录task copyResFile(type: Copy, dependsOn: 'copyLibFile') {//这里copyFile为定义在util.gradle的函数,目的就为了代码复用,外部gradle的引用请看下文TODO    copyFile("${basedir}/mylibrary/gen/${resName}", "${basedir}/app/src/main/assets")}

三、gradle 扩展
3.1 gradle任务的两种写法

task ma( description="开始打包",group="MA",dependsOn: 'mb'){doLast{printlnx "this is task ma"}}task mb(){    printlnx "this is task mb"}以上也可写成这样://<< 表示doLasttask ma<<{    printlnx "this is task ma"}//可以单独为ma配置属性,(很类似js的对象属性配置)ma{    dependsOn "mb"//依赖mb任务    description="开始打包"//任务描述    group="MA"//为当前ma任务分组}task mb(){    printlnx "this is task mb"}但请注意 以下写发错误:task ma(description="开始打包",group="MA",dependsOn: 'mb')<<{printlnx "this is task ma"}也就是<< 前面不能带()

3.2 gradle获取配置文件属性
上文有一个属性为 gradle.home,这个home属性其实是定义在根目录下local.properties里:
这里写图片描述
解析该属性在((mylibrary/setting.gradle):

    //通过gradle.ext 将sdk.api属性导出为api     gradle.ext.api = properties.getProperty('sdk.api')    gradle.ext.aapt=properties.getProperty('sdk.aapt')    gradle.ext.home=properties.getProperty('sdk.home')    gradle.ext.jar=properties.getProperty('jar')

在mylibrary/build.gradle中想使用这些属性先引用setting.gradle文件:

apply from: rootProject.getRootDir().getAbsolutePath() + "/mylibrary/settings.gradle"

然后直接通过gradle.api(这里不再是gradle.ext.api)就可以获取到local.properties配置的属性

3.3 引用外部gradle方法
在build.gradle中我只想做和打包相关的逻辑,其他辅助逻辑(比如文件拷贝)我想抽取到外部,一方面使各个gradle文件逻辑干净整洁,一方面也可以代码复用。上面提到mylibrary/build.gradle引用到了mylibrary/utils.gradle中的copyFile方法
copyFile在utils.gradle中定义如下:

def copyFile(srcPath, desPath) {    def File src = file(srcPath)    def File des = file(desPath)    //文件拷贝到文件夹    if (src.isFile() && des.isDirectory()) {        def des1 = file(des.absolutePath + "/" + src.getName())        des1.createNewFile()        des1.withOutputStream {            os ->                src.withInputStream {                    is -> os << is                }        }    } }//通过ext将当前文件的copyFile函数导出为copyFile函数供外部使用ext {    copyFile = this.&copyFile}解释一下这段代码//将文件流写入到des1中des1.withOutputStream {//这里是第一个闭包//1      os ->       src.withInputStream {//这里是第二个闭包       //2          is -> os << is                          }                    }这段通过goovy编写,闭包是groovy中一个特别重要的概念,也是gradle构建中的基础。  闭包中的->左边表示参数,箭头右边是使用到该参数的函数因此上边第一处箭头-> 左边的os表示第一个闭包的参数,对该参数的操作则是在第二个闭包中进行。在第二个闭包中箭头->is是其参数,对is的操作,是在函数 os<<is中进行,这里的<<为groovy中的语法 表示流的读写(将<<右边的is 读取到左边的os中,groovy中读写就是真么叼)

在build.gradle中使用copyFile先引用utils.gradle

apply from: rootProject.getRootDir().getAbsolutePath() + "/mylibrary/utils.gradle"

然后像调用本文件方法一样使用copyFile

task copyLibFile(type: Copy, dependsOn: 'compileJar') { copyFile("${basedir}/mylibrary/build/libs/${jarName}.jar", "${basedir}/app/libs")}

示例代码下载:https://github.com/killer8000/GradleSample

0 0
原创粉丝点击