1.构建类型(Build types)
Android Studio生成的标准buildTypes块
android {
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile
('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
debug构建类型有他自己的默认设置,当我们创建自己的构建类型,会和默认的有些不同,比如 debuggable属性将被设置为true对于debug构建类型,但是其他你创建的类型会被设置为false
1.1创建构建类型
当默认的设置无法满足需求,最简单的方法是创建自定义的构建类型,比如
android {
buildTypes {
staging {
applicationIdSuffix ".staging"
versionNameSuffix "-staging"
buildConfigField "String", "API_URL",
"\"http://staging.example.com/api\""
}
}
}
NOTE:要注意的是buildConfigField的第三个参数,不能直接是"“属性值”,不然生成在buildConfig类中的这个自定义属性的值不会有"",从而报错,需要用上面的格式写,或者使用’'括起来,里面写"属性值"。
上面代码定义了新的applicationId的后缀,他可以让你的applicationId不同于其他版本,比如
- Debug:com.package
- Release: com.package
- Staging: com.package.staging
这意味着你可以同时安装不同版本在同一设备上。
当你创建新的构建类型,你不需要每次都重写相同属性,可以复制其他类型的属性来初始化,比如
android {
buildTypes {
staging.initWith(buildTypes.debug)
staging {
applicationIdSuffix ".staging"
versionNameSuffix "-staging"
debuggable = false
}
}
}
initWith()方法创建了新的构建类型,复制了一个已经存在的构建类型的所有属性到新的里面,想要覆盖或者定义新的属性,只需要在新的构建类型中去定义
1.2 源文件集合(Source sets)
创建新的构建类型,gradle会创建新的source set,结构如下,但是这些目录不会自动创建,需要自己去创建目录结构
app
└── src
├── debug
│ ├── java
│ │ └── com.package
│ │ └── Constants.java
│ ├── res
│ │ └── layout
│ │ └── activity_main.xml
│ └── AndroidManifest.xml
├── main
│ ├── java
│ │ └── com.package
│ │ └── MainActivity.java
│ ├── res
│ │ ├── drawable
│ │ └── layout
│ │ └── activity_main.xml
│ └── AndroidManifest.xml
├── staging
│ ├── java
│ │ └── com.package
│ │ └── Constants.java
│ ├── res
│ │ └── layout
│ │ └── activity_main.xml
│ └── AndroidManifest.xml
└── release
├── java
│ └── com.package
│ └── Constants.java
└── AndroidManifest.xml
资源文件会由指定方式被使用在不同源文件集,Drawables和layout文件会完全覆盖main里面同名的源文件(就是直接使用新的文件),但是values下面的文件不会是这样,而是采用合并,比如
//main里面是这样
<resources>
<string name="app_name">TypesAndFlavors</string>
<string name="hello_world">Hello world!</string>
</resources>
//自己定义的构建类型目录下的String
<resources>
<string name="app_name">TypesAndFlavors STAGING</string>
</resources>
//strings.xml会被合并成这样,在你使用staging构建类型
<resources>
<string name="app_name">TypesAndFlavors STAGING</string>
<string name="hello_world">Hello world!</string>
</resources>
manifest文件也是这样,你不需要复制整个个manifest,只需要写你需要的部分,最后系统会合并
1.3 依赖(Dependencies)
每个构建类型都有自己的依赖集,gradle会自动为每个构建类型创建依赖配置,如果你只需要为debug类型添加logging框架,可以像下面一样
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile 'com.android.support:appcompat-v7:22.2.0'
//debugCompile 只为debug类型添加依赖
debugCompile 'de.mindpipe.android:android-logging-log4j:1.0.3'
}
2. 产品风味(Product flavors)
产品风味是用于配置同一个app或者library,是用于创建同一个app的不同版本,对于一个之改变了很少的app,比如之改变了logo,url。如果需要一个新的app发布到不同平台,可以用Product flavors,否则可以继续使用build types
感觉就是如果一次要发布多版本,而且不同版本要求更改的东西不多可以用产品风味,如果不需要很多版本,只是测试,正式分开,就可以用build types配置不同构建
2.1 创建产品风味(creating product flavors)
android {
//现在要求每个产品风味必须属于一个产品维度,下面这句现在不能少
flovarDimensions 'api','version'
productFlavors {
red {
//指明所属的维度
dimension 'api'
applicationId 'com.gradleforandroid.red'
versionCode 3
}
blue {
dimension 'api'
applicationId 'com.gradleforandroid.blue'
minSdkVersion 14
versionCode 4
}
yellow {
dimension 'version'
applicationId 'com.gradleforandroid.yellow'
minSdkVersion 14
versionCode 4
}
black {
dimension 'version'
applicationId 'com.gradleforandroid.black'
minSdkVersion 14
versionCode 4
}
}
}
最终生成的产品个数等于api维度下的产品数*version下的产品数,这个例子最终产品数是4个,当然这是一种build type下的数量,debug的有4个,release下的有4个,分别是redyellow,redbalck,blueyellow和blueblack
不同维度定义了相同属性,会由先定义的维度覆盖掉后定义的
3.构建变体(build variants)
3.1 Tasks
Android的gradle插件会为每个构建变体创建task
3.3 资源文件和manifest的合并(resource and manifest merging)
android插件会打包源代码集合到app中,库项目也会有额外的resources,我们可能需要申请额外的权限去保存debug变体类型中的log文件,但是正式版请求这个不必要的权限可能会吓走潜在用户,我们应该添加额外的manifest文件到debug构建类型的资源集合中去申明额外权限
资源的优先级(从高到低)
Build type -》 Flavor -> Main ->Dependencies
如果一个resource被声明在flavor和一个main source set中,falvor中的将有更高的优先级,所以flavor source set将被打包,main中的该资源就不会被打包,声明在库项目(library project)中的总是最低优先级
3.4 创建构建变体(creating build variants)
//这和前面内容感觉一样,难道这两种加一块叫做构建变体
//(build type 和 productFlavors)
android {
buildTypes {
debug {
buildConfigField "String", "API_URL",
"\"http://test.example.com/api\""
}
staging.initWith(android.buildTypes.debug)
staging {
buildConfigField "String", "API_URL",
"\"http://staging.example.com/api\""
applicationIdSuffix ".staging"
}
}
//现在要求必须有产品维度,示例少了产品维度
productFlavors {
red {
applicationId "com.gradleforandroid.red"
resValue "color", "flavor_color", "#ff0000"
}
blue {
applicationId "com.gradleforandroid.blue"
resValue "color", "flavor_color", "#0000ff"
}
}
}
3.5 变体过滤
如果用assemble命令执行会构建所有的变体,如果想要忽略某些变体,可以在app或库项目的(也就是module级别的)顶级build.gradle中配置
android.variantFilter { variant ->
if(variant.buildType.name.equals('release')) {
variant.getFlavors().each() {flavor ->
if (flavor.name.equals('blue')) {
variant.setIgnore(true);
}
}
}
}
3.6 签名配置(signing configurations)
发布应用的时候需要为不同的构建类型使用同的签名key,可以使用签名配置
android {
signingConfigs {
staging.initWith(signingConfigs.debug)
release {
storeFile file("release.keystore")
storePassword"secretpassword"
keyAlias "gradleforandroid"
keyPassword "secretpassword"
}
}
}
系统为debug类型自动创建了默认签名配置,我们不需要单独创建
当你定义了signing configurations,需要把他们应用到build types或flavors中,build types和flavors都有一个属性叫做signingConfig
android {
buildTypes {
release {
signingConfig signingConfigs.release
}
}
}
在flavor中,也是相同的
android {
productFlavors {
blue {
signingConfig signingConfigs.release
}
}
}
这种用法会导致错误,当你分配一个配置给一种风味,实际上是覆盖了build type的配置(这样这个风味下的debug类型的build type的签名也会被覆盖成release的签名),如果你想要每个风味的不同build type都有不同的KEY,可以如下配置,这样就不会影响debug或其他构建类型的签名
android {
buildTypes {
release {
productFlavors.red.signingConfig signingConfigs.red
productFlavors.blue.signingConfig signingConfigs.blue
//这样设置,就只会影响release
}
}
}
如果按照之前的配置,blue风味的debug和release都会使用signingConfig.release的配置,现在这样,就会设置开发版用release