Gradle的基本使用

Gradle的介绍

Gradle是一个基于Apache Ant和Apache Maven概念的项目自动化建构工具。它使用一种基于Groovy的特定领域语言(DSL)来声明项目设置,抛弃了基于XML的各类繁琐配置。html

面向Java应用为主。当前其支持的语言限于Java、Groovy和Scala,计划将来将支持更多的语言。java

Gradle入门知识

projects 和 tasks是Gradle中最重要的两个概念,任何一个Gradle构建都是由一个或者多个project组成,每一个project能够是一个jar包,一个web应用,或者一个Android app等,每一个project又由多个task构成,一个task其实就是构建过程当中一个原子性的操做,好比编译、拷贝等。linux

一个build.gradle文件是一个构建脚本,当运行gradle命令的时候会从当前目录查找build.gradle文件来执行构建。下面咱们来看下gradle的Hello World。在build.gradle构建文件中输入如下构建脚本:android

task hello {
    doLast {
        println 'Hello world!'
    }
}
  •  

task定义了一个任务,这个任务名字是hello。doLast是Task的方法,意思是在该hello任务执行以后做的事情,能够用一个闭包配置它,这里是输出Hello world!字符串。咱们在终端里执行以下命令运行查看结果:git

$gradle hello -q
Hello world!
  • 1
  • 2
  • 1
  • 2

Android Studio的结构

这里新建一个android项目,选择Project结构模式,下面是项目的结构示意图web

├── ApplicationName #项目路径
│   ├── .gradle
│   ├── .idea
│   ├── app #Android App目录
│   │   ├── build #构建输出目录
│   │   ├── libs#so相关库
│   │   ├── src #源代码,资源等
│   │   └── .gitignore  
│   │   └── app.im
│   │   └── buidle.gradle#构建脚本
│   │   └── proguard-rules.pro#proguard混淆配置
│   ├── build
│   │   ├── intermediates
│   ├── gradle  
│   │   ├── wrapper
│   └── .gitignore  
│   └── buidle.gradle #工程构建文件
│   └── gradle.properties#gradle的配置
│   └── gradlew #gradle wrapper linux shell脚本
│   └── gradlew.bat
│   └── local.properties #配置Androod SDK位置文件
│   └── MyApplication.iml
│   └── settings.gradle #工程配置
├── External Liraies#类库、jar等

settings.gradle用于配置project,标明其下有几个module,好比这里p一个:ape 
moduleshell

include ':app'
  • 1
  • 1

build.gradle(Project:projectName)是一个顶级的build配置文件,在这里能够为全部project以及module配置一些经常使用的配置。服务器

// Top-level build file where you can add configuration options common to all sub-projects/modules.

buildscript {
    repositories {
    //使用jcenter库
        jcenter()
    }
    dependencies {   
        // 依赖android提供的1.3.0的gradle build
        classpath 'com.android.tools.build:gradle:1.3.0'

        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }
}
//为全部的工程的repositories配置为jcenter
allprojects {
    repositories {
        jcenter()
    }
}
task clean(type: Delete) {
    delete rootProject.buildDir
}
  •  

build.gradle(Module:moduleName)用于module的配置,也是最重要的部分闭包

apply plugin: 'com.android.application'

