目录
一、前言
二、buildTypes
三、buildType
1、buildTypes存在形式
2、buildTypes 中属性的意义
3、buildTypes 中方法的意义
四、写在最后
继 上一篇博客 分享了defaultConfig 中可配置参数的含义,今天我们来分享另一个我们也很熟悉的 buildTypes
。
buildTypes
也是存在于每个应用级模块中的 android 下的,即如下所示,是每次构建完项目之后自动生成的结构。
android {
buildTypes{
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
}
buildTypes 可以配置我们需要的构建类型,例如我们常用到的 “测试类型” 和 “本地类型”,则可以使用如下配置
buildTypes{
// 发布类型
release {
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
// 测试类型,给测试人员
debug {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
// 本地类型,和后端联调使用
local {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
增加完这些配置后,我们可以在 android studio 看到多了 “debug” 和 “local” 两个可以构建的类型,在 “点击运行” 时,便会使用我们所选择的构建类型。假设此时选择的是 “debug” 类型,我们此时运行代码,则是 debug 下的配置参数。
当然运行编译成 apk 时,也不例外,各自使用的也是各自类型的配置。
而这里所说的 “release”,“debug”,“local”,三个构建类型其实便是三个 buildType
,buildType
所能配置的参数便是我们今天要来捋清楚的。
buildType 官方文档传送门
从上一篇博客我们知道,每个配置最终会被映射为一个类,或是一个属性、或一个方法。buildType
也不例外,他会被映射为 com.android.build.gradle.internal.dsl.BuildType
,继承结构如下
我们重新看一下 DefaultConfig 的继承结构,可以看到都会继承到 BaseConfigImpl
类,说明两者会有一定的交集。这也说明了为什么我们看 gradle 文件时,总感觉一个配置参数哪里都能出现的情况(后面会进行更多的比较,来解除我们这种疑惑)
我们先来一个约定,避免使用的代码过于冗长。
buildTypes{
debug {
// 我们下面的 “使用方法” 代码都是基于这一块,除非特殊说明。
}
}
debug {
applicationIdSuffix '.debug'
}
library
中,包括我们以aar形式导入的 library ,或是直接创建的 library。它的作用是,负责该 library 被进行编译时的混淆规则,我们在 主App 的模块下则可以不用再管理各个 library 的混淆规则,会直接使用各个 library 的混淆规则文件。debug {
consumerProguardFiles 'consumer-rules.pro'
......省略其他配置
}
// 因为该属性是一个 List 类型,如果需要多个文件配置,则如下所示
debug {
consumerProguardFiles 'consumer-rules.pro','zincPower-rules.pro'
......省略其他配置
}
debug {
crunchPngs false
......省略其他配置
}
debug {
debuggable true
}
annotationProcessor
时所需要的参数。debug {
javaCompileOptions {
annotationProcessorOptions{
arguments = []
classNames ''
....
}
}
......省略其他配置
}
JavaCompileOptions 可以配置的具体参数,请进传送门
debug {
jniDebuggable true
}
AndroidManifest.xml
中使用的参数。debug {
manifestPlaceholders = [APP_LOGO_ICON: "@mipmap/ic_logo"]
}
然后在 AndroidManifest.xml
中使用,使用 ${你配置的变量名}
// 在 application 中使用替换,还需要多添加 tools:replace 这一标签,将我们需要替换的名称写上,例如这里的 android:icon
<application
android:allowBackup="true"
android:icon="${APP_LOGO_ICON}"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme"
tools:replace="android:icon">
......
debug {
minifyEnabled true
}
minifyEnabled
设置为 true 的时候会使用这个参数,文件中需要申明哪些文件不被优化和混淆。debug {
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
64K 引用限制问题官方文档 传送门
android{
buildTypes {
debug {
multiDexEnabled true
...
}
}
}
// 添加依赖
dependencies {
// 如果使用的为 AndroidX,则使用下面这个导入
// implementation 'androidx.multidex:multidex:2.0.1'
// 如果不使用 AndroidX,则使用下面这段
compile 'com.android.support:multidex:1.0.3'
}
有两种开启 MultiDex 方法:
// 第一种:让你应用的 Application 继承 MultiDexApplication。
public class MyApplication extends MultiDexApplication {
}
// 第二种:重写应用的 Application 方法 attachBaseContext
public class MyApplication extends Application {
@Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
MultiDex.install(this);
}
}
最后别忘了在 AndroidManifest.xml
中使用我们在上面的 Application。
classs.dex
。我们在第 2.10 小点,分享到使用了多包处理,有时我们需要将一些主要的类打包进主包,则可以使用该属性。debug {
multiDexKeepFile file('multidex-config.txt')
...
}
multidex-config.txt 中的书写则如下,每一个文件则为一行
com/example/MyClass.class
com/example/TestClass.class
debug {
multiDexKeepFile file('multidex-config.pro')
...
}
multidex-config.pro 中的写法如下
// 将会保留所有的在com.example package的类
-keep class com.example.** { *; }
// debug 则会被赋值至 name 属性,而且 name 是final 类型,无法在改动。
debug{
...
}
第一步:我们在配置中开启该属性
debug{
pseudoLocalesEnabled true
}
第二步:安装我们的应用
第三步:打开设置 -> 系统 -> 语言和输入法 -> 语言 -> 添加语言
会在 “添加语言” 页面中看到如下图的选项,选择图中红色框的内容,各自的不同在图中也有标明,我们往下走看看具体不同的表现是什么。
小盆友的测试机是 荣耀8,不同机子会有些许不同
选择之后,选择不同的语言会有不同效果,如图所示
(1)左边为未开启时的样子;
(2)中间为选择了Pseudo locale(相当于en-XA);
(3)右边为选择了Bidirection test locale(相当于en-XB);
debug {
renderscriptDebuggable true
}
debug {
renderscriptOptimLevel 3
}
shrinkResources 官方使用手册 传送门
debug {
shrinkResources false
}
SigningConfig 的可配置参数 传送门
buildTypes {
release {
signingConfig {
// 不建议将签名证书的信息写在这里,而应该是写在 properties 文件中,将其引入使用
config {
keyAlias keystoreProperties['keyAlias']
keyPassword keystoreProperties['keyPassword']
storeFile file(keystoreProperties['storeFile'])
storePassword keystoreProperties['storePassword']
}
}
...
}
}
第一步:在 build.gradle 中开启 testCoverageEnabled
debug {
testCoverageEnabled true
}
第二步:连接上一台可用设备,因为我们执行的测试代码是要基于设备的,如果不连接,测试阶段会报如下错
第三步:在 android studio 的 终端(即 Terminal)中输入下面这行命令,查看所有可运行任务。
小盆友是 mac 环境,所以 ./gradlew 开头。windows 的环境则直接使用 gradlew 即可。
./gradlew app:tasks
输入运行后,可以看到图中高亮部分的可运行task。
我们以驼峰式(即第一个字母加上后面每个单词的首字母且以大写的形式)将其运行,代码如下
// create + 你的构建类型名(这里为debug) + CoverReport
./gradlew app:cDCR
运行完之后,就是查看测试报告的阶段了。我们进入coverage目录,具体路径如下图所示。
最后用浏览器打开 index.html 文件,就可以看报告啦,如下图所示,因为小盆友的这个项目没有写测试代码,所以覆盖率为0。
debug {
useProguard true
}
debug {
// 如果 versionName "1.0.0" ,则最终的版本名为 1.0.0.test
versionNameSuffix ".test"
.....
}
debug {
zipAlignEnabled true
.....
}
matchingFallbacks 还可以处理 维度风味的 问题,但我们这里先不讨论,后续的文章会介绍。
一个东西的出现是为了处理至少一个问题,所以我们需要先了解下这个问题是怎么产生的。
如上图所示,我们的 主Module(一般是App),存在了三个构建类型,即我们一开始所提的 “release”、“debug”、“local” 三种。
此时我们在项目添加了一个 module 名字为 library,并依赖进我们的app中。当我们构建 “release”、“debug” 两种版本时,都不会有任何问题,因为 library 默认也提供了 “release”、“debug” 两种构建版本。
但是当我们使用 “local” 时,便会出问题了,因为此时 gradle 的脚本也会默认选择 “library” 的 “local”,但 “library” 中并没有。会报下面这样的错误
ERROR: Unable to resolve dependency for ':app@local/compileClasspath': Could not resolve project :lib:library.
Show Details
Affected Modules: app
此时就需要帮 “local” 从 “library” 中选择一个可用的构建类型,则是通过 matchingFallbacks
进行设置。
铺垫了这么多,接下来就是怎么使用了,在 app 的 build.gradle 中添加如下代码即可。
local{
matchingFallbacks = ['zinc','release']
...
}
值得一提的是,我们可以配置多个,gradle在编译的时候,会按照从头开始匹配的原则,例如这里的 “zinc” 会匹配不到,则匹配 “release”,因为 “release” 匹配到了,则会进行使用,中断后面的匹配。
// 值的注意的是 value 的值是原样放置,我们通过使用方法一节来了解
<type> <name> = <value>
debug {
// 可以通过 BuildConfig 进行获取
buildConfigField('String', 'name', '"zinc"')
buildConfigField('int', 'age', '26')
.....
}
最终会生成如下图的配置,我们可以通过下面代码进行获取
String name = BuildConfig.name;
int age = BuildConfig.age;
值的一提的是,我们设置 String 类型的参数时,需要加上 “” 双引号(如例子中的name属性)。切记!
debug {
consumerProguardFile('consumer-rules.pro')
}
debug {
consumerProguardFile('consumer-rules.pro', 'zincPower-rules.pro',.....)
}
debug {
externalNativeBuild {
ndkBuild {
// Passes an optional argument to ndk-build.
arguments "NDK_MODULE_PATH+=../../third_party/modules"
}
// For ndk-build, instead use the ndkBuild block.
cmake {
// Passes optional arguments to CMake.
arguments "-DANDROID_ARM_NEON=TRUE", "-DANDROID_TOOLCHAIN=clang"
// Sets a flag to enable format macro constants for the C compiler.
cFlags "-D__STDC_FORMAT_MACROS"
// Sets optional flags for the C++ compiler.
cppFlags "-fexceptions", "-frtti"
// Specifies the library and executable targets from your CMake project
// that Gradle should build.
targets "libexample-one", "my-executible-demo"
}
}
}
cmake 具体参数 传送门
ndkBuild 具体参数 传送门
buildTypes {
debug{
}
local{
// 会拷贝 debug 的配置
initWith debug{
// 在这里进行我们自己的配置
}
}
}
debug {
proguardFile 'proguard-rules.pro'
}
debug {
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
debug {
proguardFiles = [getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro']
}
debug {
// 添加至 res/value,通过 R.string.age 获取
resValue('string', 'age', '12 years old')
}
Gradle 的配置文件看起来好像挺乱,其实是因为我们没有进行整体的梳理。很多配置其实不是没有用,而是我们没有对他有一个整体的了解,正所谓 “无知最可怕”。
如果喜欢的话请给我一个赞,并关注我吧。文章中如有写的不妥的地方,请评论区或加我微信与我讨论吧,共同进步。