基础概念
Gradle
Gradle 是以类 java 语法的 Groovy 语言为基础,基 于JVM 的自动化构建工具。一般通过编写 build.gradle 脚本实现编译构建逻辑开发。
Gradle Wrapper
Gradle Wrapper 是 Gradle 的封装,一个 Gradle Wrapper 对应一个特定版本的 Gradle。gradlew 为 Gradle Wrapper 的缩写。当用户第一次执行 gradlew 命令时,Gradle Wrapper 会自动下载、安装对应版本的 Gradle。
Android Gradle Plugin
Android Gradle Plugin 简写 AGP,是基于 Gradle 的 Android 应用的构建系统。与 Gradle 版本存在对应关系。
Plugin version |
Gradle version |
1.0.0 - 1.1.3 |
2.2.1 - 2.3 |
1.2.0 - 1.3.1 |
2.2.1 - 2.9 |
1.5.0 |
2.2.1 - 2.13 |
2.0.0 - 2.1.2 |
2.10 - 2.13 |
2.1.3 - 2.2.3 |
2.14.1 - 3.5 |
2.3.0+ |
3.3+ |
3.0.0+ |
4.1+ |
3.1.0+ |
4.4+ |
3.2.0 - 3.2.1 |
4.6+ |
3.3.0 - 3.3.3 |
4.10.1+ |
3.4.0 - 3.4.3 |
5.1.1+ |
3.5.0 - 3.5.4 |
5.4.1+ |
3.6.0 - 3.6.4 |
5.6.4+ |
4.0.0+ |
6.1.1+ |
4.1.0+ |
6.5+ |
4.2.0+ |
6.7.1+ |
7.0 |
7.0+ |
Android Studio 配置
Android Studio 中一般来说主要关注四个配置文件:gradle.properties、local.properties、gradle-wrapper.properties、settings.gradle、build.gradle。
1 2 3 4 5 6 7 8 9 10 11 12 13
| MyApp ├── build.gradle // 仓库设置、gradle 插件版本设置 ├── settings.gradle // 项目模块及依赖设置 ├── gradle.properties // gradle 的全局配置文件。 ├── local.properties // gradle 的本地配置文件。 ├── gradlew ├── gradlew.bat ├── gradle | └── wrapper | ├── gradle-wrapper.jar | └── gradle-wrapper.properties // gradle 版本及位置设置 └── module └── build.gradle
|
gradle.properties
gradle.properties 是 Gradle 的全局性配置文件,主要有两方面用途:
- 可以在此文件中自定义全局的属性,然后在项目中其他的 *.gradle 里面直接引用。
- 配置全局 gradle、system、project 的属性和环境变量,如代理服务、JAVA_HOME、是否使用 androidx。
自定义配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| # 用于 gradle 直接使用配置示例 COMPILE_SDK_VERSION=28 TARGET_SDK_VERSION=28
SUPPORT_APPCOMPAT_V7_VERSION=28.0.0
# 用于 java 代码使用配置示例 DEFAULT_NAME=xiaoming DEFAULT_NUMBER=10086
# 用于 xml 文件调用配置示例 USER_NAME=xioahong TEXT_SIZE=20sp TEXT_COLOR=#ef5350
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| android { compileSdkVersion COMPILE_SDK_VERSION as int defaultConfig { targetSdkVersion TARGET_SDK_VERSION as int ... } buildTypes { release { minifyEnabled true proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
buildConfigField("String", "defaultName", "\"${DEFAULT_NAME}\"") buildConfigField("Integer", "defaultNumber", DEFAULT_NUMBER)
resValue("string", "user_name", "${USER_NAME}") resValue("dimen", "text_size", "${TEXT_SIZE}") resValue("color", "text_color", "${TEXT_COLOR}")
... } } ... }
dependencies { ... implementation "com.android.support:appcompat-v7:${SUPPORT_APPCOMPAT_V7_VERSION}" ... }
|
1 2
| System.out.println("defaultName:" + BuildConfig.defaultName); System.out.println("defaultNumber:" + BuildConfig.defaultNumber);
|
1 2 3 4 5 6 7 8 9 10 11 12
| <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/user_name" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" android:textSize="@dimen/text_size" android:textColor="@color/text_color" />
|
注意:
- 在 gradle.properties 中定义的属性默认是 String 类型的,如果需要 int 类型,使用时需要添加 as int 后缀。
- 使用时,直接引用变量名即可。在字符串中使用时,要添加 ${} 。
- 如果要在 java 代码中使用,一般先将其配置为 BuildConfig。然后在代码中调用。
- 如果要在 xml 中使用,一般先将其配置为 resValue。然后在 xml 中引用 @string。
代理配置
1 2 3 4 5 6 7 8 9 10 11 12 13
| systemProp.http.proxyHost=www.somehost.org systemProp.http.proxyPort=8080 systemProp.http.proxyUser=userid systemProp.http.proxyPassword=password systemProp.http.nonProxyHosts=*.nonproxyrepos.com|localhost
systemProp.https.proxyHost=www.somehost.org systemProp.https.proxyPort=8080 systemProp.https.proxyUser=userid systemProp.https.proxyPassword=password systemProp.http.nonProxyHosts=*.nonproxyrepos.com|localhost
|
也可以在 IDE 的 Settings –> Appearance & Behavior –> System Settings –> HTTP Proxy 选项下进行配置。
local.properties
local.properties 与 gradle.properties 类似,但不会被添加到版本控制中,因此主要用来配置一些本地的变量和本地的 SDK 目录。
本地 SDK 配置
1 2 3
| sdk.dir=/Users/xxxx/Library/Android/sdk ndk.dir=/Users/xxxx/Library/Android/ndk/android-ndk-r19c
|
AGP 4.1 以上版本,通过 build.gradle 文件中使用 android.ndkVersion 和 android.ndkPath 属性指定相应的版本。
本地自定义配置
1 2 3 4 5
| key.file=C\:\\work\\Key.jks keyAlias=key keyPassword=key7766 storePassword=key6677
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
|
Properties properties = new Properties() InputStream inputStream = project.rootProject.file('local.properties').newDataInputStream(); properties.load( inputStream )
def sdkDir = properties.getProperty('key.file') storeFile file( sdkDir )
def key_keyAlias = properties.getProperty( 'keyAlias' ) def key_keyPassword = properties.getProperty( 'keyPassword' ) ; def key_storePassword = properties.getProperty( 'storePassword' ) ;
storePassword key_storePassword keyAlias key_keyAlias keyPassword key_keyPassword
|
gradle-wrapper.properties
Android Studio 新建工程时,会在项目根目录自动生成 Wrapper 所需的目录及文件。
1 2 3 4 5 6
| |____gradle | |____wrapper | | |____gradle-wrapper.jar //具体业务逻辑 | | |____gradle-wrapper.properties //配置文件 |____gradlew //Linux 下可执行脚本 |____gradlew.bat //Windows 下可执行脚本
|
其中,gradle-wrapper.properties 是 gradle-wrapper 的配置文件,主要用于配置项目使用的 gradle 版本及下载解压路径。
1 2 3 4 5
| distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-6.1.1-all.zip
|
- distributionUrl:下载的gradle的地址。
- gradle-xx-all.zip是完整版,,包含了各种二进制文件,源代码文件,和离线的文档。
- gradle-xx-bin.zip是二进制版,只包含了二进制文件(可执行文件)。
- gradle-xx-src.zip是源码版,只包含了Gradle源代码,不能用来编译工程。
- zipStoreBase 和 zipStorePath 组合在一起,是下载的 gradle-xx-xxx.zip 所存放的位置。
- distributionBase 和 distributionPath 组合在一起,是下载的 gradle-xx-xxx.zip 解压后的位置。
宏 |
目录 |
示例 |
GRADLE_USER_HOME |
用户目录 |
在 windows 下是 %USERPROFILE%/.gradle,例如 C:\Users\\.gradle\。在 linux 下是$HOME/.gradle,例如~/.gradle. |
PROJECT |
工程的当前目录 |
gradlew 所在的目录 |
settings.gradle
项目中可能存在多份 settings.gradle。其中项目根目录的 settings.gradle 文件包含项目的模块等配置。
1 2 3 4 5
| include ':module1', ':module2'
project(':module1').projectDir = new File("module1") project(':module2').projectDir = new File("module2")
|
build.gradle
项目中可能存在多份 build.gradle。其中项目根目录的 build.gradle 文件包含项目依赖(Java 或Android library)源仓库及 gradle 插件版本信息。
- repositories 闭包,声明了依赖源仓库的配置;
- dependencies 闭包,声明了一个 Gradle 插件。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| buildscript { repositories { google() jcenter() } dependencies { classpath 'com.android.tools.build:gradle:3.0.0' } }
allprojects { repositories { google() jcenter() } }
task clean(type: Delete) { delete rootProject.buildDir }
|
仓库配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| repositories { google() jcenter() mavenCentral() mavenLocal() }
repositories { maven {url 'https://maven.aliyun.com/repository/google'} maven {url 'https://maven.aliyun.com/repository/public'} maven {url 'https://maven.aliyun.com/repository/central'} }
|
使用 mavenLocal() 时 Gradle 默认会按以下顺序去查找本地的 maven 仓库:USER_HOME/.m2/settings.xml >> M2_HOME/conf/settings.xml >> USER_HOME/.m2/repository。因此,环境变量要加入 M2_HOME。另外,如果本地没有相关 jar 包,gradle 会下载到 USER_HOME/.gradle 文件夹下,若想让 gradle 下载到指定文件夹,配置 GRADLE_USER_HOME 环境变量,用于指定目录。
仓库的修改,也可以在 IDE 的 Module Setting –> project 选项下,配置 repositories。
gradle 插件版本配置
1 2 3 4 5
| buildscript { dependencies { classpath 'com.android.tools.build:gradle:4.0.0' } }
|
注意,gradle 插件版本和 gradle 版本配置时,必须满足对应关系!
gradle 插件版本的修改,也可以通过 File > Project Structure > Project 来配置。
Native 编译设置
一般在模块中,需要使用到 c++ 代码编译,可以选择 cmake 或者 ndk-build 两种构建工具,并根据选择配置模块的 build.gradle 文件。
cmake 构建
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
| android { ...
defaultConfig { ... externalNativeBuild { cmake { ... arguments "-DANDROID_ARM_NEON=TRUE", "-DANDROID_TOOLCHAIN=clang"
cFlags "-D__STDC_FORMAT_MACROS" cppFlags "-fexceptions", "-frtti"
abiFilters "arm64-v8a", "armeabi-v7a" } }
ndk { ... abiFilters 'x86', 'x86_64', 'armeabi', 'armeabi-v7a', 'arm64-v8a' } } externalNativeBuild { cmake { ... path "CMakeLists.txt" version "cmake-version" } }
ndkPath "/Users/ndkPath/ndk21" ndkVersion "major.minor.build" }
|
ndk-build 构建
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| android { ...
defaultConfig { ... externalNativeBuild { ndkBuild { ... arguments "NDK_APPLICATION_MK:=src/main/jni/Application.mk"
cFlags "-D__STDC_FORMAT_MACROS" cppFlags "-fexceptions", "-frtti"
abiFilters "arm64-v8a", "armeabi-v7a" } }
ndk { ... abiFilters 'x86', 'x86_64', 'armeabi', 'armeabi-v7a', 'arm64-v8a' } } externalNativeBuild { ndkBuild { ... path "src/main/jni/Android.mk" } }
ndkPath "/Users/ndkPath/ndk21" ndkVersion "major.minor.build" }
|
android 依赖配置
android-support
一般在模块中,使用到 android support 依赖时,需要配置模块的 build.gradle 文件,添加对应的版本。
1 2 3 4 5 6 7 8 9
| dependencies { ... implementation 'com.android.support:support-v4:28.0.0' implementation 'com.android.support:appcompat-v7:28.0.0' implementation 'com.android.support:multidex:1.0.0' implementation 'com.android.support:support-v13:28.0.0' implementation 'com.android.support:preference-v14:28.0.0' }
|
注意:
- SDK 最高支持 support 库的版本为 28,因此项目的 compileSdkVersion 不能大于 28。
androidx
AndroidX 对原始 Android 支持库进行了重大改进,自 android sdk 29 开始完全取代了 support 库。
使用或者迁移到 AndroidX,需要在项目的 gradle.properties 中进行相关配置:
1 2 3 4 5
| android.useAndroidX=true
android.enableJetifier=true
|
注意:
- SDK 最低支持 androidx 库的版本为 29,因此项目的 compileSdkVersion 不能低于 29。
- 迁移之前,应先将项目更新为使用支持库的最终版本:28.0.0。
使用 Android Studio 3.2 及更高版本,也可以从菜单栏中依次选择 Refactor > Migrate to AndroidX 进行迁移。
编译传参
1 2
| # 通过命令行传参(-P) gradlew :module:task -PYOUR_KEY=YOUR_VALUE
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| android { def yourKey = project.hasProperty('YOUR_KEY') ? YOUR_KEY : "defaultValue"
defaultConfig { minSdkVersion 15 targetSdkVersion 26 versionCode 1 versionName "1.0.0"
buildConfigField("String", "buildConfig_Key", "\"${yourKey}\"") } }
|
编译构建问题
【问题】:Error:failed to find Build Tools revision xx.x.x
【分析】:工程配置的Android BuildToolsVersion与本机安装的SDK Tool版本不一致。
【解决方法】:
- 修改工程各个 module的build.gradle 中 BuildToolsVersion 版本与本机安装的版本一致。
- 查看工程 settings.gradle 中的依赖项目,确保其 BuildToolsVersion 版本与本机安装的版本一致。
找不到android方法
【问题】:Could not find method android() for arguments [xxxxxxxxx] on root project ‘‘.
【分析】:不能在工程根目录的 build.gradle 中配置android block。
【解决方法】:将工程根目录build.gradle 中的android配置移动到module/build.gradle。
1 2 3 4
| android { compileSdkVersion 26 buildToolsVersion "26.0.1" }
|
打包aar,lib 库冲突
【问题】:通过 Android Studio 打包的 aar,包含 lib 内的依赖 jar 包,导致使用时产生冲突。
【分析】:Gradle 支持6种编译方式。compile、provided、apk、test compile、debug compile 和 release compile。
- compile:对所有 buildType 以及 flavors 进行编译并打包到apk 。
- provided:和 compile 相似,但只在编译时使用,不打包到最终apk 。
- apk:只会打包到 apk 中,不参与编译,所以不能在项目代码中使用相应库中的方法。
- test compile:仅针对单元测试的代码编译打包。
- debug compile:仅针对 debug 模式编译打包。
- release compile:仅针对 release 模式编译打包。
【解决方法】:将 module 下的 build.gradle 中编译配置由 compile 改为 provided。
1 2 3 4
| dependencies { provided fileTree(include: ['*.jar'], dir: 'libs') }
|
BuildConfig 冲突
【解决方法】:关闭不必要的 BuildConfig 生成。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
|
android { buildFeatures { buildConfig = false } }
android.defaults.buildfeatures.buildconfig=false
android { packageBuildConfig = false }
afterEvaluate { generateReleaseBuildConfig.enabled = false generateDebugBuildConfig.enabled = false }
|
参考文档
https://developer.aliyun.com/mvn/guide?spm=a2c6h.13651104.0.0.435836a4edt4OQ
https://juejin.cn/post/6844903987557171213
https://docs.gradle.org/current/userguide/build_environment.html
https://developer.android.com/studio/projects/install-ndk?hl=zh-cn
https://www.cnblogs.com/steffen/p/9212765.html