android {
    compileSdkVersion 23
    buildToolsVersion "23.0.2"

    defaultConfig {
        applicationId "com.example.zqw.myapplication"
        minSdkVersion 15
        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.0'
    compile 'com.android.support:design:23.1.0'
}
  • 1
  • apply plugin: ‘com.android.application’:表示该module是一个app module,应用了com.android.application插件,若是是一个android library,那么这里的是apply plugin: ‘com.android.library’。
  • compileSdkVersion :是你SDK的版本号,也就是API Level,例如API-1九、API-20、API-21等等
  • buildToolsVersion “23.0.2”:是你构建工具的版本,其中包括了打包工具aapt、dx等等。这个工具的目录位于..your_sdk_path/build-tools/XX.XX.XX这个版本号通常是API-LEVEL.0.0。 例如I/O2014大会上发布了API20对应的build-tool的版本就是20.0.0在这之间可能有小版本,例如20.0.1等等。
  • defaultConfig:是默认配置,若是没有其余的配置覆盖,就会使用这里的。看其属性的名字就能够知道其做用,好比applicationId是配置包名的,versionCode是版本号,versionName是版本名称等。
  • buildTypes是构建类型,经常使用的有release和debug两种,能够在这里面启用混淆,启用zipAlign以及配置签名信息等。
  • dependencies不属于Android专有的配置了,它定义了该module须要依赖的jar,aar,jcenter库信息。

Gradle配置签名

Gradle 配置应用的签名信息

这些配置放在上面提到的build.gradle(Module:moduleName)里面app

signingConfigs {//签名配置这里配置了release 对应的还能够有debug
    release {
        storeFile file("keystore.jks")//这个文件须要放在modele所在根目录下
        keyAlias "testapp"
        keyPassword "111111"
        storePassword "111111"
    }
}
buildTypes {
    release {
        signingConfig  signingConfigs.release//不要忘了要在release的时候加入我么的签名配置信息
        minifyEnabled false
        proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
    }
}

使用Gradle签名

第一种方式是使用Gradle工具,双击下图选择的命令便可,在控制台看到BUILD SUCCESSFUL就代表签名成功了,由于咱们没有配置文件的生成路径因此会在默认地址里面C:\project\demo\MyApplication\app\build\outputs\apk 
这里写图片描述 
第二种方式使用命令。打开Terminal选项卡,用最下方标签切换。打开以后咱们先敲一下gradle –help命令验证一下是否能够执行gradle命令。若是不能够的话,在环境变量里边配置一下gradle的path。

gradle assembleRelease

Gradle配置proguard混淆

咱们能够为不一样的buildTypes选择是否启用混淆,通常release发布版本是须要启用混淆的,这样别人反编译以后就很难分析你的代码,而咱们本身开发调试的时候是不须要混淆的,因此debug不启用混淆。对release启用混淆的配置以下:

android {

    buildTypes {
        release {
            minifyEnabled true
            proguardFile 'proguard.cfg'
        }
   }
}
  •  

minifyEnabled为true表示启用混淆,proguardFile是混淆使用的配置文件,这里是module根目录下的proguard.cfg文件

在上面咱们配置签名信息采用的是默认写法。下面是对默认写法的解释 
proguard-android.txt是sdk中groguard默认的文件,具体地址在:/opt/sdk/tools/proguard/proguard-android.txt 
proguard-rules.pro是AS中专用的proguard配置文件,其实只是后缀名不一样,与Eclipse中的proguard-project.txt是同样的,配置规则相同 
老版本开启混淆的命令是runProguard,如今统一用minifyEnabled命令了,将其设为true就行了。

Gradle启用zipAlign

zipalign是Android SDK中包含一个的工具,它可以对打包的应用程序进行优化。在你的应用程序上运行zipalign,使得在运行时Android与应用程序间的交互更加有效率。所以,这种方式可以让应用程序和整个系统运行得更快。强烈推荐在新的和已经发布的程序上使用zipalign工具来获得优化后的版本——即便你的程序是在老版本的Android平台下开发的。

在Android中,每一个应用程序中储存的数据文件都会被多个进程访问:安装程序会读取应用程序的manifest文件来处理与之相关的权限问题;Home应用程序会读取资源文件来获取应用程序的名和图标;系统服务会由于不少种缘由读取资源(例如,显示应用程序的Notification);此外,就是应用程序自身用到资源文件。

在Android中,当资源文件经过内存映射对齐到4字节边界时,访问资源文件的代码才是有效率的。可是,若是资源自己没有进行对齐处理(未使用zipalign工具),它就必须回到老路上,显式地读取它们——这个过程将会比较缓慢且会花费额外的内存。

对于应用程序开发者来讲,这种显式读取方式是至关便利的。它容许使用一些不一样的开发方法,包括正常流程中不包含对齐的资源,所以,这种读取方式具备很大的便利性(本段的原始意思请参考原文)。

遗憾的是,对于用户来讲,这个状况偏偏是相反的——从未对齐的apk中读取资源比较慢且花费较多内存。最好的状况是,Home程序和未对齐的程序启动得比对齐后的慢(这也是惟一可见的效果)。最坏的状况是,安装一些未对齐资源的应用程序会增长内存压力,并所以形成系统反复地启动和杀死进程。最终,用户放弃使用如此慢又耗电的设备。

开启zipAlign配置以下

android {

    buildTypes {
        release {
            zipAlignEnabled true
        }
   }
}
  •  

Gradle删除无用资源

在项目屡次版本迭代后有一部分资源文件可能不在使用了,若是之前负责的人离开或者不在负责这个了,那么后面接收的人就不敢删除,这样安装包就会愈来愈大,之前使用工具能够找到没被使用的资源。如今android gradle也直接支持,配置以下

android {

    buildTypes {
        release {
          shrinkResources true 
        }
   }
}
  •  

多渠道打包

多渠道这个也是android平台特有的,由于有360手机助手、应用宝、小米应用市场等等大量相似AppStore的应用商城。在项目发布之后须要对后台数据分渠道统计,因此才有了多渠道打包。Android Gradle给咱们提供了productFlavors,让咱们能够对生成的APK包进行定制

android  {
    productFlavors {
        dev{

        }
        google{

        }
        baidu{

        }
    }
}
  •  

这样当咱们运行assembleRelease的时候就会生成3个release包,分别是dev、google以及baidu的。目前看这三个包除了文件名没有什么不同,由于咱们尚未定制,使用的都是defaultConfig配置。这里的flavor和defaultConfig是同样的,能够自定义其applicationId、versionCode以及versionName等信息,好比区分不一样包名:注意实际发布项目APP的报名应该是惟一的,这里这是为了说明能够改

android  {
    productFlavors {
        dev{
            applicationId "org.flysnow.demo.dev"
        }
        google{
            applicationId "org.flysnow.demo.google"
        }
        baidu{
            applicationId "org.flysnow.demo.baidu"
        }
    }
}
  • 批量修改生成的apk文件名

在咱们打包发版的时候,一次性打几十个包,这时候咱们就想让生成的apk文件名有区分,好比一眼就能看出这个apk是哪一个版本的,哪一个渠道的,是哪天打的包等等,这就须要咱们在生成apk文件的时候动态修改生成的apk文件名达到这一目的。

def buildTime() {
    def date = new Date()
    def formattedDate = date.format('yyyyMMdd')
    return formattedDate
}

android {
    buildTypes {
        release {
            applicationVariants.all { variant ->
                variant.outputs.each { output ->
                    if (output.outputFile != null && output.outputFile.name.endsWith('.apk')
                        &&'release'.equals(variant.buildType.name)) {
                        def apkFile = new File(
                                output.outputFile.getParent(),
                                "testapp_${variant.flavorName}_v${variant.versionName}_${buildTime()}.apk")
                        output.outputFile = apkFile
                    }
                }
            }
        }
    }
}
  •  

以baidu渠道为例,以上的代码会生成一个名字为testapp_baidu_v9.5.2.6_20150330.apk安装包。下面咱们分析一下,Android Gradle任务比较复杂,它的不少任务都是自动生成的,为了能够更灵活的控制,Android Gradle提供了applicationVariants、libraryVariants以及testVariants,他们分别适用于app、library、app和library都适用。

这里是循环处理每一个applicationVariant,当他们的输出文件名以apk结尾而且buildType是release时,从新设置新的输出文件名,这样就达到了咱们批量修改生成的文件名的目的。

Gradle使用AndroidManifest里的占位符

这里用到的占位符也是让动态打包的APK包内配置信息和渠道对于,用于第三方的统计分析,以友盟统计为例

<meta-data android:value="${UMENG_CHANNEL_VALUE}" android:name="UMENG_CHANNEL"/>
  • 1
  • 1

若是是单一渠道咱们能够直接给value赋值好比value=“baidu”,这样在项目代码中去获取UMENG_CHANNEL值就知道是哪个渠道了,由于打的渠道包很是的多因此咱们能够采用上面占位符方式 
下面是gradle的配置

android {
    defaultConfig {
        manifestPlaceholders = [UMENG_CHANNEL_VALUE: 'dev']
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5

咱们的默认配置里AndroidManifest的${UMENG_CHANNEL_VALUE}占位符会被dev这个字符串所替换,也就说默认运行的版本是一个开发板。以此类推,咱们其余渠道的版本就能够这样定义:

android  {
    productFlavors {
        google{
            applicationId "org.flysnow.demo.google"
            manifestPlaceholders.put("UMENG_CHANNEL_VALUE",'google')
        }
        baidu{
            applicationId "org.flysnow.demo.baidu"
            manifestPlaceholders.put("UMENG_CHANNEL_VALUE",'baidu')
        }
    }
}
  •  

这样写依然过于繁琐,咱们能够直接用渠道名称来给这个占位符赋值

productFlavors.all { flavor ->
        manifestPlaceholders.put("UMENG_CHANNEL_VALUE",name)
    }
  •  

自定义你的BuildConfig

在咱们实际项目开发中通常会有测试环境和正式环境的区分(和服务器有交互的APP),通常咱们会写一个配置文件,根据不一样状况来访问不一样的环境。之前的时候咱们经过把不一样的配置文件打包进APK中来控制,Android Gradle能够动态生成BuildConfig.java,咱们只须要填写信息便可,使用起来更加方便。

android {
    defaultConfig {
        buildConfigField 'String','API_SERVER_URL','"http://www.myweb.com/"'
    }
    productFlavors {
        google{
            buildConfigField 'String','API_SERVER_URL','"http://www.google.com/"'
        }
        baidu{
            buildConfigField 'String','API_SERVER_URL','"http://www.baidu.com/"'
        }
    }
}
  •  

buildConfigField 一共有3个参数,第一个是数据类型,就是你定义的常量值是一个什么类型,和Java的类型是对等的,这里是String。第二个参数是常量名,这里是API_SERVER_URL。第三个参数是常量值。如此定义以后,就会在BuildConfig.java中生成一个常量名为API_SERVER_URL的常量定义。默认配置的生成是:

public final static String API_SERVER_URL = "http://www.myweb.com/"

当是baidu和google渠道的时候生成的就是http://www.myweb.com/了。这个常量能够在咱们编码中引用。在咱们进行打包的时候会根据Gradle配置动态替换。

咱们发现通常渠道版本都是用来发布的,确定用的是生产服务器,因此咱们可使用批处理来搞定这个事情,而不用在一个个渠道里写这些配置。

productFlavors.all { flavor ->
    buildConfigField 'String','API_SERVER_URL','"http://www.flysnow.org/"'
}

此外,好比Gradle的resValue,也是和buildConfigField,只不过它控制生成的是资源,好比咱们在android的values.xml定义生成的字符串。能够用它来动态生成咱们想要的字符串,好比应用的名字,可能一些渠道会不同,这样就能够很灵活的控制自动生成,关于resValue详细介绍请参考相关文档,这里再也不举例说明。

插装测试覆盖率代码

dexOptions javaMaxHeapSize

在Gradle 进行dex的可能会遇到内

源码地址

部份内容来源1 部份内容来源2

相关文章
相关标签/搜索