Gradle的基本使用

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构建文件中输入以下构建脚本:

1task hello { 2 doLast { 3 println 'Hello world!' 4 } 5}

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

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

  • 2

  • 1

  • 2

Android Studio的结构

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

1├── ApplicationName #项目路径 2│ ├── .gradle 3│ ├── .idea 4│ ├── app #Android App目录 5│ │ ├── build #构建输出目录 6│ │ ├── libs#so相关库 7│ │ ├── src #源代码,资源等 8│ │ └── .gitignore 9│ │ └── app.im 10│ │ └── buidle.gradle#构建脚本 11│ │ └── proguard-rules.pro#proguard混淆配置 12│ ├── build 13│ │ ├── intermediates 14│ ├── gradle 15│ │ ├── wrapper 16│ └── .gitignore 17│ └── buidle.gradle #工程构建文件 18│ └── gradle.properties#gradle的配置 19│ └── gradlew #gradle wrapper linux shell脚本 20│ └── gradlew.bat 21│ └── local.properties #配置Androod SDK位置文件 22│ └── MyApplication.iml 23│ └── settings.gradle #工程配置 24├── External Liraies#类库、jar等

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

include ':app'
  • 1

  • 1

build.gradle(Project:projectName)是一个顶级的build配置文件,在这里可以为所有project以及module配置一些常用的配置。

1// Top-level build file where you can add configuration options common to all sub-projects/modules. 2 3buildscript { 4 repositories { 5 //使用jcenter库 6 jcenter() 7 } 8 dependencies { 9 // 依赖android提供的1.3.0的gradle build 10 classpath 'com.android.tools.build:gradle:1.3.0' 11 12 // NOTE: Do not place your application dependencies here; they belong 13 // in the individual module build.gradle files 14 } 15} 16//为所有的工程的repositories配置为jcenter 17allprojects { 18 repositories { 19 jcenter() 20 } 21} 22task clean(type: Delete) { 23 delete rootProject.buildDir 24}

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

1apply plugin: 'com.android.application' 2 3android { 4 compileSdkVersion 23 5 buildToolsVersion "23.0.2" 6 7 defaultConfig { 8 applicationId "com.example.zqw.myapplication" 9 minSdkVersion 15 10 targetSdkVersion 23 11 versionCode 1 12 versionName "1.0" 13 } 14 buildTypes { 15 release { 16 minifyEnabled false 17 proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 18 } 19 } 20} 21 22dependencies { 23 compile fileTree(dir: 'libs', include: ['*.jar']) 24 testCompile 'junit:junit:4.12' 25 compile 'com.android.support:appcompat-v7:23.1.0' 26 compile 'com.android.support:design:23.1.0' 27}
  • 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)里面

1signingConfigs {//签名配置这里配置了release 对应的还可以有debug 2 release { 3 storeFile file("keystore.jks")//这个文件需要放在modele所在根目录下 4 keyAlias "testapp" 5 keyPassword "111111" 6 storePassword "111111" 7 } 8} 9buildTypes { 10 release { 11 signingConfig signingConfigs.release//不要忘了要在release的时候加入我么的签名配置信息 12 minifyEnabled false 13 proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 14 } 15}

使用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启用混淆的配置如下:

1android { 2 3 buildTypes { 4 release { 5 minifyEnabled true 6 proguardFile 'proguard.cfg' 7 } 8 } 9}

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配置如下

1android { 2 3 buildTypes { 4 release { 5 zipAlignEnabled true 6 } 7 } 8}

Gradle删除无用资源

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

1android { 2 3 buildTypes { 4 release { 5 shrinkResources true 6 } 7 } 8}

多渠道打包

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

1android { 2 productFlavors { 3 dev{ 4 5 } 6 google{ 7 8 } 9 baidu{ 10 11 } 12 } 13}

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

1android { 2 productFlavors { 3 dev{ 4 applicationId "org.flysnow.demo.dev" 5 } 6 google{ 7 applicationId "org.flysnow.demo.google" 8 } 9 baidu{ 10 applicationId "org.flysnow.demo.baidu" 11 } 12 } 13}
  • 批量修改生成的apk文件名

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

1def buildTime() { 2 def date = new Date() 3 def formattedDate = date.format('yyyyMMdd') 4 return formattedDate 5} 6 7android { 8 buildTypes { 9 release { 10 applicationVariants.all { variant -> 11 variant.outputs.each { output -> 12 if (output.outputFile != null && output.outputFile.name.endsWith('.apk') 13 &&'release'.equals(variant.buildType.name)) { 14 def apkFile = new File( 15 output.outputFile.getParent(), 16 "testapp_${variant.flavorName}_v${variant.versionName}_${buildTime()}.apk") 17 output.outputFile = apkFile 18 } 19 } 20 } 21 } 22 } 23}

以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的配置

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

  • 2

  • 3

  • 4

  • 5

  • 1

  • 2

  • 3

  • 4

  • 5

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

1android { 2 productFlavors { 3 google{ 4 applicationId "org.flysnow.demo.google" 5 manifestPlaceholders.put("UMENG_CHANNEL_VALUE",'google') 6 } 7 baidu{ 8 applicationId "org.flysnow.demo.baidu" 9 manifestPlaceholders.put("UMENG_CHANNEL_VALUE",'baidu') 10 } 11 } 12}

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

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

自定义你的BuildConfig

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

1android { 2 defaultConfig { 3 buildConfigField 'String','API_SERVER_URL','"http://www.myweb.com/"' 4 } 5 productFlavors { 6 google{ 7 buildConfigField 'String','API_SERVER_URL','"http://www.google.com/"' 8 } 9 baidu{ 10 buildConfigField 'String','API_SERVER_URL','"http://www.baidu.com/"' 11 } 12 } 13}

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配置动态替换。

我们发现一般渠道版本都是用来发布的,肯定用的是生产服务器,所以我们可以使用批处理来搞定这个事情,而不用在一个个渠道里写这些配置。

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

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

插装测试覆盖率代码

dexOptions javaMaxHeapSize

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

源码地址

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

点赞
收藏

评论区

加载中...

相关推荐

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

Oracle 分组与拼接字符串同时使用

SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(

MySQL部分从库上面因为大量的临时表tmp_table造成慢查询

背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_

皕杰报表之UUID

​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为

手写Java HashMap源码

HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22

2020年前端实用代码段,为你的工作保驾护航

有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )