gradle打包简介

一、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()
#定义编译资源的task
task 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/libs
task 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"
}
以上也可写成这样:
//<< 表示doLast
task 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
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值