Android Studio Gradle进阶配置

设置 Java 版本

在根目录下的build.gradle文件下添加 ext{ .... } 中的内容:

ext{
kotlin_version = '1.1.51'
rxandroid = '2.0.1'
anko_version = '0.8.2'
support_version = '26.1.0'
target_sdk_version = 26
compile_sdk_version = 26
min_sdk_version = 15
}

使用规则,字符串需使用“$rootProject.”,整形直接用rootProject.。ext可加可不加

android {
compileSdkVersion rootProject.compile_sdk_version
defaultConfig {
applicationId "com.xxx.xxxx"
minSdkVersion rootProject.ext.min_sdk_version
targetSdkVersion rootProject.ext.target_sdk_version
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation"org.jetbrains.kotlin:kotlin-stdlib-jre7:$rootProject.ext.kotlin_version"
implementation "com.android.support:appcompat-v7:$rootProject.support_version"
implementation "io.reactivex.rxjava2:rxandroid:$rootProject.rxandroid"
compile "org.jetbrains.anko:anko-common:$rootProject.anko_version"
compile "com.android.support:recyclerview-v7:$rootProject.support_version"
}

参考:https://www.jianshu.com/p/abb5bbb99142

全局设定编码

allprojects {
repositories {
jcenter()
}
tasks.withType(JavaCompile) {
options.encoding = "UTF-8"
}
}

定义全局变量

先在 project 根目录下的 build.gradle 定义全局变量:

ext {
minSdkVersion = 16
targetSdkVersion = 24
}

然后在各 module 的 build.gradle 中可以通过rootProject.ext来引用:

android {
defaultConfig {
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
}

定义局部变量

有时候一个库会被引用多次,或者一个库有多个依赖,但这些依赖的版本都是统一的。我们通过ext来定义一些变量,这样在用到的时候就可以统一使用了。

ext {
leakcanaryVersion = '1.3.1'
scalpelVersion = "1.1.2" // other param
}

debugCompile "com.squareup.leakcanary:leakcanary-android:$leakcanaryVersion"
releaseCompile "com.squareup.leakcanary:leakcanary-android-no-op:$leakcanaryVersion"

exlude关键字

我们经常会遇到库冲突的问题,这个在多个部门协作的大公司会更常见到。将冲突的库通过exclude来做剔除是一个好方法。
1.剔除整个组织的库

compile ('com.facebook.fresco:animated-webp:0.13.0') {
exclude group: 'com.android.support' // 仅仅写组织名称
}

2.剔除某个库

compile('com.android.support:appcompat-v7:23.2.0') {
exclude group: 'com.android.support', module: 'support-annotations' // 写全称
exclude group: 'com.android.support', module: 'support-compat'
exclude group: 'com.android.support', module: 'support-v4'
exclude group: 'com.android.support', module: 'support-vector-drawable'
}

引用本地aar

1.把aar文件放在某目录内,比如就放在某个 module 的 libs 目录内
2.在这个 module 的 build.gradle 文件中添加:

repositories {
flatDir {
dirs 'libs' //this way we can find the .aar file in libs folder
}
}

3.之后在其他项目中添加下面的代码后就引用了该 aar

dependencies {
compile(name:'aar的名字(不用加后缀)', ext:'aar')
}

如果你希望把 aar 放在项目的根目录中,也可以参考上面的配置方案。在根目录的build.gradle中写上:

allprojects {
repositories {
jcenter()
flatDir {
dirs 'libs'
}
}
}

依赖项目中的 module 和 jar

依赖项目中的 module 和 jar

dependencies {
compile project(':mylibraryModule')
compile files('libs/sdk-1.1.jar')
}

配置独立的签名信息

通常我们可以直接把签名的明文信息写在 gradle 配置文件中,但是在开源代码的时候不是很方便,前者可能存放签名文件的位置需要修改,后者则希望隐藏签名信息,在看不少开源项目的时候,发现很多是这样做的 signingConfigs 位置, android 的下一级

signingConfigs {
release_key{
storeFile file(RELEASE_STORE_FILE)
storePassword RELEASE_STORE_PASSWORD
keyAlias RELEASE_KEY_ALIAS
keyPassword RELEASE_KEY_PASSWORD
}
}

buildTypes {
release {
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
signingConfig signingConfigs.release_key
}
debug {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
signingConfig signingConfigs.release_key
}
}

在对应位置引用常量,在 properties 中再进行具体赋值,这样不会直接暴露签名信息,也方便配置
在 gradle.properties 中

RELEASE_KEY_PASSWORD=xxxx
RELEASE_KEY_ALIAS=xxx
RELEASE_STORE_PASSWORD=xxx
RELEASE_STORE_FILE=../.keystore/xxx.jks

多渠道打包

在 product flavor 下定义不同类型, 把 AndroiManifest 中的 channel 替换
ductFlavors 位置: android 的下一级

android {
productFlavors {
fir {
manifestPlaceholders = [UMENG_CHANNEL_VALUE: "fir"]
}
GooglePlay {
manifestPlaceholders = [UMENG_CHANNEL_VALUE: "GooglePlay"]
}
Umeng {
manifestPlaceholders = [UMENG_CHANNEL_VALUE: "Umeng"]
}
}
}

替换 AndroiManifest 中的字段

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

减少编译错误和忽略 lint 检查

packagingOptions {
exclude 'META-INF/DEPENDENCIES.txt'
exclude 'META-INF/LICENSE.txt'
exclude 'META-INF/NOTICE.txt'
exclude 'META-INF/NOTICE'
exclude 'META-INF/LICENSE'
exclude 'META-INF/DEPENDENCIES'
exclude 'META-INF/notice.txt'
exclude 'META-INF/license.txt'
exclude 'META-INF/dependencies.txt'
exclude 'META-INF/LGPL2.1'
}
lintOptions {
abortOnError false
}

生成自定义 App 名称,在Android标签添加如下代码

applicationVariants.all { variant ->
variant.outputs.all { output ->
def outputFile = output.outputFile
if (outputFile != null && outputFile.name.endsWith('.apk')) {
// 输出apk名称为ForWatch_v1.1(2)2016-09-28_15-54-35.apk
def version = "v${versionName}-${versionCode}"
def endIndex = outputFile.name.indexOf('.apk')
def apkName = outputFile.name.substring(0, endIndex);
def fileName = "${apkName}
${version}${buildTime()}${revision()}.apk"
//output.outputFile = new File(outputFile.parent, fileName)
outputFileName = fileName
}
}
}

自定义apk的生成目录(含有自定义app名称的代码)

android {
……//省略部分代码
applicationVariants.all {
//判断是release还是debug版本
def buildType = it.buildType.name
def fileName
//下面的channel是获取渠道号,你获取渠道号不一定会和我的代码一样,因为有可能你的渠道名称的规则和我的不一样,我的规则是${渠道名}-${applicationId},所以我是这样取的。
def channel = it.productFlavors[0].name.split("-")[0]
//获取当前时间的"YYYY-MM-dd"格式。
def createTime = new Date().format("YYYY-MM-dd", TimeZone.getTimeZone("GMT+08:00"))
//只对Release包起作用,如果不是Release包则不变更输出路径,否则可能导致AS无法自动安装debug包。
if (buildType == "release") {
it.getPackageApplication().outputDirectory = new File(project.rootDir.absolutePath + "/apks/${it.productFlavors[0].applicationId}/${createTime}")
}
it.outputs.each {
//只对Release包起作用,如果不是Release包则不变更名称。
if (buildType == "release") {
//我此处的命名规则是:渠道名项目名版本名创建时间构建类型.apk
fileName = "${channel}_项目名称v${defaultConfig.versionName}${createTime}-${buildType}.apk"
//将名字打印出来,以便及时查看是否满意。
println "文件名:-----------------${fileName}"
//重新对apk命名。(适用于Gradle4.0以下版本)
//it.outputFile = new File(it.outputFile.parent, fileName)
//重新对apk命名。(适用于Gradle4.0(含)以上版本)如果你Gradle版本是4.0以下版本则将上面的一行代码放开并注释下面的这一行。
it.outputFileName = fileName
}
}
}
……//省略部分代码
}

参考:https://blog.csdn.net/kelin410/article/details/75500821

指定资源目录

自定义 java 代码和 res 资源的目录,更加灵活

android {
sourceSets {
main {
manifest.srcFile 'AndroidManifest.xml'
java.srcDirs = ['src']
resources.srcDirs = ['src']
aidl.srcDirs = ['src']
renderscript.srcDirs = ['src']
assets.srcDirs = ['assets']
if (!IS_USE_DATABINDING) { // 如果用了databinding
jniLibs.srcDirs = ['libs']
res.srcDirs = ['res', 'res-vm'] // 多加了databinding的资源目录
} else {
res.srcDirs = ['res']
}
}
test {
java.srcDirs = ['test']
}
androidTest {
java.srcDirs = ['androidTest']
}
}
}

在 BuildConfig.class 中增加静态变量

有时候我们想根据不同的版本,设置相同变量不同的值,最常见的使用场景就是 Log 工具类,通过设置 isDubug 不同值,只有 debug 版本的 app 会产生 log 日志,设置过程如下:

buildTypes {
release {
buildConfigField("boolean", "isDebug", "false") // 定义 isdubug 的值
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
debug{
buildConfigField("boolean", "isDebug", "true")
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}

在 sync 后BuildConfig中就有你定义的这个变量(isDebug)。

public final class BuildConfig {
public static final boolean DEBUG = Boolean.parseBoolean("true");
public static final String APPLICATION_ID = "com.hiwhitley.himei";
public static final String BUILD_TYPE = "debug";
public static final String FLAVOR = "";
public static final int VERSION_CODE = 1;
public static final String VERSION_NAME = "1.0";
// Fields from build type: debug
public static final boolean isDebug = true;
}

如果有带引号的 string,要记得转义:

buildConfigField "String", "URL_ENDPOINT", ""http://your.development.endpoint.com/""

参考:

Gradle配置最佳实践
Android Studio 中 gradle 的一些玩法
Gradle 语法

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,425评论 4 361
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,058评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,186评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,848评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,249评论 3 286
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,554评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,830评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,536评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,239评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,505评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,004评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,346评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,999评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,060评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,821评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,574评论 2 271
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,480评论 2 267

推荐阅读更多精彩内容

  • Gradle配置最佳实践 本文会不定期更新,推荐watch下项目。如果喜欢请star,如果觉得有纰漏请提交issu...
    Solang阅读 1,562评论 0 4
  • 说明 本文主要介绍和Gradle关系密切、相对不容易理解的配置,偏重概念介绍。部分内容是Android特有的(例如...
    jzj1993阅读 15,361评论 1 62
  • 参考 中文官网构建指南:https://developer.android.google.cn/studio/bu...
    FinalSky阅读 5,263评论 0 16
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 170,565评论 25 707
  • 最近中毒太深,每天一拿手机就刷头条,不是看新闻八卦,而是看各种小户型装修,几近疯狂。 控制不住脑袋里...
    滟昕阅读 324评论 4 3