使用场景:
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文件
<resources>
<string name="app_name">TypesAndFlavors</string>
<string name="hello_world">Hello world!</string>
</resources>
staging build type source set的 strings.xml文件
<resources>
<string name="app_name">TypesAndFlavors STAGING</string>
</resources>
merged strings.xml file
<resources>
<string name="app_name">TypesAndFlavors STAGING</string>
<string name="hello_world">Hello world!</string>
</resources>
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'
}
}
}