Gradle的基本使用

Stella981
• 阅读 968

Gradle的介绍

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

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

Gradle入门知识

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

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

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

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

$gradle hello -q
Hello world!
  • 1

  • 2

  • 1

  • 2

Android Studio的结构

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

├── 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 
module

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-19、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)里面

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 
Gradle的基本使用  
第二种方式使用命令。打开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的可能会遇到内

Gradle的基本使用 源码地址

部分内容来源1 部分内容来源2

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
待兔 待兔
3个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Jacquelyn38 Jacquelyn38
3年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
Wesley13 Wesley13
3年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Wesley13 Wesley13
3年前
Java日期时间API系列36
  十二时辰,古代劳动人民把一昼夜划分成十二个时段,每一个时段叫一个时辰。二十四小时和十二时辰对照表:时辰时间24时制子时深夜11:00凌晨01:0023:0001:00丑时上午01:00上午03:0001:0003:00寅时上午03:00上午0
Wesley13 Wesley13
3年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Stella981 Stella981
3年前
Django中Admin中的一些参数配置
设置在列表中显示的字段,id为django模型默认的主键list_display('id','name','sex','profession','email','qq','phone','status','create_time')设置在列表可编辑字段list_editable
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
9个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这