如官网所说,Android Studio使用Gradle来自动化执行和管理构建流程,允许各种灵活配置参数。每个构建配置均可自行定义一组代码和资源,同时对所有应用版本共有的部分加以重复利用。
Gradle独立于Android Studio运作,也就是说完全可以在没有as的环境下单独使用gradle构建运行安卓应用。
一些构建运行的命令可参考官网。
关于安卓开发常用的gradle配置如下:(注:以下内容转载自 这里 ,作者:Jinwong)
1. Project中build.gradle
project下的build.gradle是基于整个project的配置,主要配置gradle 版本及 全局依赖仓库、库或者其他全部参数。
android studio 现在重要仓库采用jcenter(),之前版本放在mavenCentral。
另外有时还没有加入jcenter()仓库的第三方库,也需要在这里配置他们的库地址。
需要在这里配置,才能将第三方库拉下来
buildscript {
//构建过程依赖的仓库
repositories {
jcenter()
}
//构建过程需要依赖的库
dependencies {
//声明的是gradle插件的版本
classpath 'com.android.tools.build:gradle:2.0.0'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
//这里面配置整个项目依赖的仓库,这样每个module就不用配置仓库了
repositories {
jcenter()
maven {
// LeanCloud 的包仓库
url "http://mvn.leancloud.cn/nexus/content/repositories/releases"
}
}
}
//配置全局变量
ext {
// module依赖库公共版本号
SupportXVersion = '23.2.0'
GsonVersion = '2.6.2'
LeanCloudVersion = 'v3.13.4'
JunitVersion = '4.12'
compileSdkVersion = 22
buildToolsVersion = "23.0.1"
minSdkVersion = 10
targetSdkVersion = 22
versionCode = 34
versionName = "v2.6.1"
}
注:
大家可能很奇怪,为什么仓库repositories需要声明两次,这其实是由于它们作用不同,buildscript中的仓库是gradle脚本自身需要的资源,而allprojects下的仓库是项目所有模块需要的资源
2. module中build.gradle
//申明使用插件,表明要编译的内容和产物, //com.android.application 表明该module 为android 应用 //com.android.library 表明为library库 //java 表名是java库 apply plugin: 'com.android.application' //安卓构建过程需要配置的参数 android { //编译SDK的版本 compileSdkVersion COMPILE_SDK_VERSION as int //buildtool 的版本 buildToolsVersion BUILD_TOOLS_VERSION /默认配置,会同时应用到debug和release版本上 defaultConfig { //应用包名 applicationId APPLICATION_ID //支持最小android sdk 版本 minSdkVersion MIN_SDK_VERSION as int // 目标版本 targetSdkVersion TARGET_SDK_VERSION as int //应用版本号 versionCode VERSION_CODE as int //应用版本名称 versionName VERSION_NAME /// 配置生成的 BuildConfig 文件中的常量,代码引用直接 buildConfigField "String", "LOG_TAG", LOG_TAG // 日志tag buildConfigField "String", "LOG_HTTP_TAG", LOG_TAG_HTTP // http日志tag buildConfigField "String", "LOG_WEB_TAG", LOG_TAG_WEB // web日志tag // 默认是UMENG_CHANNEL_VALUE为umeng manifestPlaceholders = [UMENG_CHANNEL_VALUE: "umeng"] // dex突破65535的限制 multiDexEnabled true } //java版本号 compileOptions{ sourceCompatibility JavaVersion.VERSION_1_7 targetCompatibility JavaVersion.VERSION_1_7 } //签名 signingConfigs { release { //签名文件 storeFile file(STORE_FILE) storePassword STORE_PASSWORD keyAlias KEY_ALIAS keyPassword KEY_PASSWORD } } // 为了解决部分第三方库重复打包了META-INF的问题 packagingOptions { exclude 'META-INF/LICENSE.txt' exclude 'META-INF/NOTICE.txt' } //移除lint检测的error lintOptions { abortOnError false } //编译类型 //其中debug, release是gradle默认自带的两个build type, 当然你可以定义其他类型。 //可以针对不停编译的版本中配置不同的参数,比如混淆、签名等。preview buildTypes { debug { minifyEnabled false zipAlignEnabled false shrinkResources false } preview { debuggable false // 是否保留调试信息 minifyEnabled true //是否混淆 zipAlignEnabled true // 包优化 shrinkResources true // 移除不必要的资源 // 签名 signingConfig signingConfigs.release // 代码混淆规则文件 proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } release { //加上后缀 applicationIdSuffix ".release" minifyEnabled true //是否混淆 zipAlignEnabled true // zip对齐优化 shrinkResources true // 移除不必要的资源 // 不显示Log buildConfigField "boolean", "LOG_DEBUG", "false" // 签名 signingConfig signingConfigs.release //混淆文件的位置 proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } // 多渠道 productFlavors { //可以设置不同渠道渠道号,应用名称 dev { // 开发 buildConfigField "String", "CHANNEL_NUMBER", '"11111"' } '360' { buildConfigField "String", "CHANNEL_NUMBER", '"11112"' } GooglePlay { buildConfigField "String", "CHANNEL_NUMBER", "11113"' } // 多渠道批量替换 productFlavors.all { flavor -> //批量修改Manifest占位符替换 //在Manifest使用`${UMENG_CHANNEL_VALUE}`,`LEANCLOUD_CHANNEL_VALUE`,打包时将替换成渠道名,例如UMENG_CHANNEL_VALUE="dev"; flavor.manifestPlaceholders = [UMENG_CHANNEL_VALUE: name, LEANCLOUD_CHANNEL_VALUE: name] // Project Properties->_myAPPBuildVersionName,用于程序集成下命令行修改 if (project.hasProperty('_myAPPBuildVersionName')) { defaultConfig.versionName = _myAPPBuildVersionName } } //定义变量 //gradle 可以用def定义一些值例如:def KeyPassword = "123123" def releaseTime() { return new Date().format("yyyy-MM-dd", TimeZone.getTimeZone("UTC")) } // 批量打包 applicationVariants.all { variant -> variant.outputs.each { output -> def outputFile = output.outputFile if (outputFile != null && outputFile.name.endsWith('.apk')) { def fileName if (variant.buildType.name.equals('release')) { // myAPP_v版本号_渠道名.apk fileName = "myAPP_v${variant.versionName}_${variant.productFlavors[0].name}.apk" } else { // myAPP_v版本号_渠道名_时间_编译类型名.apk fileName = "myAPP_v${variant.versionName}_${variant.productFlavors[0].name}_${releaseTime()}_${variant.buildType.name}.apk" } output.outputFile = new File(outputFile.parent + "/${variant.buildType.name}", fileName) } } } } //依赖第三方库 dependencies { //编译libs目录下所以jar包 //compile files('libs/xxx.jar') 导入一个特定jar包 compile fileTree(dir: 'libs', include: ['*.jar'])//导入所有的jar包 compile project(':core') compile 'com.android.support:appcompat-v7:23.1.1' compile 'com.android.support:design:23.1.1' compile 'com.android.support:recyclerview-v7:23.1.1' compile 'com.android.support:cardview-v7:23.1.1' }
注意:
- buildToolsVersion这个需要你本地安装该版本才行,很多人导入新的第三方库,失败的原因之一是build version的版本不对,这个可以手动更改成你本地已有的版本或者打开 SDK Manager 去下载对应版本。
- proguardFiles这部分有两段,前一部分代表系统默认的android程序的混淆文件,该文件已经包含了基本的混淆声明,免去了我们很多事,这个文件的目录在/tools/proguard/proguard-android.txt , 后一部分是我们项目里的自定义的混淆文件,目录就在app/proguard-rules.pro ,在这个文件里你可以声明一些第三方依赖的一些混淆规则,最终混淆的结果是这两部分文件共同作用的。
- 一般重要的信息,例如签名信息,可以直接将信息写到gradle.properties,然后在然后在build.gradle中引用即可。
- 多渠道的关键在于定义不同的product flavor。
注意:这里的flavor名如果是数字开头,必须用引号引起来。buildTypes
是指建构的类型,一般只用两种默认类型 debug 和 release ,顾名思义 debug 用来配置开发过程中的一些内容;release 用来配置正式发布版本的内容。有时我们需要发布介于debug与release之间的preview 版本。
3. Project中setting.gradle
这个文件是全局的项目配置文件,里面主要声明Project中所包括的所有module,
//一个Project中所包括的所有module
include ':app', ':model',':lib', ':core'
4. Project中gradle.properties
gradle.properties为gradle的配置文件,里面可以定义一些常量供build.gradle使用,比如可以配置签名相关信息如keystore位置,密码,keyalias等,build.gradle就可以直接引用
gradle 中的一些配置参数建议写到gradle.properties
//编译版本信息 APPLICATION_ID = com.jin.myAPP COMPILE_SDK_VERSION = 23 BUILD_TOOLS_VERSION = 23.0.1 MIN_SDK_VERSION = 15 TARGET_SDK_VERSION = 1 VERSION_CODE = 1 VERSION_NAME = 1.0.0.0 //keystore信息 STORE_FILE = ../app/mykey.keystore STORE_PASSWORD = your password KEY_ALIAS = your alias KEY_PASSWORD = your password
5. ext配置全局参数
project的build.gradle中的ext可以为各位module进行全局配置参数,防止各个module之间的不统一,不可控。而且当我们升级sdk、build tool、target sdk等,几个module都要更改,非常的麻烦。
ext { compileSdkVersion = 22 buildToolsVersion = "23.0.1" minSdkVersion = 10 targetSdkVersion = 22 versionCode = 34 versionName = "v2.6.1" }
然后在各自module的build.gradle中引用:
android { compileSdkVersion rootProject.ext.compileSdkVersion buildToolsVersion rootProject.ext.buildToolsVersion defaultConfig { applicationId "com.xxx.xxx" minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion versionCode rootProject.ext.versionCode versionName rootProject.ext.versionName } }
6. resValue 定义资源。
例如resValue "string" 就是字符串资源,可以用R.String 来引用对应的字符串资源
android { defaultConfig { resValue "string", "build_time", buildTime() resValue "string", "build_host", hostName() resValue "string", "build_revision", revision() } } def buildTime() { return new Date().format("yyyy-MM-dd HH:mm:ss") } def hostName() { return System.getProperty("user.name") + "@" +InetAddress.localHost.hostName } def revision() { def code = new ByteArrayOutputStream() exec { commandLine 'git', 'rev-parse', '--short', 'HEAD' standardOutput = code } return code.toString() } 上述代码实现了动态的添加了3个字符串资源: build_time、build_host、build_revision, 然后在其他地方可像如引用字符串一样使用如下: // 在Activity里调用 getString(R.string.build_time) // 输出2015-11-07 17:01 getString(R.string.build_host) // 输出jay@deepin,这是我的电脑的用户名和PC名 getString(R.string.build_revision) // 输出3dd5823, 这是最后一次commit的sha值
7. PlaceHolder
manifest的一些值我们可以用PlaceHolder处理。例如
在gradle中改成
manifestPlaceholders = [UMENG_CHANNEL_VALUE: "360"]
可以放在defaultConfig
中设置默认值,或者放在productFlavors
中根据不同渠道修改成不同值。或者批量修改
productFlavors.all {
flavor -> flavor.manifestPlaceholders = [UMENG_CHANNEL_VALUE: name]
}
8. 导入某个project
如果你的app是多模块的,假设有两个模块app和lib,并且app模块是依赖lib的,这时候我们就需要在app模块的build.gradle中的dependencies结点下配置依赖:
compile project(':lib')
并且你需要在settings.gradle中把lib模块包含进来:
include ':lib',':app'
此外,这种情况下lib模块是作为库存在的,因而它的build.gradle中的插件声明通常应该是这样的:
apply plugin: 'com.android.library'
而且,作为library的模块lib的build.gradle文件的defaultConfig中是不允许声明applicationId的,这点需要注意。
9. 引用本地aar:
- 首先将你的库通过android studio 运行打包成aar文件。运行后在/build/output/aar文件夹中。
- 首先将aar文件放到模块的libs目录下,然后在该模块的build.gradle中声明flat仓库:
repositories{ flatDir { dirs 'libs' } }
- 最后在dependencies结点下依赖该aar模块:
dependencies{ compile (name:'xxx',ext:'aar') }
10. BuildConfig
在build.gradle中配置buildConfigField参数,编译后会在..\app\build\generated\source\buildConfig文件夹下会自动生成对应版本对应module的BuildConfig.java。BuildConfig就会包含对应版本的配置信息。程序中可以直接引用这些数据。例如BuildConfig.DEBUG。
public final class BuildConfig {
public static final boolean DEBUG = Boolean.parseBoolean("true");
public static final String BUILD_TYPE = "debug";
public static final String FLAVOR = "360";
public static final int VERSION_CODE = 45;
public static final String VERSION_NAME = "3.2.0.0";
// Fields from build type: debug
public static final String HOST_IMG_SERVER = "img";
public static final String HOST_SERVER = "test";
// Fields from product flavor: 360
public static final String CHANNEL_NUMBER = "232100";
}
11. module 调整目录结构sourceSets
默认情况下,java文件和resource文件分别在src/main/java和src/main/res目录下,在build.gradle文件,andorid{}里面添加下面的代码,便可以将java文件和resource文件放到src/java和src/resources目录下。
sourceSets {
main {
java {
srcDir 'src/java'
}
resources {
srcDir 'src/resources'
}
}
}
更简便的写法是:
sourceSets {
min.java.srcDirs = ['src/java']
min.resources.srcDirs = ['src/resources']
}
12. Gradle常用命令
上面大家接触了一些命令如 ./gradlew -v ./gradlew clean ./gradlew build, 这里注意是./gradlew,./代表当前目录,gradlew代表 gradle wrapper,意思是gradle的一层包装,大家可以理解为在这个项目本地就封装了gradle,即gradle wrapper, myAPP/gradle/wrapper/gralde-wrapper.properties**文件中声明了它指向的目录和版本。只要下载成功即可用grdlew wrapper的命令代替全局的gradle命令。
理解了gradle wrapper的概念,下面一些常用命令也就容易理解了。
./gradlew 下载更新gradle
./gradlew -v 版本号
./gradlew assemble 构建项目输出
./gradlew check 运行检测和测试任务
./gradlew clean 清除9GAG/app目录下的build文件夹
./gradlew build 运行check和assemble,检查依赖并编译打包
这里注意的是 ./gradlew build 命令把debug、release环境的包都打出来,如果正式发布只需要打Release的包,该怎么办呢,下面介绍一个很有用的命令assemble<build type="" name="">, 如</build>
./gradlew assembleDebug 编译并打Debug包
./gradlew assembleRelease 编译并打Release的包所有渠道的
./gradlew assembleWandoujiaRelease 编译并打包豌豆荚的Release版本
./gradlew assembleWandoujia 编译并打包豌豆荚的所有版本
./gradlew installRelease Release模式打包并安装
./gradlew uninstallRelease 卸载Release模式包