1.修改Gradle文件的存放位置
默认情况下,android studio中gradle存放本地 C:\Users\用户名.gradle 文件夹下,下面存放着不同版本的gradle文件,如果想要修改存放位置可以在File>setting>Build,Execution,Deployment>Build Tools>gradle下
2.gradle的兼容问题
说完gradle文件存放的位置,不得不说一下下面这张图中的文件,这个文件夹包含了一个wrapper文件夹,那么为什么要有这个呢?gradle是一门发展很快的语言,语言发展快,api也就会经常更新,构建语言含有丰富的插件,变化很快的话,就难以兼容以前老的版本。而wrapper就用来解决解决兼容性问题。wrapper里定义了gradle的版本。
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.8-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
我现在这个项目用的gradle版本是6.8,构建这个工程时,它都会用我所绑定的gradle版本(避免版本兼容性问题)所以wrapper的作用就是会来检查在你构建这个工程的机器上有没有6.8这个版本。如果有就开始构建,没有就去下载这个版本。再举个例子,假如你现在从网上下载了一个项目,而这个项目它所绑定的gradle版本是6.8的,而你的机器现在只有6.8版本的gradle,那么当这个项目在你这台机器上构建的时候,wrapper就会看你机器上有没有6.8版本的gradle,发现没有的话就会去到所提供的url下载这个版本。 这个文件夹最主要的作用就是,当你clone了别人的项目,你网络又不好时,可以修改gradle的版本,使用本地已经下载好的gradle,让项目顺利构建。同时也可以避免本地下载一堆的gradle,占用磁盘空间。 写这篇文章才发现,我已经下载了那么多
3.Android gradle plugin(gradle插件简称AGP) 和gradle的关系对照
您可以在 Android Studio 的 File > Project Structure > Project 菜单中指定 Gradle 版本,也可以使用命令行更新 Gradle 版本。官网链接
4.常用的gradle命令
4.1 编译并生成相应的apk文件
./gradlew clean 清除/app目录下的build文件夹
./gradlew build //依赖并编译打包
./gradlew assembledebug //打debug包
./gradlew assemblerelease //编译并打release的包
./gradlew installrelease //release模式打包并安装
./gradlew uninstallrelease //卸载release模式包
./gradlew build --refresh-dependencies //刷新项目依赖
//编译并打印日志
./gradlew build --info
//译并输出性能报告,性能报告一般在 构建工程根目录 build/reports/profile
./gradlew build --profile
// 调试模式构建并打印堆栈日志
./gradlew build --info --debug --stacktrace
// 强制更新最新依赖,清除构建并重新构建
./gradlew clean build --refresh-dependencies
4.2.任务查询命令
//查看任务
./gradlew tasks
//查看所有任务,包括缓存任务
.gradlew tasks -all
//针对某个module [modulename]的某个TaskName运行
.gradlew :modulename:taskName
说明,module 定义在 工程根 settings.gradle
下,由 include 指定
子模块任务,不代表工程根也有同样的任务,所以需要单独查询moduel 最佳命名实践为 全小写英文
防止编译兼容问题。
4.3 查看包依赖
./gradlew dependencies
//查看模组的依赖
./gradlew app:dependencies
//检索依赖库
.gradlew app:dependencies |grep CompileClasspath
//windows 环境下
.gradlew app:dependencies | findstr "CompileClasspath"
// 将检索到的依赖分组找到 比如 multiDebugCompileClasspath 就是 multi 渠道分发的开发编译依赖
./gradlew app:dependencies --configuration multiDebugCompileClasspath
// 一般编译时的依赖库,不是固定配置方式,建议检索后尝试
./gradlew app:dependencies --configuration compile
// 一般运行时的依赖库,不是固定配置方式,建议检索后尝试
./gradlew app:dependencies --configuration runtime
4.4 统计task时长
gradle构建项目是将项目分成一个个的task的构建,通常为了分析哪个task花费了较长时间,需要我们自己写一些类来得到不同task的时长,好做针对性优化,这里有篇博客写的比较好,敢兴趣的直接跳转。统计task时长
4.5 有用的小技巧
有用的技巧 1. resolutionStrategy 统一全局第三方库版本 2. 修改包的输出路径 3. 找到版本冲突的库 4. 修改依赖方式
5.gradle.properties 文件
AS项目的根目录下有一个gradle.properties文件,专门用来配置全局键值对数据的。可用于存放敏感数据。
将它从git版本控制中排除,这样gradle.properties文件只能保留在本地,从而不用担心keystore文件等敏感信息泄漏。常见的配置如下
# Project-wide Gradle settings.
# IDE (e.g. Android Studio) users:
# Gradle settings configured through the IDE *will override*
# any settings specified in this file.
# For more details on how to configure your build environment visit
# http://www.gradle.org/docs/current/userguide/build_environment.html
# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel = true
# 为 Studio 分配默认的内存大小
org.gradle.jvmargs=-Xmx2048m
# 表示使用 AndroidX
android.useAndroidX=true
# 表示将第三方库迁移到 AndroidX
android.enableJetifier=true
# 如果不设置为 false ,在某些机型上将不被允许安装
android.injected.testOnly=false
同时配合BuildConfig可以定义一些常量,如果你的app有两以上不同的环境运行,那么可以尝试一下这种方式定义baseUrl
- 第一步:在app/build.gradle设置BuildConfig
android {
...
buildTypes {
release {
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
//buildConfigField用于给BuildConfig文件添加一个字段,baseUrl为键,后面的${releaseUrl}为值
buildConfigField("String","baseUrl","\"${releaseUrl}\"")
}
debug{
buildConfigField("String","baseUrl","\"${debugUrl}\"")
}
}
...
}
- 第二步:取值定义在gradle.properties文件中。
debugUrl = https://xxxdebug.com
realeaseUrl= https://xxxrelease.com
- 使用(你可以在项目中任意位置以BuildConfig.key的形式调用在buildConfigField上面定义的常量)
Log.d("tag",BuildConfig.baseUrl)
在debug环境下打印结果为https://xxxdebug.com 在release环境下打印结果为https://xxxrelease.com 这样就可以实现在不同包中使用不同的baseUrl.
6.使用Gradle规定组件之间资源前缀
通常我们的项目不是单个模块,分成了多个模块,因为我们拆分出了很多业务组件和功能组件,在把这些组件合并到**“app壳工程”时候就有可能会出现资源名冲突问题,例如A组件和B组件都有一张叫做“ic_back”的图标**,这时候在集成模式下打包APP就会编译出错,解决这个问题最简单的办法就是在项目中约定资源文件命名规约,比如强制使每个资源文件的名称以组件名开始,这个可以根据实际情况和开发人员制定规则。当然了万能的Gradle构建工具也提供了解决方法,通过在在组件的build.gradle中添加如下的代码:
//设置了resourcePrefix值后,所有的资源名必须以指定的字符串做前缀,否则会报错。
//但是resourcePrefix这个值只能限定xml里面的资源,并不能限定图片资源,所有图片资源仍然需要手动去修改资源名。
resourcePrefix "girls_"
7.gradle警告配置
// 代码警告配置
lintOptions {
// 禁用文本硬编码警告
disable 'HardcodedText'
// 禁用图片描述警告
disable 'ContentDescription'
}
8.build.gralde(project)
8.1旧版本
旧版本的build.gradle文件是这样的
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
ext.kotlin_version = '1.5.10'
ext.navigationVersion = '2.3.1'
//注释1:
repositories {
google()
mavenCentral()
jcenter()
maven { url 'https://jitpack.io' }
maven { url "https://maven.aliyun.com/repository/public" }
}
dependencies {
classpath "com.android.tools.build:gradle:4.0.2"
classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.5.31'
classpath "com.tencent.bugly:tinker-support:1.2.3"
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
//注释2:
allprojects {
repositories {
google()
mavenCentral()
jcenter()
maven { url "https://www.jitpack.io" }
maven { url 'https://jitpack.io' }
maven { url "https://maven.aliyun.com/repository/public" }
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
- 注释1中buildscript中的声明是gradle脚本自身需要使用的资源。可以声明的资源包括依赖项、第三方插件、maven仓库地址等。
- 而注释2在build.gradle文件中直接声明的依赖项、仓库地址等信息是项目自身需要的资源。
8.2 新版本build.gradle(project)
plugins {
id 'com.android.application' version '7.1.2' apply false
id 'com.android.library' version '7.1.2' apply false
id 'org.jetbrains.kotlin.android' version '1.6.10' apply false
}
task clean(type: Delete) {
delete rootProject.buildDir
}
上面使用了DSL写法,语法为
plugins {
id «plugin id» // (1)
id «plugin id» version «plugin version» [apply «false»] // (2)
}
plugin id 和 plugin version 是必需的 且必须是常量,字面量,字符串.其他语句都是不允许的
apply 是可选的,默认是 true;它是控制在应用插件的时候是否立刻使用插件的默认行为。
这个 plugins{} 块 是不能嵌套在别的配置块里的,必须是脚本的顶级模块。
8.3 应用插件到不同的模块(module)
应用插件到子项目 可以利用 plugins {} 的 apply 选项将插件应用到某些项目而不是所有项目里。 默认 plugins {} 的插件是立即被解析并应用的。 可以使用 apply false 告诉 Gradle 不应用到当前项目, 然后在子项目的脚本中使用 apply plugin <> 或者 plugins{} 应用插件 settings.gradle中
include 'helloA'
include 'helloB'
include 'goodbyeC'
导入了3个模块 然后在build.gradle中
plugins {
id 'org.gradle.sample.hello' version '1.0.0' apply false
id 'org.gradle.sample.goodbye' version '1.0.0' apply false
}
subprojects {
if (name.startsWith('hello')) {
apply plugin: 'org.gradle.sample.hello'
}
}
goodbyeC/build.gradle
plugins {
id 'org.gradle.sample.goodbye'
}
上面的示例演示了如何给多个子项目分别应用不同的插件。
8.4 setting.gradle(旧版)
include ':app'
rootProject.name = "CustomView"
8.5setting.gralde(新版)
和旧版仅仅是管理项目和不同模块之间的关系不同,新的setting.gradle还添加了 这个 pluginManagement DSL 是用来管理插件的,它可以配置插件,自定义仓库,自定义解析规则等。 pluginManagement{} 只能定义在两个地方:settings.gradle 里,并且必须是第一个模块
//插件管理
pluginManagement {
repositories {
gradlePluginPortal()
google()
mavenCentral()
}
}
//管理第3方依赖
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
google()
mavenCentral()
}
}
rootProject.name = "CustomView"
include ':app'
另一个是init.gradle 里
settingsEvaluated { settings ->
settings.pluginManagement {
plugins {
}
resolutionStrategy {
}
repositories {
}
}
}
9 使用ext进行统一版本配置
ext {
android = [
compileSdkVersion : 29,
buildToolsVersion : "30.0.2",
applicationId : "com.xionggouba.bearseller",
minSdkVersion : 19,
targetSdkVersion : 30,
versionCode : 27,
versionName : "3.9.1",
defaultPublishConfig: 'release',
publishNonDefault : true,
multiDexEnabled : true,
mapKey : 'c7e1ee468aa1bf8a6739',
pushKey : '65aae199a0059eb1dbe7',
pushChannel : 'developer-default',
]
appid = [
app : "com.xionggouba.bearseller",
login : "com.huitao.login",
home : "com.huitao.home",
webview : "com.huitao.webview",
main : "com.huitao.main",
productManager: "com.huitao.productmanager",
personal : "com.huitao.personalcenter",
map : "com.huitao.map",
bluetooth : "com.huitao.bluetooth",
push : "com.huitao.push",
markketing : "con.huitao.marketing",
printer : "com.huitao.printer"
]
versions = [
"lifecycle_version": "2.2.0",
"arch_version" : "2.1.0",
"retrofit_version" : "2.6.2",
"dialog_version" : "3.3.0",
"glide_version" : "4.9.0",
"hilt" : "2.28-alpha",
"kotlin_version" : "1.4.10",
"fragment_version" : "1.2.5",
"room_version" : "2.2.6"
]
]
通常为了方便版本管理,我们会在根目录下创建一个config.gradle文件,统一管理版本号,然后在build.gradle(project)下使用
apply from "config.gradle"
引入,然后使用,比如依赖room库
implementation "androidx.room:room-runtime:$versions.room_version"
10 build.gradle(app)
//该模块为应用程序模块,可以直接运行
apply plugin: 'com.android.application'
android {
//指定项目的编译版本,
compileSdkVersion 31
//指定项目构建工具的版本
buildToolsVersion "30.0.3"
defaultConfig {
//项目包名为com.example.test
applicationId "com.example.test"
//最低兼容到Android 5.0版本
minSdkVersion 21
//指定已做过充分测试的目标版本
targetSdkVersion 25
//版本号,这个是给开发者看的,以后应用升级都是以这个为准,范围大于1的整数
versionCode 1
// 这个是版本名称,给用户看的,
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
// 仅保留中文语种的资源
resConfigs 'zh,zh-rCN'
// 仅保留 xxhdpi 图片资源(目前主流分辨率 1920 * 1080)
resConfigs 'xxhdpi'
ndk {
// 设置支持的SO库架构,目前上支持armeabi-v7a ,和arm64-v8a就可以运行在大部分手机上了
// abiFilters 'arm64-v8a', 'x86_64','armeabi' ,
abiFilters 'arm64-v8a','armeabi-v7a' // ,'armeabi-v7a' //'x86_64', ,
}
}
//配置签名
/**
* Linux或者Mac
* gradle assembleRelease 生成release版本
* gradle assembleDebug
*
* win
* gradlew assembleRelease 生成release版本
* gradlew assembleDebug
*
*/
signingConfigs {
release {
keyAlias 'android' //随便起
keyPassword '' //生成签名是的密码
storeFile file('../mobile-app.jks') //签名文件
storePassword 'adsda2++' //你自己的密码
v1SigningEnabled true //v1 签名
v2SigningEnabled true //v2 签名
}
debug {
keyAlias 'ttyh.android.key'
keyPassword 'adsda2++' //你自己的密码
storeFile file('../mobile-app.jks')
storePassword 'ttyh-123456++'
v1SigningEnabled true
v2SigningEnabled true
}
}
//打包偏好设置
buildTypes {
//指定生成正式版安装文件的配置
release {
//代码不进行混淆
minifyEnabled false
//压缩文件
zipAlignEnabled true
// 移除无用的resource文件
shrinkResources false
//指定混淆的规则文件,proguard-android.txt为默认的混淆文件,定义了一些通用的混淆规则;
//proguard-rules.pro文件位于当前项目的根目录下,定义一些项目特有的混淆规则。
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
//指定测试版的安装文件配置
debug {
minifyEnabled false
signingConfig signingConfigs.debug
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard- rules.pro'
}
}
productFlavors{
urlDebug{
signingConfig signingConfigs.debug //引用前面的签名配置
//测试环境Url,指定不同环境下的域名,到时可以通过BuildConfig.SERVER_URL 获取到域名
buildConfigField 'String',"SERVER_URL", '\"https://xxx.com'
}
urlRelease{
signingConfig signingConfigs.release
//生产环境Url
buildConfigField 'String', 'SERVER_URL','\"https://xxx.com'
}
}
//不同资源文件尺寸的偏好
flavorDimensions 'default'
//kotlin 1.1.4开始,新增3个特性,要开启这3个特性,需要下面的设置
//1.任何类中view 属性都会被缓存为ViewHolder;
//2.提供@Parcelize 可以让任何类以一种简单的方式实现Parcelable
//3.还有一种方法可以自定义生成的缓存
androidExtensions {
experimental = true
}
//使用viewbinding
buildFeatures {
viewBinding true
}
//确定java 版本
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = "1.8"
}
sourceSets {
main {
jniLibs.srcDirs = ['libs']
}
}
}
10.sourceSet
强大的gradle,通过sourceSets可以让开发者能够自定义项目结构,如自定义assets目录、java目录、res目录,而且还可以是多个,但要知道的是,sourceSets并不会破坏变体的合并规则,它们是分开的,sourceSets只是起到了“扩充”的作用。这里先摆一下sourceSets的常规使用:
sourceSets {
main {
manifest.srcFile 'AndroidManifest.xml'
java.srcDirs = ['src']
aidl.srcDirs = ['src']
renderscript.srcDirs = ['src']
res.srcDirs = ['res']
assets.srcDirs = ['assets']
}
}
对于多渠道共用同一套assets资源文件这个问题,结合sourceSets,我们可以这么处理,步骤如下:
- 把共用的assets资源存放到一个渠道目录下,如free/assets。
- 修改sourceSets规则,强制指定china渠道的assets目录为free/assets。
sourceSets {
china {
sourceSet.assets.srcDirs = ['src/free/assets']
}
}
参考文章: - gradle插件 - 《Android Gradle 权威指南》 - sourceSets在多渠道打包中的作用 - Gradle7.1+新版本依赖变化 - android多渠道打包