Gradle for Android ( 构建变体 )
链接:
https://www.cnblogs.com/tangZH/p/10999060.html
有时候我们一个app需要有不同的版本,不同的版本又会使用不同的配置,我们可以使用gradle进行管理。
- Build types
- Product flavors
- Build variants
- Signing configurations
一、构建版本Build types:
常见的构建版本有debug与release。
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
自定义构建版本:
custom {
applicationIdSuffix ".custom"
versionNameSuffix ".custom"
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
signingConfig signingConfigs.readerDaquanConfig
}
除了debug构建版本不需要签名外,其它的都是需要配置签名的,不然无法运行在手机上,该版本定义了新的applicationId与版本号。不同构建版本的applicationId如下:
- Debug: com.package
- Release: com.package
- Staging: com.package.staging
也可以采用继承的方式:
custom.initWith(buildTypes.debug)
custom {
applicationIdSuffix ".custom"
versionNameSuffix ".custom"
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
signingConfig signingConfigs.readerDaquanConfig
}
custom继承debug构建版本的配置,custom中的配置会覆盖debug的配置。
在BuildConfig中添加变量
custom {
applicationIdSuffix ".custom"
versionNameSuffix ".custom"
buildConfigField("String", "name","\"custom app\"")
buildConfigField("int", "id", "0")
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
signingConfig signingConfigs.readerDaquanConfig
}
之后我们可以看到:

注意如果要添加的是String,那么双一号里面需要再一个双引号标识字符串"\"custom app\"",斜杆是对里面双引号进行转义。
Source sets
source set。默认的source set目录会放在相同的Build Type的目录下。当你创建一个新的build type时,该目录不会自动创建,你必须在你使用代码与资源前自己为每一个build type创建source set目录。app
└── src
├── debug
│ ├── java
│ │ └── com.package
│ ├── res
│ │ └── layout
│ │ └── activity_main.xml
│ └── AndroidManifest.xml
├── main
│ ├── java
│ │ └── com.package
│ ├── res
└── MainActivity.java
└── Constants.java
│ └── AndroidManifest.xml
├── custom
│ ├── java
│ │ └── com.package
├── drawable
└── layout
└── activity_main.xml
│ ├── res
│ │ └── layout
│ │ └── activity_main.xml
│ └── AndroidManifest.xml
└── release
├── java
│ └── com.package
│ └── Constants.java
└── AndroidManifest.xml
假如我们自己建立custom的source set

我们使用不同的构建版本便会使用不同的source set。当使用不同的source sets的时候,资源文件的处理需要特殊的方式。Drawables和layout文件将会复写在main中的重名文件,但是values文件下的资源不会。gradle将会把这些资源连同main里面的资源一起合并。(如果出现资源重复异常,请clean一下工程)
例如,在main中的string.xml为:
<resources>
<string name="app_name">BuildTypeProject</string>
<string name="hello_name">BuildTypeHello</string>
</resources>
在custom版本中为:
<resources>
<string name="app_name">BuildTypeCustomProject</string>
</resources>
当我们构建custom版本的时会合并为:
<resources>
<string name="app_name">BuildTypeCustomProject</string>
<string name="hello_name">BuildTypeHello</string>
</resources>
当你创建一个新的构建版本而不是custom,最终的strings.xml将会是main目录下的strings.xml。
manifest也和value文件下的文件一样。如果你为你的构建版本创建了一个manifest文件,那么你不必要去拷贝在main文件下的manifest文件,你需要做的是添加标签。Android插件将会为你合并它们。
但是需要注意,当我们添加.java文件到custom版本中,你可以添加相同的类到debug和release版本,但是不能添加到main版本。如果你添加了,会抛出异常。这时候我们如果构建custom版本,那么便会使用custom对应source set中的.java文件。
依赖包
每一个构建版本都有自己的依赖包,gradle自动为每一个构建的版本创建不同的依赖配置。如果你想为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
不同的生产版本。
product flavors极大简化了基于相同的代码构建不同版本的app。
创建product flavors
android {
productFlavors {
vivo {
applicationId "vivo"
versionCode 1
minSdkVersion 15
}
oppo {
applicationId "oppo"
versionCode 2
minSdkVersion 15
}
}
}
这时候AS 3.0以上会报错ERROR: All flavors must now belong to a named flavor dimension
没有给它们设置一个风味维度,我们可以加上
flavorDimensions "default"
flavorDimensions "default"
android {
productFlavors {
vivo {
applicationId "vivo"
versionCode 1
minSdkVersion 15
}
oppo {
applicationId "oppo"
versionCode 2
minSdkVersion 15
}
}
}
给这些产品版本默认一个风味维度,具体有何作用,等会会讲。
这时候我们会在左下角的窗口看到这么多个变体:

