使用场景:
1.应用拥有付费版和免费版。2.应用需要为各个平台打包。3.其他需要产生不同版本的情况。
在AS中Gradle为我们默认创建了两个构建类型(build types),还有另外一个概念 product flavor,它能让我们更好的管理APP或library的各种版本。 Build types 和 product flavors 通常结合使用,他们统称build variant。
构建类型+定制产品=构建变种版本,BuildType + ProductFlavor 任何一种组合都会是一个版本。
章节主题:
- Build types
- Product flavors
- Build variants
- Signing configurations
一,Build types
在Gradle 的Android plugin中,一个build type用来定义APP或library如何构建。每个build type都能指定一些debug符号表,比如application ID,是否应该混淆,无用资源是否应该被删除等等。这些参数在可以在 buildTypes block中定义,在AS中一个标准的buildTypes block如下:
android {
buildTypes {
release {
minifyEnabled true
shrinkResources true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
buildTypes block默认为我们生成了一个release版,minifyEnabled为true代表开启混淆,shrinkResources为true代表删除无用资源,proguardFiles 代表混淆规则文件名称,第一个是Android自带通用混淆规则,第二个是项目自定义混淆规则。混淆规则编写可以参考郭神的Android安全攻防战,反编译与混淆技术完全解析(下)
1.创建build types
当默认的配置不能满足需求时,我们也能很简单的在buildTypes block里面配置相应参数。如下一个创建staging的build type:
android {
buildTypes {
staging {
applicationIdSuffix ".staging"
versionNameSuffix "-staging"
buildConfigField "String", "API_URL", "\"http://staging.example.com/api\""
}
}
}
staging为 application ID添加了后缀,使staging的application ID和 debug,release版本不同。比如:
Debug: com.package
Release: com.package
Staging: com.package.staging
这样可以使你能在同一个设备上安装Staging和release版,staging版本也有version名后缀。buildConfigField 在第二章介绍过。
在定义一个新的build type时,也不需要从头定义,可以摘抄一些其他build type的属性, initWith()方法摘抄了debug type的属性,当定义了相同属性会覆盖。
android {
buildTypes {
staging.initWith(buildTypes.debug)
staging {
applicationIdSuffix ".staging"
versionNameSuffix "-staging"
debuggable = false
}
}
}
2.Source sets
当创建一个新的 build type时,Gradle也会创建一个新的source set,默认source set和build type名称相同,但是这个目录不会默认创建,需要自己去为build type创建source set目录。你可以通过source set 为特定版本添加自定义代码。
Resources在source set处理上有些特别,相同名称的Drawables 和layout files将覆盖main source set,但是
values 文件不会,Gradle将合并不同的地方。
main source set的 strings.xml文件
TypesAndFlavors
Hello world!
staging build type source set的 strings.xml文件
TypesAndFlavors STAGING
merged strings.xml file
TypesAndFlavors STAGING
Hello world!
3.Dependencies
每个build type都可以有它们自己的dependencies.例如在debug包里添加logging
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile 'com.android.support:appcompat-v7:22.2.0'
debugCompile 'de.mindpipe.android:android-logging-log4j:1.0.3'
}
二,Product flavors
与build type相比,Product flavors适用于为同一APP创建不同版本,典型的就是付费和免费版。为不同平台生产不同版本。build type主要用于内部使用,如果是发布到平台上,而且想和已发布的版本区分开,就应该使用 product flavors 。
1.创建product flavors
方法和build types类似,productFlavor block。
android {
productFlavors {
red {
applicationId 'com.gradleforandroid.red'
versionCode 3
}
blue {
applicationId 'com.gradleforandroid.blue'
minSdkVersion 14
versionCode 4
}
}
}
Product flavors和 build types拥有不同属性,因为product flavors是ProductFlavor class 的对象。defaultConfig 对象在build scripts中,product flavors会共享 defaultConfig的属性,所以可以在defaultConfig里配置product flavors的共同属性。每个flavor也会覆盖相同属性。
2.多flavor variants
android {
flavorDimensions "color","price"
productFlavors{
red{
flavorDimension "color"
}
blue{
flavorDimension "color"
}
free{
flavorDimension "price"
}
paid{
flavorDimension "price"
}
}
}
例如上面,有付费版和免费版,颜色上面还有要求。要结合几种情况,首先指定flavorDimensions属性(在Android block中定义),然后分别在productFlavors block中指定版本,然后会产生以下几种版本(结合build types)。
- blueFreeDebug and blueFreeRelease
- bluePaidDebug and bluePaidRelease
- redFreeDebug and redFreeRelease
- redPaidDebug and redPaidRelease
每个flavor都必须指定一个flavorDimension属性, flavorDimensions 定义的属性必须使用,顺序也很重要,当两个类型结合时,相同属性会被前面的覆盖,例如color覆盖price的属性。产生版本个数为:
总数=color属性个数 * price熟悉个数 * build type个数(debug+release)
三,Build variants
Build variants是build types和product flavors结合的产物,在AS左侧有Build Variants窗口可以查看各个版本,单击即可构建该版本。如果没有指定 product flavors,Gradle的Android插件会默认生成debug和release build type。
1.Tasks
Android plugin for Gradle会为每个build variant创建task。例如assembleDebug会构建所有debug版本,assembleBlue会构建所有blue版本。
2.Source sets
和 build type一样,Build variants也拥有自己的source set,例如blue flavor 和free flavor的目录,src/blueFreeDebug/java/,也可以使用sourceSets block指定目录路径。
3.Resource and manifest合并
在打包前Gradle会合并 main source set 和 build type source sets资源,library的资源也会被合并。当在debug版本时想保存log文件,需要一些文件读写权限,但在正式版时不需要此权限,可以在debug 的source set里面申请额外的权限。
resources and manifests的优先级顺序:
在main source set和一个flavor中存在一个相同的resource时,打包flavor时会使用flavor resource,而不是main source set。library的resource优先级最低。
4.Creating build variants
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"
}
}
}
如上定义,会产生build variants: blueDebug, blueStaging, redDebug, 和redStaging
staging build type 的 source set的drawable目录下app icon和debug不同
5.Variant filters
有时需要过滤掉一些Variant 来加快assemble 命令。(assemble 构建所有Variant )
//过滤掉release下的blue版本,这个task也被取消了。看得懂也行,反正我也写不来(ง ˙o˙)ว
android.variantFilter { variant ->
if(variant.buildType.name.equals('release')) {
variant.getFlavors().each() { flavor ->
if (flavor.name.equals('blue')) {
variant.setIgnore(true);
}
}
}
}
四,Signing configurations
发布APK时需要签名
android {
signingConfigs {
release {
//签名文件路径
storeFile file("release.keystore")
//签名文件的密码
storePassword "secretpassword"
//指定签名文件的别名
keyAlias "gradleforandroid"
//指定签名文件的别名配对密码
keyPassword "secretpassword"
}
}
buildTypes {
release {
//指点签名配置
signingConfig signingConfigs.release
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}