如果找不到该窗口,可以在这里打开:

由于我们之前在custom构建版本上设置了applicationIdSuffix ".custom",所以,当我们运行oppoCustom版本的时候,applicationId为oppo.custom
Source Set
product Flavors也有自己的代码文件夹。创建一个特殊的版本就像创建一个文件夹那么简单。如下图所示:

但是值得注意的是,我们无法再vivo文件夹里相同的包中添加构建版本已经有的.java文件,添加了会报异常。而对于资源文件,我们可以添加构建版本里面有的文件,但是这个产品版本所对应的目录的优先级低于Build type,也就是说,当Custom目录有一张图片,vivo目录也有一张图片,那么当我们运行打包vivoCustom版本的时候,使用的是custom里面的图片。除非我们建立的文件夹是vivoCustom,那么它的优先级便会是最高的。

Multiflavor variants
在某些情况下,你可能希望创建一些联合的Product Flavors,这个时候便要使用到我们刚刚所说的flavorDimensions 了。
设想一下,假如我们需要打包两个渠道的app:vivo和oppo,而这两个渠道的app各自有付费版与免费版,那么我们就需要用到多维度了。
首先定义两个维度:渠道channel,付费与免费:money
flavorDimensions "channel","money"
flavorDimensions "channel","money"
android {
productFlavors {
vivo {
dimension "channel"
applicationId "vivo"
versionCode 1
minSdkVersion 15
}
oppo {
dimension "channel"
applicationId "oppo"
versionCode 2
minSdkVersion 15
}
free {
dimension "money"
}
vip {
dimension "money"
}
}
}
当你添加了flavor dimensions,你就需要为每个flavor添加dimension,否则会提示错误。
之后我们可以看到这么多个变体:

而我们定义多个维度的顺序是很重要的,因为当你在各个维度各自定义了同一个常量的值,比如:buildConfigField("String", "name","\"custom app\""),总是以第一维度的为准。
Build variants
构建变体
构建变体是构建版本和生产版本的结合体。当你创建了一个构建版本或者生产版本,同样的,新的变体也会被创建。
像我们上图便有这么多的变体:

我们可以在这个窗口进行切换,然后运行不同的变体。
tasks
assembleDebug一个是assembleRelease来构建不同的APK。当添加一个新的Build Type的时候,一个新的Task也就会被创建,一旦你开始添加Flavors,一整套Tasks就会被创建,因为每一个BuildType的Tasks都会为每个Product Flavor联合。Source sets
构建变体也可以有自己的资源文件夹,举个例子,你可以有src/vivoVipCustom/java/。原理与上面的类似
Resource and mainfest merging
Android Plugin需要在打包前对Main的SourceSet以及BuildType的SourceSet进行一次Merge。而且Library工程也会提供额外的资源,它们也会被Merge,例如Manifest.xml等等。也会在其中声明一些权限等。
Resource和Manifest.xml的优先级顺序如下:

如果一个资源在main中和在flavor中定义了,那么那个在flavor中的资源有更高的优先级。这样那个在flavor文件夹中的资源将会被打包到apk。而在依赖项目申明的资源总是拥有最低优先级。
当然,如果你建立的目录是变体的目录入:vivoVipCustom,那么它的优先级自然是高于Build type
创建构建变体
关于如何构建变量,上面已经说了,不再重复。
flavorDimensions "channel","money"
android {
productFlavors {
vivo {
dimension "channel"
applicationId "vivo"
versionCode 1
minSdkVersion 15
}
oppo {
dimension "channel"
applicationId "oppo"
versionCode 2
minSdkVersion 15
}
free {
dimension "money"
resValue "color", "colorfree", "#ff8888"
}
vip {
dimension "money"
resValue "color", "colorfree", "#ff0000"
}
}
}
resValue "color", "colorfree", "#ff8888"表示添加颜色名为colorfree的颜色
变体过滤器
忽略某个变体也是可行的。这样你可以加速你的构建当使用assemble的时候,这样你列出的tasks将不会执行那么你不需要的变体。你可以使用过滤器,在build.gradle中添加代码如下所示:
android.variantFilter { variant ->
if(variant.buildType.name.equals('release')) {
variant.getFlavors().each() { flavor ->
if (flavor.name.equals('vivo')) { variant.setIgnore(true);
}
}
}
}
发现相关的变体不见了:

Signing Configurations
在你发布你的应用之前,你需要为你的app私钥签名。如果你有付费版和免费版,你需要有不同的key去签名不同的变体。这就是配置签名的好处。配置签名可以这样定义:
android {
signingConfigs {
custom.initWith(signingConfigs.debug)
release {
storeFile file("release.keystore")
storePassword"secretpassword"
keyAlias "gradleforandroid"
keyPassword "secretpassword"
}
}
}
在这个例子中,我们创建了2个不同的签名配置。debug配置是as默认的,其使用了公共的keystore和password,所以没有必要为debug版本创建签名配置了。custom配置使用了initWith()方法,其会复制其他的签名配置。这意味着custom和debug的key是一样的。
release配置使用了storeFile,定义了key alias和密码。当然这不是一个好的选择,你需要在 Gradle properties文件中配置。
当你定义了签名配置后,你需要应用它们。构建版本都有一个属性叫做signingConfig,你可以这么干:
android {
buildTypes {
release {
signingConfig signingConfigs.release
}
}
}
上例使用了buildTypes,但是你可能需要对每个版本生成不同的验证,你可以这么定义:
android {
productFlavors {
vivo{
signingConfig signingConfigs.release
}
}
}
当签名一个Flavor版本的时候,你需要重写BuildType中的签名配置。当需要使用相同的BuildType不同版本的Flavors的签名时,可以通过下述方式:
android {
buildTypes {
release {
productFlavors.vivo.signingConfig signingConfigs.vivo
productFlavors.oppo.signingConfig signingConfigs.oppo
}
}
}
上面这个例子展示了如何在vivo和oppo的Release版本使用不同的签名,但是却不影响Debug和Custom的BuildType。
Gradle for Android ( 构建变体 )的更多相关文章
- 【转载】Gradle for Android 第四篇( 构建变体 )
当你在开发一个app,通常你会有几个版本.大多数情况是你需要一个开发版本,用来测试app和弄清它的质量,然后还需要一个生产版本.这些版本通常有不同的设置,例如不同的URL地址.更可能的是你可能需要一个 ...
- Gradle for Android 第三篇( 依赖管理 )
依赖管理 这会是一个系列,所以如果你还没有看我之前的几篇文章,请先查看以下文章: Gradle for Android 第一篇( 从 Gradle 和 AS 开始 ) Gradle for Andro ...
- 【转载】Gradle for Android 第三篇( 依赖管理 )
依赖管理是Gradle最闪耀的地方,最好的情景是,你仅仅只需添加一行代码在你的build文件,Gradle会自动从远程仓库为你下载相关的jar包,并且保证你能够正确使用它们.Gradle甚至可以为你做 ...
- 【转载】Gradle for Android 第五篇( 多模块构建 )
Android studio不仅允许你为你的app和依赖库创建模块,同时也可为Android wear,Android TV,Google App Engine等创建模块,而这些单独的模块又可以在一个 ...
- 【Gradle】Android Gradle 多项目构建
Android Gradle 多项目构建 Android 项目区别 Android项目一般分为库项目,应用项目,测试项目,Android Gradle 根据这些项目分别对应3种插件:com.andro ...
- 为什么说 Gradle 是 Android 进阶绕不去的坎 —— Gradle 系列(1)
请点赞,你的点赞对我意义重大,满足下我的虚荣心. Hi,我是小彭.本文已收录到 GitHub · Android-NoteBook 中.这里有 Android 进阶成长知识体系,有志同道合的朋友,欢迎 ...
- Gradle 实现 Android 多渠道定制化打包
Gradle 实现 Android 多渠道定制化打包 版权声明:本文为博主原创文章,未经博主允许不得转载. 最近在项目中遇到需要实现 Apk 多渠道.定制化打包, Google .百度查找了一些资料, ...
- 深入理解gradle编译-Android基础篇
深入理解gradle编译-Android基础篇 导读 Gradle基于Groovy的特定领域语言(DSL)编写的一种自动化建构工具,Groovy作为一种高级语言由Java代码实现,本文将对Gradle ...
- 【转】gradle for android 第一篇
正如大家所见,这是本英文书,而由于国内的gradle翻译资料不全,所以特次开辟专栏,翻译gradle for android这本书,同时添加自己的心得体会以及在实际工作上的实战,希望大家能够喜欢. 如 ...
随机推荐
- Python的import机制
模块与包 在了解 import 之前,有两个概念必须提一下: 模块: 一个 .py 文件就是一个模块(module) 包: __init__.py 文件所在目录就是包(package) 当然,这只是极 ...
- vue 结合 Echarts 实现半开环形图
Echarts 实现半开环形图 1.先看看实现的图 2.HTML部分 创建id 是 chart 的div标签. <div class="content-item"> & ...
- docker配置mysql主从与django实现读写分离
一.搭建主从mysql环境 1 下载mysql镜像 docker pull mysql:5.7 2 运行刚下载的mysql镜像文件 # 运行该命令之前可以使用`docker images`是否下载成功 ...
- centos7忘记root密码的重置方法-超简单
忘记root密码,重置root密码8步. 1.在开机界面按e进入grub编辑模式 2.找到 ro修改为rw /sysroot/bin/sh 3.Ctrl + x 启动 4.chroot /sysroo ...
- python_tornado
1.创建Tornado服务器 1.创建Application对象 Application是Torando最核心的类 所有关于服务器的配置信息都写在Applicatio ...
- Python使用itchat获取微信好友信息~
最近发现了一个好玩的包itchat,通过调用微信网页版的接口实现收发消息,获取好友信息等一些功能,各位可以移步itchat项目介绍查看详细信息. 目标: 获取好友列表 统计性别及城市分布 根据好友签名 ...
- JQuery之选择器转移
JQuery之选择器转移方法如下图: 代码实现: <script src="JS/jquery-1.12.4.min.js"></script> <s ...
- 借 redis cluster 集群,聊一聊集群中数据分布算法
Redis Cluster 集群中涉及到了数据分布问题,因为 redis cluster 是多 master 的结构,每个 master 都是可以提供存储服务的,这就会涉及到数据分布的问题,在新的 r ...
- ios宏定义应该呆在恰当的地方
项目为了看起来整洁 并减少不必要的多次拼写 我们会把这样的方法 做成宏定义 那么问题来了 很多文件同时用到一个或多个宏定义 写完之后就会变成这个样子 看起来很乱 阅读性也不好 那么问题来了怎么解决嘞 ...
- jQuery中操作页面的文本和值
主要是区分俩种方法: 1.html():可以识别HTML文件,将里面内容全部打印(操作双标签) 2.text():只是将里面的内容打印出来,不能识别HTML格式(操作双标签) <!DOCTYPE ...